Mapas interactivos en HTML5 con SnapSVG
06/03/2016
HTML5 ha llegado aquí y está para quedarse y puede usarse en prácticamente cualquier sitio. Además según la encuesta del blog HTML5 era uno de los temas en los que estabais más interesados. Hoy vamos a ver como se puede hacer un mapa interactivo fácilmente, compatible con PCs, tabletas y móviles y veremos como los podemos animar.
Aquí entra en juego SnapSVG. Se trata de una librería para JavaScript financiada y acogida por Adobe. Es una mejora de la ya popular librería para tratar SVG conocida como RaphaëlJS (ambas librerías son del mismo autor). Sin embargo, SnapSVG aporta muchas mejoras respecto a RaphaëlJS. La fundamental es que SnapSVG permite cargar archivos SVG ya existentes.
Actualmente es fácil encontrar mapas en SVG de cualquier territorio. Sin embargo para que sea fácil trabajar con ellos hay que procurar que estén preparados para interactuar con ellos. Es necesario que las etiquetas
En nuestro HTML creamos una etiqueta
Primero necesitamos obtener un papel (Paper en la documentación), con la función Snap y un selector CSS obtenemos el papel que ya hemos creado.
Ahora ya podemos usar todo el poder de SnapSVG, pero si queremos trabajar con un SVG ya existente el procedimiento es un poco distinto.
Podemos alterar los atributos de estilo de SVG. Para quién no los conozca, funcionan igual que las propiedades CSS pero se aplican de manera distinta. Con SnapSVG podemos cambiar esos atributos en tiempo de ejecución. Por ejemplo, el relleno (propiedad
Podemos añadir figuras simples de manera muy sencilla
Ahora viene la parte interesante, eventos y animaciones. SnapSVG soporta varios tipos de evento en cada elemento. Veamos el click simple aunque existe doble click, ratón por encima, táctil (aunque click funciona en pantallas táctiles).
Podemos animar los elementos especificando las propiedades que cambian y su tiempo
SnapSVG es muy potente y permite realizar muchas más operaciones, como elementos arrastrables, grupos, patrones, filtros y más. El objetivo, según Adobe, es ser el jQuery de los documentos SVG.
SVG es un formato vectorial así que podemos aumentar el tamaño sin tener que preocuparnos por los píxeles. Sin embargo si simplemente cambias el tamaño del elemento
SnapSVG se puede usar en Apache Cordova. Sin embargo yo he tenido problemas de rendimiento con la configuración por defecto en Android. Para solventar este problema he tenido que:
Solo así conseguí un rendimiento decente dentro de Cordova.
Haz click en la provincia de Valladolid múltiples veces
SnapSVG
Aquí entra en juego SnapSVG. Se trata de una librería para JavaScript financiada y acogida por Adobe. Es una mejora de la ya popular librería para tratar SVG conocida como RaphaëlJS (ambas librerías son del mismo autor). Sin embargo, SnapSVG aporta muchas mejoras respecto a RaphaëlJS. La fundamental es que SnapSVG permite cargar archivos SVG ya existentes.
Mapas en SVG
Actualmente es fácil encontrar mapas en SVG de cualquier territorio. Sin embargo para que sea fácil trabajar con ellos hay que procurar que estén preparados para interactuar con ellos. Es necesario que las etiquetas
<path>
posean un atributo id
y sea fácilmente reconocible. En el caso del mapa de España que hay al principio, el mapa está muy bien organizado. Las provincias empiezan por pr, los enclaves por en y las islas por is. Así que Valladolid es pr_valladolid
y Menorca es is_menorca
. Encontrar mapas así ya puede ser más difícil pero no imposible.Primeros pasos
En nuestro HTML creamos una etiqueta
<svg>
con un id
, por ejemplo id=papel
. Ya está. Ahora pasamos al JavaScript.Primero necesitamos obtener un papel (Paper en la documentación), con la función Snap y un selector CSS obtenemos el papel que ya hemos creado.
var s = Snap("#papel");
Ahora ya podemos usar todo el poder de SnapSVG, pero si queremos trabajar con un SVG ya existente el procedimiento es un poco distinto.
var s = Snap("#papel"); // Obtenemos el papel
Snap.load("/mapa.svg",function(f){
// Al cargar el mapa se nos devuelve un fragmento
// los fragmentos contienen elementos de SVG
// Como queremos añadir todos los elementos, los seleccionamos todos, como un único grupo
// otra vez vemos los selectores CSS en acción
var g = f.selectAll("*");
// y ahora añadimos el grupo al papel
s.append(g);
// cuando querramos acceder a un elemento podemos usar un selector CSS
var valladolid = s.select("#pr_valladolid");
});
Atributos
Podemos alterar los atributos de estilo de SVG. Para quién no los conozca, funcionan igual que las propiedades CSS pero se aplican de manera distinta. Con SnapSVG podemos cambiar esos atributos en tiempo de ejecución. Por ejemplo, el relleno (propiedad
fill
).
s.attr({
fill: "red"
});
// Cambia el relleno a rojo, afecta a los elementos inferiores, en este caso como es el papel, afecta a todo el SVG.
Figuras simples
Podemos añadir figuras simples de manera muy sencilla
var rect = s.rect(0,0,100,20).attr({fill: "cyan"});
// Creamos un rectángulo de 100x20 en la posición (0,0) con relleno cyan.
// Luego lo podemos borrar
rect.remove();
Eventos y animaciones
Ahora viene la parte interesante, eventos y animaciones. SnapSVG soporta varios tipos de evento en cada elemento. Veamos el click simple aunque existe doble click, ratón por encima, táctil (aunque click funciona en pantallas táctiles).
var murcia = s.select("#pr_murcia");
murcia.click(function(){
murcia.attr({
fill: "yellow"
});
});
Podemos animar los elementos especificando las propiedades que cambian y su tiempo
murcia.animate({fill: "purple"},1000);
SnapSVG es muy potente y permite realizar muchas más operaciones, como elementos arrastrables, grupos, patrones, filtros y más. El objetivo, según Adobe, es ser el jQuery de los documentos SVG.
Escalar imagen automáticamente
SVG es un formato vectorial así que podemos aumentar el tamaño sin tener que preocuparnos por los píxeles. Sin embargo si simplemente cambias el tamaño del elemento
<svg>
vía CSS verás que no funciona. Es necesario especificar un atributo viewBox
y mantenerlo constante. Básicamente viewBox da las dimensiones reales del lienzo donde se dibuja el SVG. Si cambian width
y height
y viewBox
también entonces la imagen no se escala, simplemente se amplía el área del lienzo. Algunos mapas en SVG no ofrecen viewBox. En ese caso espeficicamos como viewBox el tamaño original del fichero SVG. En el caso de querer ocupar toda la pantalla.
s.attr({ viewBox: "0 0 800 600",width: window.innerWidth, height: window.innerHeight});
window.addEventListener("resize",function(){
s.attr({ viewBox: "0 0 800 600",width: window.innerWidth, height: window.innerHeight});
});
Cordova y Android
SnapSVG se puede usar en Apache Cordova. Sin embargo yo he tenido problemas de rendimiento con la configuración por defecto en Android. Para solventar este problema he tenido que:
- Instalar el plugin Crosswalk de Android WebView
- Desactivar la aceleración por hardware en la aplicación.
- En el AndroidManifest.xml poner
android:hardwareAccelerated="false"
- En el AndroidManifest.xml poner
Solo así conseguí un rendimiento decente dentro de Cordova.