平移到谷歌地图的“可用部分”

时间:2014-04-25 19:25:31

标签: javascript google-maps-api-3

我使用Google Maps API在网页中嵌入地图。地图填满了整个屏幕,但屏幕左侧有大约400px的内容,主要覆盖地图。当我想要平移地图时,应该将左边的区域视为不可见。

我想出了以下代码来计算"可用部分"我希望从地图的边缘开始50px的地图,并且还应该避免地图左侧的400px区域:

panIfNotClose = function(latLngs){
    if(latLngs.length === 0)
        return;

    // Get some important values that may not be available yet
    // http://stackoverflow.com/a/2833015/802335
    var bounds = map.getBounds();
    if(!bounds)
        return setTimeout(panIfNotClose.bind(this, latLngs), 10);
    var overlay = new google.maps.OverlayView();
    overlay.draw = function(){};
    overlay.setMap(map);
    var proj = overlay.getProjection();
    if(!proj)
        return setTimeout(panIfNotClose.bind(this, latLngs), 10);

    // Calculate the "usable part" of the map
    var center = bounds.getCenter();
    var northEast = bounds.getNorthEast();
    var southWest = bounds.getSouthWest();
    var northEastPx = proj.fromLatLngToContainerPixel(northEast);
    var southWestPx = proj.fromLatLngToContainerPixel(southWest);
    var menuPadding = 400;
    var newNorthEastPx = new google.maps.Point(northEastPx.x + 50, northEastPx.y + 50);
    var newSouthWestPx = new google.maps.Point(southWestPx.x - (50 + menuPadding), southWestPx.y - 50);
    var newNorthEast = proj.fromContainerPixelToLatLng(newNorthEastPx);
    var newSouthWest = proj.fromContainerPixelToLatLng(newSouthWestPx);
    var centerBounds = new google.maps.LatLngBounds(newSouthWest, newSouthWest);

    // Decide if any of the new LatLngs are far enough away that the map should move 
    var shouldMove = false;
    var targetBounds = new google.maps.LatLngBounds();
    for(var i = 0; i < latLngs.length; i++){
        targetBounds.extend(latLngs[i]);
        if(!centerBounds.contains(latLngs[i]))
            shouldMove = true;
    }

    // If the LatLngs aren't all near the center of the map, pan to it
    if(latLngs.length === 1){
        if(shouldMove || map.getZoom() !== 18)
            map.panTo(latLngs[0]);
        map.setZoom(18);
    }else{
        var targetZoom = Math.min(getBoundsZoomLevel(targetBounds), 18);
        if(shouldMove || map.getZoom() !== targetZoom)
            map.panTo(targetBounds.getCenter());
        map.setZoom(targetZoom);
    }
}

此代码应测试&#34;有效&#34;区域以确保所有给定的LatLng适合内部,但它尚未对panTo进行任何更改以及#34;移动&#34;右边的中心200px占左边400px的内容。

代码并没有像我预期的那样工作,但我不确定原因。我怀疑从LatLng转换为Point或反之亦然时,我可能做错了。尽管我无法想出一种简化它的方法,但我也可能做了比必要更多的工作。

1 个答案:

答案 0 :(得分:0)

这是一个非常简单的错误。在var centerBounds = new google.maps.LatLngBounds(newSouthWest, newSouthWest);行中,我意外地使用了相同的LatLng两次,而不是东北角和西南角。在计算newNorthEastPxnewSouthWestPx时,我也遇到了一些简单的算术问题。使用google.maps.Rectangle绘制centerBounds有助于快速轻松地完成工作。对于任何感兴趣的人,最终结果如下:

function panIfNotClose(latLngs, zoomOnly){
    if(latLngs.length === 0)
        return;

    if(typeof latLngs !== "object")
        latLngs = [latLngs];

    // Calculate the "middle half" of the map
    var bounds = map.getBounds();
    if(!bounds) // http://stackoverflow.com/a/2833015/802335
        return setTimeout(panIfNotClose.bind(this, latLngs, zoomOnly), 10);
    var overlay = new google.maps.OverlayView();
    overlay.draw = function(){};
    overlay.setMap(map);
    var proj = overlay.getProjection();
    if(!proj)
        return setTimeout(panIfNotClose.bind(this, latLngs, zoomOnly), 10);

    var center = bounds.getCenter();
    var northEast = bounds.getNorthEast();
    var southWest = bounds.getSouthWest();
    var northEastPx = proj.fromLatLngToContainerPixel(northEast);
    var southWestPx = proj.fromLatLngToContainerPixel(southWest);
    var menuPadding = 0;
    if($navBar.css("display") !== "none")
        menuPadding = 400;
    var newNorthEastPx = new google.maps.Point(northEastPx.x - 100, northEastPx.y + 100);
    var newSouthWestPx = new google.maps.Point(southWestPx.x + (100 + menuPadding), southWestPx.y - 100);
    var newNorthEast = proj.fromContainerPixelToLatLng(newNorthEastPx);
    var newSouthWest = proj.fromContainerPixelToLatLng(newSouthWestPx);
    centerBounds = new google.maps.LatLngBounds(newSouthWest, newNorthEast);

    var shouldMove = false;
    var targetBounds = new google.maps.LatLngBounds();
    for(var i = 0; i < latLngs.length; i++){
        targetBounds.extend(latLngs[i]);
        if(!centerBounds.contains(latLngs[i]))
            shouldMove = true;
    }

    // If the marker isn't near the center of the map, pan to it
    if(latLngs.length === 1){
        if(!zoomOnly && (shouldMove || map.getZoom() !== 18))
            map.panTo(correctCenter(latLngs[0], proj));
        map.setZoom(18);
    }else{
        var targetZoom = Math.min(getBoundsZoomLevel(targetBounds), 18);
        if(!zoomOnly && (shouldMove || map.getZoom() !== targetZoom))
            map.panTo(correctCenter(targetBounds.getCenter(), proj));
        map.setZoom(targetZoom);
    }
}

function correctCenter(latLng, proj){
    // $navBar references a jQuery pointer to a DOM element
    if($navBar.css("display") === "none")
        return latLng;
    var latLngPx = proj.fromLatLngToContainerPixel(latLng);
    var newLatLngPx = new google.maps.Point(latLngPx.x - 200, latLngPx.y)
    return proj.fromContainerPixelToLatLng(newLatLngPx);
}

// Adapted from http://stackoverflow.com/a/13274361/802335
function getBoundsZoomLevel(bounds){
    // $mapCanvas is a jQuery reference to the div containing the Google Map
    var mapDim = {
        width: $mapCanvas.width() * .6,
        height: $mapCanvas.height() * .6
    };
    var ZOOM_MAX = 18;

    function latRad(lat){
        var sin = Math.sin(lat * Math.PI / 180);
        var radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
        return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
    }

    function zoom(mapPx, fraction){
        return Math.floor(Math.log(mapPx / 256 / fraction) / Math.LN2);
    }

    var ne = bounds.getNorthEast();
    var sw = bounds.getSouthWest();

    var latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI;

    var lngDiff = ne.lng() - sw.lng();
    var lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;

    var latZoom = zoom(mapDim.height, latFraction);
    var lngZoom = zoom(mapDim.width, lngFraction);

    return Math.min(latZoom, lngZoom, ZOOM_MAX);
}