Creación de prototipos de un mapa más suave

Un vistazo a cómo funciona Google Maps

Cuando trabajé en Google Maps como ingeniero de UX, una de las cosas que realmente quería hacer era crear prototipos que pudieran sincronizar animaciones con zoom. Sin embargo, la API de JavaScript Maps tiene un control limitado del zoom, por lo que para tener más control, experimenté con el uso del lienzo HTML5 para componer los mosaicos en una implementación totalmente personalizada.

Para comprender lo que hace que el zoom suave sea un desafío para las aplicaciones de mapas modernas, es útil comprender primero cómo se hace el mapa y cómo funcionan los clientes de mapas de Google Maps (y la mayoría de los demás): puede buscar los títulos en negrita para ir directamente allí.

  1. Hacer la Tierra plana: el proceso mediante el cual un globo 3D se convierte en un mapa 2D.
  2. Google Maps: cómo Google cambió el mundo de la cartografía en 2005 y cómo rinde el cliente.
  3. Animación del mapa rasterizado: el enfoque personalizado que utilicé para habilitar la animación fluida.

1. Hacer la tierra plana

Espero que no sea una sorpresa para nadie, pero el mundo es redondo, aunque curiosamente, en realidad no es una esfera, sino un poco aplastado y más ancho en el medio.

El proceso de tomar este objeto mayormente esférico y representarlo en 2D es algo con lo que los cartógrafos han estado luchando y discutiendo durante milenios. En realidad, no hay una "mejor" forma de hacerlo, cada uno viene con compensaciones.

Latitud y longitud

Si imagina el mundo como una esfera que gira alrededor de su eje, el polo norte está en la parte superior, el polo sur está en la parte inferior y el ecuador es la línea imaginaria que corre alrededor del centro.

Retícula

Si piensa en el ecuador como un círculo que se asienta horizontalmente (como un cinturón), entonces podría imaginar círculos horizontales adicionales arriba y abajo, cada uno de estos paralelos al ecuador. Siguiendo cualquier círculo a la derecha, se mueve hacia el este, siguiendo cualquier círculo a la izquierda hacia el oeste. Estas líneas imaginarias se llaman círculos de latitud. Las latitudes son siempre la misma distancia entre sí, sin importar qué tan lejos viaje al este o al oeste.

Debido a que la tierra está inclinada sobre su eje, el sol no siempre se sienta directamente sobre el ecuador, sino que parece vagar ligeramente hacia el norte y el sur durante nuestra órbita. El Trópico de Cáncer es el círculo de latitud más al norte en el que el sol puede aparecer directamente sobre la cabeza (en el solsticio de junio), y el Trópico de Capricornio es el equivalente en el hemisferio sur (y el solsticio de diciembre). En realidad, eso no es importante para Google Maps, pero es una trivia divertida.

Latitud denota cuán lejos está el norte o el sur (porque no importa qué tan lejos vaya al este o al oeste, no se ha movido del norte al sur).

Corriendo en la otra dirección, perpendicular al ecuador, están los meridianos, o líneas de longitud, cada uno conecta el polo norte con el sur en línea recta. Siguiendo cualquier línea te mueves hacia el norte, siguiendo hacia el sur.

La longitud indica qué tan lejos está este u oeste (porque no importa qué tan lejos vaya al norte o al sur, no se ha movido en absoluto al este o al oeste).

La diferencia crucial entre la latitud y la longitud es que, si bien la latitud está siempre a la misma distancia en una esfera, las líneas de longitud están más alejadas en el medio (el ecuador) y se acercan más cerca de los polos (donde se tocan).

Medición de latitud y longitud

Tanto la latitud como la longitud se miden en grados. Comenzando desde el centro de la esfera, solo mide el ángulo en cada círculo (los círculos paralelos de latitud y los círculos perpendiculares de longitud).

La latitud es el ángulo formado a partir del ecuador, por lo que es 0º en el ecuador y hasta 90º norte o sur (en los polos). A mitad de camino hacia el Polo Norte estaría a 45º N.

La longitud es el ángulo medido desde el primer meridiano (una línea arbitraria que atraviesa Greenwich, Inglaterra). Es 0º en Greenwich y hasta 180º Este u Oeste (el lado opuesto del mundo).

Posicionamiento global

Un último dato curioso, que realmente no le importa a Google Maps (pero de todos modos me parece interesante), es cómo se ubicaron las personas antes del GPS.

La latitud es relativamente simple, solo necesita medir el ángulo entre el horizonte y una estrella conocida (o nuestro sol) y luego hacer un poco de matemática. Las personas han estado navegando en base a las estrellas durante miles de años, Polaris (la Estrella del Norte) es especialmente popular: en el Polo Norte, Polaris está directamente arriba (a 90º del horizonte). En el ecuador, Polaris parece sentarse en el horizonte (a 0º). Entre estos dos extremos, el ángulo hacia Polaris es el ángulo de latitud Norte. También puedes usar otras estrellas, solo requieren más matemáticas.

La longitud es mucho, mucho más difícil, de hecho, es tan difícil que nadie podría hacerlo bien hasta finales de 1700 (ni fácilmente hasta mucho más tarde que eso). La solución implica tiempo: la tierra gira a la misma velocidad, 360º cada 24 horas (o 15º por hora), por lo que si conoce la hora en que comenzó y la hora en que se encuentra, puede calcular la distancia en función de la diferencia. Fácil de hacer hoy, con relojes precisos, pero muy difícil de hacer anteriormente.

Originalmente, utilizaron las posiciones predichas de los cuerpos celestes en tiempos conocidos para calcular la hora, y luego lo compararon con la hora local (usando el sol al mediodía para restablecer el "reloj local"). El conjunto de predicciones más utilizado fue el Almanaque Náutico publicado por el Observatorio Real en Greenwich, Inglaterra, que, si alguna vez se ha preguntado por qué se llamaba GMT (Greenwich Mean Time), o por qué el primer meridiano atraviesa Greenwich, es porque durante mucho tiempo todos estaban midiendo en relación con el observatorio en Greenwich.

El mayor avance en la medición de la longitud fueron los relojes más precisos para que pudieran dejar de mirar las estrellas y simplemente verificar GMT: la longitud fue la diferencia de horas multiplicada por 15º. De hecho, esto es más o menos como todos calcularon la longitud hasta la invención del Sistema de Posicionamiento Global (GPS), que es solo un conjunto de relojes atómicos súper precisos que se encuentran en el espacio (y algunas matemáticas impresionantes).

Si estás tan fascinado por esto como yo, realmente te recomiendo leer este gran libro al respecto.

Escogiendo una Proyección

El método de traducir los puntos en un globo terráqueo 3D a un plano 2D se llama proyección de mapa. Hay muchas proyecciones diferentes, cada una con sus propias fortalezas y limitaciones, y ninguna sin alguna forma de distorsión de la geometría real; aquí hay algunas:

Proyecciones en Wikipedia

La proyección que seleccionó Google Maps es una versión modificada de la proyección de Mercator, titulada creativamente Web Mercator [la principal diferencia es que supone que el mundo es una esfera, en lugar de un elipsoide aplanado].

Hay algunas razones para elegir Mercator, pero la mejor razón es que el norte y el sur son rectos hacia arriba y hacia abajo, y el este y el oeste son rectos hacia la izquierda y hacia la derecha; en algunas de las otras proyecciones, estas líneas se curvarían o desviarían a medida que avanza el mapa. Esto es muy similar a la razón por la que Mercator fue tan ampliamente adoptado para la navegación: las líneas de rumbo constante (es decir, si elige un rumbo de brújula y se queda con él) son completamente rectas. Un beneficio adicional es que, debido a que es una proyección cilíndrica, puede envolver horizontalmente y colocar el mapa en mosaico.

Algunas de las otras propiedades especiales de la proyección de Mercator son que la escala es la misma en todas las direcciones alrededor de cualquier punto localizado (es decir, si se acerca a una ciudad, las distancias norte y sur son las mismas que este y oeste) y todos los ángulos son representado con precisión (es decir, el este está a 90º del norte).

La mayor crítica de la proyección de Mercator es que distorsiona significativamente la escala de países a medida que se aleja del ecuador (por ejemplo, Groenlandia parece tan grande como África, a pesar de ser menos de una décima parte del tamaño).

Piensa en lo que sucede cuando pelas una naranja y luego imagina hacer lo mismo con la tierra. Si cortara a lo largo de la serie de líneas longitudinales, terminaría con una variedad de cortes en cuña: en el globo, cada línea vertical aparece recta, pero a medida que la desenvuelve en dos dimensiones se vuelve curva (recuerde cómo esas líneas de longitud se acercaron más en los polos?

Desenvolviendo el globo

Para que el mapa de Mercator se una nuevamente, necesitamos estirar esos segmentos horizontalmente. En el ecuador ya se están tocando, por lo que no necesitan estirarse en absoluto, pero en los polos hay una brecha realmente grande y necesitan estirarse mucho (técnicamente infinitamente). Para preservar las distancias y ángulos en ambas direcciones a medida que se estira horizontalmente, se estira en la misma cantidad verticalmente. Cuanto más se acerca a los polos, más necesita estirarse.

Esto es un poco más fácil de visualizar si intenta dibujar un círculo del mismo tamaño en varios puntos del mapa. Para la proyección de Mercator, puede ver que los círculos parecen mucho más grandes hacia los polos (aunque en realidad son exactamente del mismo tamaño). Esto se debe a que necesitábamos estirar más el mapa en los polos para que se conectara.

Deformación de escala

Esto realmente solo importa cuando se aleja mucho, porque la escala es la misma en cualquier región localizada, por lo que para una ciudad o país determinado todo sigue siendo proporcional. Y en realidad es solo un problema importante para los polacos, pero como los pingüinos y los osos polares no usan Google Maps, no ha habido muchas quejas.

Si pensamos en la esfera, donde las líneas de latitud eran paralelas entre sí, y siempre a la misma distancia, mientras las líneas de longitud se acercaban en los polos, con Mercator, la latitud permanece perfectamente paralela y la longitud se vuelve perfectamente perpendicular. Todo esta bien.

Este fantástico video de Grafonaut demuestra toda la transformación:

2. Google Maps

En 2005, Google Maps se lanzó utilizando una innovación que todavía sustenta todos los servicios de mapas: el mapa en mosaico. En 2013 hubo una actualización importante para usar WebGL y agregar renderizado del lado del cliente, pero el enfoque en mosaico permanece.

Debo señalar que Google Maps no inventó el concepto del mapa en mosaico, pero tal vez fue la primera aplicación principal en usarlo, y combinarlo con AJAX y la web ciertamente ayudó a popularizar el enfoque.

Mapas en mosaico

En lugar de intentar representar una sola imagen, Google divide el mapa en mosaicos más pequeños y luego los coloca uno al lado del otro para formar una imagen más grande, como un mosaico.

Mapa en mosaico

La razón principal de esto es el tamaño de la imagen. En el nivel de zoom más alto de Google Maps, la imagen tendría más de 500 millones de píxeles cuadrados (el doble que en las pantallas HDPI), que es más de 25,000 terabytes (¿creo?) Incluso con una compresión de imagen generosamente optimista. Suponiendo que su navegador pueda representar esa imagen, le tomaría más de 6 años descargar con Google Fiber.

La segunda razón es la carga del servidor. En lugar de usar mosaicos, el servidor podría generar un mapa de tamaño perfecto para cada usuario, en el nivel exacto de zoom, latitud y longitud, y el tamaño correcto para llenar su ventana. Pero eso probablemente significaría que cada usuario necesita un mapa completamente personalizado, y con más de mil millones de usuarios mensuales, ¡son muchos mapas personalizados! También significaría que cada vez que desplaza el mapa, incluso unos pocos píxeles, debe descargar un mapa completamente nuevo.

Lo bueno de los mosaicos es que todos pueden compartirlos, el servidor puede almacenarlos en caché (e incluso pregenerarlos), y el cliente puede moverlos fácilmente. Algunos usuarios pueden descargar algunos mosaicos adicionales si su ventana es más grande, pero los mosaicos solo necesitan renderizarse una vez.

Nota: para la implementación de WebGL basada en vectores de 2013, en lugar de enviar mosaicos de imágenes, el servidor envía la información del vector (cada ruta y polígono) y el cliente presenta las imágenes. Sin embargo, esta información vectorial todavía está agrupada en "mosaicos", exactamente por las mismas razones (permite el almacenamiento en caché del servidor y proporciona una forma limpia para que el cliente subdivida las solicitudes de datos). Mientras que las siguientes secciones discuten la implementación de ráster (que todavía es utilizada por la API de JavaScript de Maps), el enfoque general también se aplica a la versión de WebGL.

Niveles de zoom

Google Maps tiene un número variable de niveles de zoom en función de la ubicación, pero generalmente es de alrededor de 21. En la mayoría de los alejados (nivel 0), todo el mapa está representado por un único mosaico cuadrado de 256 por 256 píxeles. En cada nivel de zoom incremental, el mapa duplica su tamaño en cada dirección: cada mosaico se reemplaza por 4 más detallados (2x2) al hacer zoom. Cada mosaico todavía tiene solo 256 por 256 píxeles, y cuando los combina se obtiene el mismo mapa (solo que más detallado).

En el nivel de zoom 0, el mapa mundial es un mosaico único, en el zoom 1 el mapa tiene 2 mosaicos en cada dirección, en el zoom 2 tiene 4 mosaicos de ancho, en el zoom 3 tiene 8 mosaicos de ancho, y así sucesivamente (se duplica cada vez) . Entonces, si bien el ancho y la altura totales duplican cada nivel, el área aumenta más rápidamente (1 mosaico, 4 mosaicos, 16 mosaicos, 64 mosaicos, etc.). Cuando llega al nivel de zoom 21, el mapa tiene 2 millones de fichas de ancho y contiene más de 4 billones de fichas en total.

Mapa de mosaicos en cada nivel de zoom

Cada nivel de zoom obtiene sus propias reglas de estilo para decidir qué información se debe mostrar. Hay poco valor al agregar información de carreteras al mapa mundial, ni al crear información para el mapa del país, etc. Hay un equipo muy trabajador que constantemente equilibra las etiquetas y características que se presentan y diseñan en cada nivel.

Como regla general, los primeros niveles son prácticamente solo el mapa mundial. En el zoom 5, los continentes y las masas de tierra son las características principales. Para el nivel 10, emergen los detalles de la ciudad. En el nivel 15, las calles son claramente visibles. Y con el zoom 20, todos los edificios se representan.

Podemos estimar fácilmente la escala de píxeles para estos zooms, podríamos hacerlo precisamente con matemáticas más complejas, pero en el ecuador (donde la proyección de Mercator no estira el mapa) es un cálculo simple:

En el zoom 1, cada píxel representa 78 km (48 millas), el zoom 5 es 5 km (3 millas), el zoom 10 es 150 m (164 yardas), 15 es 5 m (5,5 yardas), y con el zoom 20 cada píxel equivale a 15 cm ( 6 pulgadas) - ¡eso es impresionantemente detallado!

Posicionamiento

Google Maps tiene tres conceptos de coordenadas además de latitud y longitud: coordenadas mundiales, coordenadas de píxeles y coordenadas de mosaico.

Las coordenadas mundiales son independientes del nivel de zoom y se utilizan para traducir entre latitudes y longitudes y la posición actual en el mapa (o viceversa). Se calculan en relación con un mosaico único en el nivel de zoom 0. La latitud y la longitud se asignan al píxel fraccionario x e y en ese mosaico único (un número entre 0 y 256, su ancho y alto).

La conversión es muy fácil, aunque no puedo decir que entienda las matemáticas. El mapeo de longitud es fácil de entender ya que se traduce directamente, pero la latitud es más complicada debido a la inclinación al acercarse a los polos.

Las coordenadas de píxel hacen referencia a la posición exacta de píxel de una latitud y longitud a un nivel de zoom especificado. Se pueden calcular tomando las coordenadas mundiales y multiplicándolas por la cantidad de escala total para el nivel de zoom, que es fácil de calcular porque la escala duplica cada zoom.

Las coordenadas de mosaico son cómo el cliente le pide al servidor imágenes.

Coordenadas de mosaico

Se colocan en filas y columnas, con la fila 0, la columna 0 en la parte superior izquierda, las filas que aumentan a la derecha y las columnas a medida que avanza. Al igual que las coordenadas de píxel, los mosaicos dependen del nivel de zoom, de hecho, es un mapeo simple de píxel a mosaico dividiendo las coordenadas de píxel por el tamaño del mosaico y tomando el número integral.

El cliente puede determinar fácilmente qué mosaicos necesita calculando las coordenadas de mosaico para cada esquina de la pantalla. Por lo general, agrega un poco de relleno, como un medio de precarga, en caso de que el usuario desplace el mapa unos pocos píxeles.

Los clientes pueden generar fácilmente URL de mosaico utilizando estas coordenadas; por ejemplo, el nivel de zoom 1, fila 0, columna 0, es este mosaico que contiene América del Norte. Es trivial construir en código, aunque la API de Maps lo maneja por usted (junto con el estilo y otros beneficios).

Paneo

Interactuar con el mapa es donde los mosaicos realmente demuestran su valía. Antes de Google Maps, las cosas funcionaban un poco más como un Atlas: si llegaba al borde del mapa, tenía que pasar la página para ver algo más. Lo mejor de los mosaicos es que permite a los usuarios explorar libremente el mapa sin interrupciones mientras se desplazan y se acercan.

Cada mosaico se coloca absolutamente dentro de un contenedor, y luego, cuando desplaza el mapa en lugar de mover cada mosaico, solo el contenedor necesita moverse (y los mosaicos cambian con él). Esto le permite al cliente minimizar la cantidad de cambios DOM.

El contenedor se mueve, no los azulejos.

Es fácil calcular la posición en la que debe estar cada mosaico simplemente multiplicando la coordenada del mosaico por el tamaño del mosaico.

El último truco de posicionamiento es minimizar el número total de mosaicos que el navegador tiene que representar.

Mantener un DOM de tamaño constante

A medida que el usuario desplaza el mapa, el cliente comprueba qué mosaicos deberían estar visibles y carga los nuevos o elimina los que ya no están visibles.

Esto se hace tan rápido que el usuario rara vez se da cuenta (y en lugar de recortar los límites estrictos de la pantalla, a menudo obtiene unos pocos mosaicos adicionales a cada lado como un búfer). [Este enfoque en realidad no es tan diferente de cómo funciona ahora Google Photos]

Zoom

La panorámica es perfecta, pero el zoom es una de las áreas de desafío con un mapa en mosaico.

En el aspecto técnico, el desafío es menos cómo colocar las fichas, sino más cómo hacer la transición entre niveles. Cada nivel de zoom se duplica en escala, y no hay mosaicos intermedios para ayudar.

Ajustar entre niveles

Originalmente, hacer zoom era muy simple, simplemente reemplazaba el mapa con el siguiente conjunto de mosaicos, pero eso era un poco discordante porque de repente se "rompería" entre niveles.

Una forma de compensar esto es que, en lugar de hacer zoom en el centro del mapa, mantenga la ubicación debajo del cursor estacionaria (fijada debajo del cursor). Esto permite a los usuarios literalmente "apuntar" a la función que les interesa y centrarse (controlan el punto de referencia).

Animación de escala rápida (Maps JavaScript API)

Una adaptación más reciente lo hizo sentir más receptivo. Al hacer zoom, mantiene temporalmente los dos niveles de zoom en mosaicos (el antiguo y el nuevo) y realiza una animación de escala muy rápida entre ellos: los nuevos mosaicos comienzan a reducirse a la mitad y los mosaicos antiguos se animan hasta el doble de tamaño.

Todavía "se ajusta" entre las capas cuando termina la animación, pero todo sucede tan rápido que el ojo imagina el estado intermedio.

Este enfoque de escala y ajuste es lo que todavía utilizan hoy la API JavaScript de Google Maps, Bing Maps, Here Maps, Yahoo Maps, MapQuest y OpenStreetMap (LeafletJS).

Transición de escala durante el zoom

Posiblemente, la mayor limitación con scale & snap es que el usuario no tiene control sobre la animación, una vez que activa el zoom se ejecutará hasta que se complete, no hay capacidad para controlar la velocidad o pausar en un estado intermedio.

Mapas vectoriales

En 2013, Google Maps lanzó una importante actualización de maps.google.com que dejó de usar mosaicos PNG para las imágenes y comenzó a descargar mosaicos vectoriales. Estos mosaicos vectoriales siguen siendo referenciados por sus coordenadas de mosaico, aún se comportan de manera muy similar a los mosaicos ráster, pero en lugar de ser una imagen, contienen todas las etiquetas, trazados y polígonos, y se dibujan en el cliente.

Hay una variedad de razones por las cuales esto es importante: los datos vectoriales se comprimen mejor que las imágenes (por lo que ahorra ancho de banda), posibilita actualizaciones y estilos dinámicos (por ejemplo, si un usuario hace clic en una ruta de tránsito) y permite un zoom mejorado sustancialmente .

Zoom suave

Con los PNG rasterizados, al escalar el mapa no se puede saber qué es una carretera (y debe permanecer dibujada con el mismo ancho) o qué es un parque (y se debe escalar más grande), lo que significa que todo se estira y se pixela. Con la información vectorial, el cliente puede mantener las etiquetas correctamente posicionadas, mantener el ancho de la carretera y escalar todos los polígonos; el resultado es una experiencia de zoom increíblemente suave. Aún mejor, es completamente sensible, por lo que el usuario puede controlar la velocidad e incluso detenerse en niveles de zoom fraccionales.

Sin embargo, si observa de cerca (o intenta hacerlo usted mismo) mientras escala los mosaicos sin problemas, no hay información nueva hasta que se detenga. Tan pronto como el usuario detiene el zoom, el mapa carga rápidamente los mosaicos vectoriales en el nuevo nivel de zoom y los intercambia. Es realmente suave y rápido.

MapBox es uno de los otros clientes que usa mosaicos vectoriales en la web, y también utiliza este enfoque suave y rápido, aunque cargan nuevos mosaicos de manera más agresiva durante las transiciones de zoom.

3. Animando el mapa rasterizado

Para poder animar suavemente el mapa, el elemento más crítico es la capacidad de establecer niveles de zoom fraccionales (por ejemplo, a medio camino entre dos de los niveles de zoom integral en los que se representan los mosaicos). Con los mosaicos vectoriales, esto se puede representar de forma personalizada en el cliente, pero con los mosaicos de trama, deberíamos ser más creativos.

Para admitirlo, escribí una versión totalmente personalizada de la API de JavaScript de Maps, que reutiliza los mosaicos de imágenes del servidor de mapas, pero luego los coloca y maneja la interacción por sí mismo. Esto permitió un control completo sobre la escala y el posicionamiento de cada mosaico, así como el control sobre el zoom y la animación. En total, fueron 4.442 líneas de código comentado: es notable la poca cantidad de código que necesita el cliente, pero si lo piensa, la mayor parte del trabajo realmente duro se está haciendo en el servidor (averiguar qué carreteras, lagos, edificios, etc.) son visibles en cada mosaico, deciden los estilos y colores y luego los representan como imágenes).

El resto de este artículo hace referencia a mi código prototipo y no a la versión normal de Google Maps.

Crear niveles de zoom fraccionales

Similar al enfoque en Google Photos para desvanecer la opacidad entre las imágenes de baja y alta resolución para mezclar los detalles al cargar, mi teoría era que podríamos mezclar los mosaicos de diferentes niveles de zoom para crear un estado intermedio.

Podríamos tomar niveles de zoom más bajos y escalarlos como cuando se acerca, o hacer lo contrario y reducir los niveles de zoom más altos al alejar. Al escalar y superponer mosaicos de múltiples niveles de zoom, podríamos hacer una transición suave entre los zooms integrales y hacerlo de una manera matemáticamente predecible (perfecto para sincronizar animaciones).

Esto es posible porque Google usa la proyección Mercator: la escala es uniforme para las regiones localizadas, por lo que escalar linealmente los mosaicos conserva las formas.

Calcular la opacidad para el fundido cruzado es simple y lineal. Al realizar la transición entre dos niveles de zoom, el siguiente mosaico debe ser completamente transparente (opacidad 0) en el primer paso de zoom y completamente opaco (opacidad 1) en el siguiente. Entonces, la opacidad es solo 1 menos la distancia que está el zoom del mosaico del zoom del mapa (aunque en la práctica se ajusta a valores entre 0 y 1).

La escala tampoco es tan complicada. Dado que la escala se duplica en cada nivel de zoom, es posible calcular la cantidad a escalar para un nivel intermedio usando potencias de 2.

Si mapZoom es un nivel completo más alto que el mosaico (mapZoom - tileZoom = 1), la matemática daría como resultado 2¹ o 2. Si mapZoom tiene el mismo nivel que el mosaico (mapZoom - tileZoom = 0), la matemática sería 2⁰ o 1. Lo mejor de calcular potencias es que funciona para fracciones y negativos. Si mapZoom está a un nivel más bajo que el mosaico (mapZoom - tileZoom = -1), obtienes 2⁻¹ o 0,5. A mitad de camino entre los niveles de zoom (mapZoom - tileZoom = 0.5) obtienes 2 ^ (0.5) o 1.414, y puedes hacer esto para escalar suavemente entre cada estado.

La siguiente ilustración muestra cómo se aplica esto al hacer zoom. El mosaico monocromo es el nivel de zoom inicial, y los mosaicos de colores son el siguiente nivel de zoom (dibujado en un tablero de ajedrez para que pueda observar la diferencia). Puede ver que cuanto más nos acercamos al siguiente nivel de zoom, más dominan los mosaicos de colores y los detalles (por ejemplo, las etiquetas) comienzan a desvanecerse.

Zoom en

Aquí está la dirección opuesta, alejándose. Monocromo son el nivel de zoom inicial nuevamente, y colorean el nivel de zoom anterior; en este caso, estamos perdiendo detalles a medida que alejamos.

Alejándose12 fps

Funciona muy bien, proporciona un zoom relativamente suave (mucho mejor que la escala y el ajuste) y, aunque no es tan suave como la representación vectorial (suavizado y ajuste), en realidad elimina el aspecto del ajuste por completo.

He dejado la superposición de depuración activada en el GIF para que pueda ver dónde se están cargando los nuevos mosaicos. En la práctica es más suave (60 fotogramas por segundo) pero limité el GIF a 12 fps. Aquí está el video. Alternativamente, aquí está sin líneas de depuración.

En cualquier extremo, el mapa es casi imperceptiblemente diferente del zoom integral, aunque en el medio puede entrar en un estado incómodo con etiquetas que compiten entre sí. Esto no sería un gran efecto si se mantiene en un nivel de zoom fraccional, pero no es un problema durante las transiciones, y para evitar los zooms fraccionales, es fácil para el cliente "establecerse" de nuevo en un zoom integral cuando el usuario termina de hacer zoom, esperando hasta que lo suelten para que puedan mantener el control total mientras tanto.

Zoom entre los niveles integrales 3 y 4

¿Llamaremos a este efecto escala y mezcla? No solo se amplía suavemente, sino que también responde a la entrada del usuario en todo momento.

Zoom animado a 24 fps

HTML5 Canvas

Para lograr el mejor rendimiento, abandoné el enfoque web normal de usar elementos HTML estándar. Como se describe en la sección anterior, la API de Maps utiliza una combinación de elementos DIV e IMG para representar el mapa. Cada imagen se coloca dentro de un contenedor principal y ese contenedor se mueve a medida que el mapa se desplaza. Para las aplicaciones web normales, permitir que el navegador administre las cosas tiene muchas ventajas, el navegador maneja todas las decisiones sobre cuándo volver a dibujar la pantalla, cómo diseñar y colocar elementos, así como simplificar la interacción (como desplazarse y hacer clic en eventos). Aprovechar el navegador para esto es casi siempre el mejor enfoque.

Sin embargo, a veces, especialmente para dibujos muy personalizados, es ventajoso hacerlo manualmente. Para respaldar esto, los navegadores crearon el elemento de lienzo. A diferencia del HTML normal donde crea elementos y los agrega a la página, con un lienzo ejecuta comandos de dibujo en él. Puede dibujar líneas, arcos, círculos, rectángulos e incluso curvas complejas. El lienzo no hará nada extra por ti y trata el resultado como una imagen. Si dibuja una imagen en el lienzo, debe decirle exactamente dónde y qué tamaño, y luego, si decide mover esa imagen unos pocos píxeles, debe borrar todo el lienzo y volver a pintar todo en él (incluidas las otras líneas y imágenes). Si se desplaza por un sitio web normal, el navegador vuelve a calcular las posiciones y vuelve a dibujar. Si desea permitir que los usuarios desplace un lienzo, debe volver a calcular manualmente cada posición y luego volver a dibujar cada pieza usted mismo.

Si parece mucho trabajo, realmente lo es, y esa es una de las muchas razones por las que el lienzo no se usa con más frecuencia; pero hay ciertas situaciones en las que un lienzo es la mejor manera de lograr algo, y un renderizador de mapas totalmente personalizado es una de ellas (ya que la escala y el posicionamiento de cada mosaico era personalizado de todos modos, el uso de un lienzo agregó algo de complejidad pero redujo la sobrecarga) .

Una forma de visualizar la diferencia en cómo se construye la página es mirando el HTML resultante. El enfoque normal crea docenas de elementos y los agrega a la página, pero para el enfoque del lienzo hay muy poco, todo era un comando de dibujo dentro del lienzo.

Diferencia de estructura de página entre el enfoque basado en elementos y el enfoque de lienzo

Azulejos de reserva

Un caso de borde para manejar al escalar y mezclar los mosaicos es lo que sucede si no hay mosaicos para mezclar. Si el zoom inferior aún no se ha cargado, entonces, en lugar de animar la opacidad en el siguiente nivel, es mejor comenzar completamente opaco; de lo contrario, habrá huecos irregulares en el mapa.

El cálculo de la cobertura de los mosaicos alternativos es un área en la que la composición del lienzo personalizado realmente brilla: cada operación de dibujo puede establecer una opacidad personalizada, y dado que el lienzo es realmente eficiente para operaciones de dibujo pequeñas (por ejemplo, tamaño de mosaico del mapa), podemos establecer eficientemente niveles de opacidad personalizados para Cada azulejo individual. Si confiamos en el navegador para hacer esto con elementos personalizados, todas las animaciones individuales podrían causar una desaceleración.

El cliente siempre dibuja mosaicos de respaldo (el subyacente) con una opacidad total, y solo cambia la opacidad de los mosaicos primarios (nivel de zoom objetivo) que superpone en la parte superior. Antes del ciclo de pintura, verifica si el mosaico primario tiene una cobertura de recuperación completa, es decir, si todo lo que está debajo de ese mosaico se ha dibujado.

Por ejemplo, si estuviéramos haciendo zoom aquí, de zoom 0 a 1, esas fichas de colores tienen una cobertura completa, y esa única ficha gris debajo de ellas se superpone por completo. Esto significa que pueden tener su opacidad animada de forma segura sin dejar huecos.

Sin embargo, lo contrario no es cierto. Si estuviéramos alejando, de 1 a 0 (por lo que los mosaicos de colores serían la capa subyacente) no podríamos animar la opacidad en el mosaico gris porque dejaría algunos huecos.

Una posible solución a esto sería pintar los mosaicos primarios sin cobertura una vez como una capa base completamente opaca, luego pintar los mosaicos de respaldo, luego cambiar de forma segura la opacidad del mosaico primario (en el peor de los casos, se mezclaría consigo mismo), pero eso aumentaría El número de operaciones de sorteo para una mejora notable.

Otra cosa que podemos hacer con la opacidad es animar rápidamente en mosaicos recién cargados, por lo que en lugar de encajar en su lugar, hay un desvanecimiento rápido.

Dirección de zoom y velocidad

El cliente también realiza un seguimiento de la dirección en la que los usuarios están haciendo zoom (dentro o fuera), así como la rapidez con la que están haciendo zoom, y usa esto para determinar si debe cargar nuevos mosaicos.

Por ejemplo, si se acerca de 14 a 15, el cliente no se molestará en cargar más mosaicos desde el nivel de zoom 14, sino que priorizará la búsqueda de los nuevos que necesita de 15. Si ocurriera lo contrario, alejar de 15 a 14, el cliente solo intentaría cargar los nuevos mosaicos desde 14.

Utiliza la velocidad del zoom para decidir si hay algún punto para cargar mosaicos, o si es probable que la capa se amplíe antes de que las imágenes tengan la oportunidad de cargarse. Por ejemplo, al hacer zoom rápidamente, el usuario puede correr desde el zoom 4 al 15 en solo un segundo, y tiene poco sentido cargar 5, 6, 7, 8 ... porque sería un desperdicio de fichas. Afortunadamente, para acercar podemos escalar solo unos pocos mosaicos (recuerde que con el zoom 0 el mosaico representa el mundo entero) para mantener los colores / formas vagamente representativos.

Evitar la reducción de escala

Dado que el mapa se vuelve cada vez más detallado a niveles de zoom más altos, ingenuamente asumí que sería preferible usar los niveles más altos y reducirlos al reducir.

Reducir demasiados mosaicos

Sin embargo, en la práctica esto no funcionó muy bien, mientras que la escala de todos los polígonos (por ejemplo, agua y parques) está bien conservada, todas las etiquetas e íconos también se escalan, haciendo un mapa que se ve realmente desordenado, especialmente en el medio. La actuación también tuvo un gran éxito, porque en lugar de dibujar algunas docenas de mosaicos, de repente había cientos disponibles para dibujar.

Para evitar esto, deshabilité los mosaicos de reducción de escala en más de 1 diferencia de zoom. Es decir, al hacer zoom en los niveles fraccionales de los 14s (por ejemplo, 14.2) puede usar fichas del zoom 15, pero nunca, nunca, fichas de 16 o más.

Animaciones

Mi intención declarada al comienzo del proyecto era poder sincronizar mediante programación las animaciones con el zoom, aunque también tiene el beneficio adicional de sentirse mejor: es más suave y responde mejor a la entrada del usuario. Cuando está en niveles de zoom integral, se comporta igual que la implementación normal. Sin embargo, creo que es bastante efectivo para animar, puedes juzgar por ti mismo.

Aquí hay un ejemplo que visualiza una posible ruta de vuelo desde San Francisco a Australia. [alternativamente el video completo, o uno con la superposición de depuración]

Volar (y animar sin problemas) de San Francisco a Australia

Por supuesto, no hay razón para limitarlo a las animaciones de zoom. Un beneficio adicional de pintar todo en un lienzo es que nos permite hacer algunas cosas realmente creativas si lo deseamos.

destino-salida globalCompositeOperation

Se muestra un ejemplo que usa el modo de composición de destino en el lienzo para "cortar" formas del mapa; aquí se superpone un mapa monocromo sobre uno de color y luego se anima la revelación. [video completo]

Uso futuro

Tan divertido como fue escribir, y tan útil como esto fue para mi creación de prototipos (alimentó docenas de prototipos durante mi tiempo en el equipo) Google y MapBox tienen una representación vectorial que supera este enfoque de escala y mezcla. Me gustaría alentar a todos los demás, que no están actualizando a mosaicos vectoriales, a considerar implementar algo similar. Es una técnica bastante simple que no agrega mucha complejidad al cliente (ciertamente menos trabajo que la representación vectorial), pero permite una experiencia mucho más fluida y receptiva.