我们开发了一个解决方法来平滑地设置动画
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)
}
}