2011-01-20 70 views
27

Me gustaría poder hacer zoom suavemente en un marcador en Google Maps. Si uno simplemente establece el zoom con doble clic, el mapa se encuentra repentinamente en ese nivel de zoom, sin ninguna transición suave.¿Cómo hacer zoom suavemente en un marcador en Google Maps?

Al hacer zoom en un solo nivel más allá del nivel actual, Google Maps muestra una transición suave y agradable. Por lo tanto, debe ser posible acercarse sin problemas por más de un nivel, pero ¿cómo?

Respuesta

46

Como la suerte lo tendría, Quería lograr el mismo efecto recientemente, y encontré una solución, sobre la que hice a post. Básicamente, solo establecer un tiempo de espera para cada transición no es suficiente, ya que podría resultar fácilmente en un tipo de "inicio-parada" si el efecto de zoom de Google aún no ha finalizado o ha terminado hace mucho tiempo.

Como mencionó Martin, hay algunas desventajas en esto, que no voy a reiterar. Si lo utiliza al final es su elección, y depende en gran medida de la potencia de la CPU y/o el navegador de sus usuarios. Sin embargo, es un efecto agradable, y seguro que impresionará a algunos, cuando se usa con prudencia.

Mi solución fue la siguiente:

// example marker: 
var marker = new google.maps.Marker({ 
    map: map, 
    position: new google.maps.LatLng(-20.3,30.3) 
}); 


// add the double-click event listener 
google.maps.event.addListener(marker, 'dblclick', function(event){ 
    map = marker.getMap();  
    map.setCenter(overlay.getPosition()); // set map center to marker position 
    smoothZoom(map, 12, map.getZoom()); // call smoothZoom, parameters map, final zoomLevel, and starting zoom level 
}); 


// the smooth zoom function 
function smoothZoom (map, max, cnt) { 
    if (cnt >= max) { 
     return; 
    } 
    else { 
     z = google.maps.event.addListener(map, 'zoom_changed', function(event){ 
      google.maps.event.removeListener(z); 
      smoothZoom(map, max, cnt + 1); 
     }); 
     setTimeout(function(){map.setZoom(cnt)}, 80); // 80ms is what I found to work well on my system -- it might not work well on all systems 
    } 
} 

Básicamente lo que se pretende es ajustar el nivel de zoom a uno, que detecta el evento zoom_changed, a la espera de 80 ms antes de ajustar el nivel de zoom por uno nuevo, etc. Lo que es bueno de esto es que el evento zoom_changed parece ser llamado después de la transición suave proporcionada por Google Maps, pero antes de las imágenes reales se cargan, por lo que no desperdicia ancho de banda demasiado.

Los 80ms en el tiempo de espera también son un número mágico que se me ocurrió - sería aconsejable hacer una prueba más exhaustiva y ver qué funciona en diferentes sistemas y navegadores, y quizás cambiar el algoritmo ligeramente en función de su hallazgos o para diferentes sistemas.

Probablemente tampoco sea necesario agregar y eliminar el oyente cada vez, pero puede realizar esa pequeña mejora si lo desea.

+0

Gracias, voy a echar un vistazo! – PeanutButterJelly

+4

¡Funciona como un encanto! En lugar de setCenter, si usa panTo se ve mejor ...;) –

+0

Sería inteligente eliminar ese '' self' para evitar confusiones –

2

Puede intentar utilizar un setInterval para ampliar un nivel a la vez, y borrarlo cuando alcance el nivel deseado.

El problema es que el intervalo que lo hará funcionar depende completamente de la CPU y el ancho de banda de la máquina del usuario (qué tan rápido puede cargar y representar el nuevo conjunto de mosaicos de imágenes).

Tbh, no estoy seguro de que se pueda hacer para que funcione bien en cada situación, pero un pequeño intervalo entre los niveles de zoom podría ayudar un poco.

Un par de cosas a tener en cuenta Tho:

  1. esto va a poner mucho más énfasis en el usuario de la CPU y ancho de banda que va directamente a la zoomLevel elegido
  2. el usuario tendrá que esperar hasta este se hace para comenzar a interactuar con el mapa, lo que podría convertirse fácilmente en una experiencia de usuario muy mala.

Esos dos y probablemente otras razones explican por qué Google no construyó el tipo de zoom que desee en mapas en el primer lugar - porque es una mala idea ...

+0

Sí, entiendo su punto: lo tendré en cuenta. Sin embargo, es para uso en un entorno interno, por lo que la CPU y el ancho de banda son variables conocidas, y no deberían ser un problema. En cuanto al tiempo que toma la transición, siempre que el usuario no lo necesite con demasiada frecuencia, debería estar bien. De hecho, sería bueno no estar completamente desorientado después de hacer doble clic en un marcador. – PeanutButterJelly

1

@Herman Schaaf Su solución es grande, pero cuando se hace doble clic en él se salta unos zooms : D Así que han hecho una solución + smoothZoom cabo no puedo tomar todo el crédito He editado el código de JesseDobbelaere de jsfiddle.net Es una mezcla de los tuyos y el código de Jesse.

function smoothZoom(map, level, cnt, mode) 
{ 
    if(mode == true) 
    { 
     if (cnt >= level) { 
      return; 
     } 
     else 
     { 
      if((maxZoomOut + 2) <= cnt) 
      { 
       var z = google.maps.event.addListener(map, 'zoom_changed', function(event) 
       { 
        google.maps.event.removeListener(z); 
        map.setCenter(marker.getPosition()); 
        smoothZoom(map, level, cnt + 1, true); 
       }); 
       setTimeout(function(){map.setZoom(cnt);}, timeOut); 
      } 
      else 
      { 
       map.setZoom(cnt); 
       smoothZoom(map, level, cnt + 1, true); 
      } 
     } 
    } 
    else 
    { 
     if (cnt < level) { 
      return; 
     } 
     else 
     { 
      var z = google.maps.event.addListener(map, 'zoom_changed', function(event) 
      { 
       google.maps.event.removeListener(z); 
       map.setCenter(marker.getPosition()); 
       smoothZoom(map, level, cnt - 1, false); 
      }); 
      if(maxZoomIn - 2 <= cnt) 
      { 
       map.setZoom(cnt); 
      } 
      else 
      { 
       setTimeout(function(){map.setZoom(cnt);}, timeOut); 
      } 
     } 
    } 
}  

he hecho pocas más variables como el tiempo de espera y maxZoomIn hacia fuera ... se puede encontrar el código completo en jsFiddle http://jsfiddle.net/dexy86/9afy9/

-2

Esto lo acercará sin problemas en la ubicación deseada. Trate de añadir estas líneas:

LatLng latLng = new LatLng(lat,lng); 
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, ZOOM_FACTOR)); 
+0

¿Puede elaborarlo? –

+4

Por lo que sé, esto solo está disponible cuando se usan los SDK de Android o iOS, no para JS. –

+0

esta respuesta es irrelevante, ya que está en Java, pero la pregunta es si en Javascript. – BlueBird

8

Ésta me funcionó muy bien:

function animateMapZoomTo(map, targetZoom) { 
    var currentZoom = arguments[2] || map.getZoom(); 
    if (currentZoom != targetZoom) { 
     google.maps.event.addListenerOnce(map, 'zoom_changed', function (event) { 
      animateMapZoomTo(map, targetZoom, currentZoom + (targetZoom > currentZoom ? 1 : -1)); 
     }); 
     setTimeout(function(){ map.setZoom(currentZoom) }, 80); 
    } 
} 
0

que he probado las alternativas proporcionadas anteriormente, sin embargo, cada vez que veo la transición en un navegador de escritorio o una aplicación móvil, todo ocurre instantáneamente, o al menos, dentro de un período de tiempo que es imperceptible para la vista debido al tiempo entre cada iteración de bucle, al menos en el hardware que he probado.

Utilicé el mismo lazo que los otros métodos, pero alteré el tiempo de espera para que el zoom ocurriera más rápidamente cuando el nivel de zoom era más alto y más lento cuando era más bajo para que los resultados fueran más visibles.

En lugar de utilizar un periodo de tiempo de espera fijo, fijo el primer tiempo de espera a 0, y entonces los tiempos de espera subsiguientes con la siguiente ecuación rápida y sucia

((1+ currentZoom)/maxZoom) * 500; 

En código asumí el zoom max como 18, pero puede usar maxZoom para averiguar cuál es el nivel de zoom para una latitud/longitud determinada. Mi código es:

timeout = (1+map.getZoom()/18) * 500; 
Cuestiones relacionadas