代码之家  ›  专栏  ›  技术社区  ›  Kai Qing

谷歌地图v3-我可以确保平滑平移每次?

  •  18
  • Kai Qing  · 技术社区  · 14 年前

    我的地图在一个城市里有几百个标记。通常半径不超过20英里。 我已经阅读了文档,还没有找到一种方法来设置init在每个标记之间自动平移,不管距离有多远。 默认的行为是,如果接近,则平移,如果远,则跳转。 我理解他们为什么要这样做,因为地图没有在选定的缩放级别加载整个世界,如果距离太远,可能会搞砸。不过,我认为它可以处理20英里半径最小的投诉。

    6 回复  |  直到 14 年前
        1
  •  21
  •   Community iksemyonov    4 年前

    平滑平移的阈值不依赖于当前中心和新目标之间的距离。这取决于更改是否需要整页滚动(水平和垂直):

    引用 API Reference

    潘托(车床:车床)

    将地图的中心更改为给定的纬度。如果更改小于贴图的宽度和高度,则过渡将平滑设置动画。

        2
  •  14
  •   Darren Hicks    9 年前

    这是一个平滑平移的解决方案,还允许在上一个平移已在进行时将其他单击请求排队:

    var panPath = [];   // An array of points the current panning action will use
    var panQueue = [];  // An array of subsequent panTo actions to take
    var STEPS = 50;     // The number of steps that each panTo action will undergo
    
    function panTo(newLat, newLng) {
      if (panPath.length > 0) {
        // We are already panning...queue this up for next move
        panQueue.push([newLat, newLng]);
      } else {
        // Lets compute the points we'll use
        panPath.push("LAZY SYNCRONIZED LOCK");  // make length non-zero - 'release' this before calling setTimeout
        var curLat = map.getCenter().lat();
        var curLng = map.getCenter().lng();
        var dLat = (newLat - curLat)/STEPS;
        var dLng = (newLng - curLng)/STEPS;
    
        for (var i=0; i < STEPS; i++) {
          panPath.push([curLat + dLat * i, curLng + dLng * i]);
        }
        panPath.push([newLat, newLng]);
        panPath.shift();      // LAZY SYNCRONIZED LOCK
        setTimeout(doPan, 20);
      }
    }
    
    function doPan() {
      var next = panPath.shift();
      if (next != null) {
        // Continue our current pan action
        map.panTo( new google.maps.LatLng(next[0], next[1]));
        setTimeout(doPan, 20 );
      } else {
        // We are finished with this pan - check if there are any queue'd up locations to pan to 
        var queued = panQueue.shift();
        if (queued != null) {
          panTo(queued[0], queued[1]);
        }
      }
    }
    
        3
  •  9
  •   tato.rodrigo    5 年前

    我们开发了一个解决方法来平滑地设置动画 panTo

    潘托 zoom out , zoom in 到达目的地。

    要使用下面的代码,请致电 smoothlyAnimatePanTo map 实例作为第一个参数和目标 latLng 作为第二个参数。

    有一个jsfiddle来演示这个解决方案 here . 只需编辑 script

    欢迎发表任何评论和意见。

    /**
     * Handy functions to project lat/lng to pixel
     * Extracted from: https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
     **/
    function project(latLng) {
        var TILE_SIZE = 256
    
        var siny = Math.sin(latLng.lat() * Math.PI / 180)
    
        // Truncating to 0.9999 effectively limits latitude to 89.189. This is
        // about a third of a tile past the edge of the world tile.
        siny = Math.min(Math.max(siny, -0.9999), 0.9999)
    
        return new google.maps.Point(
            TILE_SIZE * (0.5 + latLng.lng() / 360),
            TILE_SIZE * (0.5 - Math.log((1 + siny) / (1 - siny)) / (4 * Math.PI)))
    }
    
    /**
     * Handy functions to project lat/lng to pixel
     * Extracted from: https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
     **/
    function getPixel(latLng, zoom) {
        var scale = 1 << zoom
        var worldCoordinate = project(latLng)
        return new google.maps.Point(
                Math.floor(worldCoordinate.x * scale),
                Math.floor(worldCoordinate.y * scale))
    }
    
    /**
     * Given a map, return the map dimension (width and height)
     * in pixels.
     **/
    function getMapDimenInPixels(map) {
        var zoom = map.getZoom()
        var bounds = map.getBounds()
        var southWestPixel = getPixel(bounds.getSouthWest(), zoom)
        var northEastPixel = getPixel(bounds.getNorthEast(), zoom)
        return {
            width: Math.abs(southWestPixel.x - northEastPixel.x),
            height: Math.abs(southWestPixel.y - northEastPixel.y)
        }
    }
    
    /**
     * Given a map and a destLatLng returns true if calling
     * map.panTo(destLatLng) will be smoothly animated or false
     * otherwise.
     *
     * optionalZoomLevel can be optionally be provided and if so
     * returns true if map.panTo(destLatLng) would be smoothly animated
     * at optionalZoomLevel.
     **/
    function willAnimatePanTo(map, destLatLng, optionalZoomLevel) {
        var dimen = getMapDimenInPixels(map)
    
        var mapCenter = map.getCenter()
        optionalZoomLevel = !!optionalZoomLevel ? optionalZoomLevel : map.getZoom()
    
        var destPixel = getPixel(destLatLng, optionalZoomLevel)
        var mapPixel = getPixel(mapCenter, optionalZoomLevel)
        var diffX = Math.abs(destPixel.x - mapPixel.x)
        var diffY = Math.abs(destPixel.y - mapPixel.y)
    
        return diffX < dimen.width && diffY < dimen.height
    }
    
    /**
     * Returns the optimal zoom value when animating 
     * the zoom out.
     *
     * The maximum change will be currentZoom - 3.
     * Changing the zoom with a difference greater than 
     * 3 levels will cause the map to "jump" and not
     * smoothly animate.
     *
     * Unfortunately the magical number "3" was empirically
     * determined as we could not find any official docs
     * about it.
     **/
    function getOptimalZoomOut(map, latLng, currentZoom) {
        if(willAnimatePanTo(map, latLng, currentZoom - 1)) {
            return currentZoom - 1
        } else if(willAnimatePanTo(map, latLng, currentZoom - 2)) {
            return currentZoom - 2
        } else {
            return currentZoom - 3
        }
    }
    
    /**
     * Given a map and a destLatLng, smoothly animates the map center to
     * destLatLng by zooming out until distance (in pixels) between map center
     * and destLatLng are less than map width and height, then panTo to destLatLng
     * and finally animate to restore the initial zoom.
     *
     * optionalAnimationEndCallback can be optionally be provided and if so
     * it will be called when the animation ends
     **/
    function smoothlyAnimatePanToWorkarround(map, destLatLng, optionalAnimationEndCallback) {
        var initialZoom = map.getZoom(), listener
    
        function zoomIn() {
            if(map.getZoom() < initialZoom) {
                map.setZoom(Math.min(map.getZoom() + 3, initialZoom))
            } else {
                google.maps.event.removeListener(listener)
    
                //here you should (re?)enable only the ui controls that make sense to your app 
                map.setOptions({draggable: true, zoomControl: true, scrollwheel: true, disableDoubleClickZoom: false})
    
                if(!!optionalAnimationEndCallback) {
                    optionalAnimationEndCallback()
                }
            }
        }
    
        function zoomOut() {
            if(willAnimatePanTo(map, destLatLng)) {
                google.maps.event.removeListener(listener)
                listener = google.maps.event.addListener(map, 'idle', zoomIn)
                map.panTo(destLatLng)
            } else {
                map.setZoom(getOptimalZoomOut(map, destLatLng, map.getZoom()))
            }
        }
    
        //here you should disable all the ui controls that your app uses
        map.setOptions({draggable: false, zoomControl: false, scrollwheel: false, disableDoubleClickZoom: true})
        map.setZoom(getOptimalZoomOut(map, destLatLng, initialZoom))
        listener = google.maps.event.addListener(map, 'idle', zoomOut)
    }
    
    function smoothlyAnimatePanTo(map, destLatLng) {
        if(willAnimatePanTo(map, destLatLng)) {
            map.panTo(destLatLng)
        } else {
            smoothlyAnimatePanToWorkarround(map, destLatLng)
        }
    }
    
        4
  •  4
  •   Community iksemyonov    7 年前

    看到这个关于使用javascript的答案了吗 setInterval panBy 在地图上: Can Google Maps be set to a slow constant pan? Like a globe revolution?

    这可以用来在每次调用panBy时将地图平移x个像素,这样可以降低平移速率(因为你只是告诉gmaps在短距离内平移)。

        5
  •  1
  •   levik    14 年前

        6
  •  0
  •   JohnDoeTheFifth    6 年前

    @塔托罗德里戈

    我没有足够的声誉张贴作为一个答案,所以我张贴作为回复塔托在这里,因为他的插件工作得很好,正是我需要的,但有一个错误(我用它作为一个依赖,所以 map 变量通过函数传递)

    你需要通过 地图 function getOptimalZoomOut(latLng, currentZoom) {}

    当你使用

    这样地: function getOptimalZoomOut(latLng, currentZoom, map) {}

    后来: map.setZoom(getOptimalZoomOut(destLatLng, initialZoom)); 传过来: map.setZoom(getOptimalZoomOut(destLatLng, initialZoom, map));