viernes, 15 de enero de 2016

Libro Google maps Javascript - Capítulo 3: Maker arrastrable en el mapa y animado


Volver al indice


Maker arrastrable en el mapa y animado


Con la propiedad “draggable” del objeto marker podemos habilitar, que el marker sea arrastrado por el usuario.

google.maps.event.addListenerOnce(map, 'idle', function() {   
    var marker = new google.maps.Marker({
        position: new google.maps.LatLng(-34.397, 150.644),
        title : "Hola soy el marcador",
        map: map ,
        draggable : true
    });           
});

Y con la propiedad “animation” podemos darle cierta animación al marker usando la clase google.maps.Animation.

google.maps.event.addListenerOnce(map, 'idle', function() {   
   var marker = new google.maps.Marker({
           position: new google.maps.LatLng(-34.397, 150.644),
           title : "Hola soy el marcador",
           map: map ,
              draggable : true
   });           
   google.maps.event.addListener(marker, 'click', function() {
      if (marker.getAnimation() != null) {
        marker.setAnimation(null);
      } else {
             marker.setAnimation(google.maps.Animation.BOUNCE);
      }
   });           
});

Aquí usamos el método getAnimation() del objeto marker, para saber si hay alguna animación activa y si la hay,  entonces la detenemos pasando el valor null a setAnimation().

Overlay : Polylines.


Ahora pasaremos a ver cómo dibujar figuras geométricas en nuestro mapa, que nos permitirá crear caminos , bordes y áreas. Primero vamos comenzar con la overlay Polyline , Una simple polyline esta formada por un punto inicial y otro final,  los cuales se conectan por una línea . También una polyline puede ser una colección de puntos para formar formas más complejas.

Cada punto de la polyline será un punto LatLng en el mapa, que debemos crear de antemano,  como lo hemos hecho anteriormente. Aquí la parte difícil, es saber cuales son esos puntos Latlng en el mapa. Por ahora vamos a usar valores fijos, que sabemos de antemano. Pero más adelante vamos a dejar que el propio usuario dibuje su propia polyline donde desee.

A continuación podemos abrir el archivo de ejemplo de la carpeta número  ”5”  y ejecutamos el archivo “index.html” y  veremos a continuación una polyline creada por el siguiente código:

var polylineCoordinates = [
    new google.maps.LatLng(37.772323, -122.214897),
    new google.maps.LatLng(21.291982, -157.821856),
    new google.maps.LatLng(-18.142599, 178.431),
    new google.maps.LatLng(-27.46758, 153.027892)
];       
var polyline = new google.maps.Polyline({
    path:  polylineCoordinates,
    map : map
});

Lo primero que estamos haciendo, es crear un arreglo de puntos Latlng llamado ”polylineCoordinates“,  donde cada elemento del arreglo  es un punto Latlng.  Seguido  creamos nuestra polyline usando la clase “google.maps.polyline” y pasamos nuestro objeto que tiene como propiedades las opciones básicas :

map :  Que es nuestro objeto mapa donde queremos que aparezca la polyline.

Path : Que son las coordenadas de puntos Latlng , en este caso hemos definido un arreglo de puntos. Ya que esta propiedad recibe un arreglo de puntos.

Con esto basta para crear una polyline básica. A continuación, jugaremos un poco con las opciones adicionales disponibles. Por ejemplo podemos hacer nuestra polyline de otro color , ancho y que sea editable para el usuario, esto permitirá al usuario cambiar la forma de la polyline.

var polyline = new google.maps.Polyline({
    path: polylineCoordinates,
    strokeColor: "#FF0000",
    strokeWeight: 3,
    editable: true,
    map:map
});

Si copiamos y pegamos este código, reemplazando el anterior y recargamos la página podemos ver que nuestra polyline es de color rojo y más gruesa. Esto es debido a “strokeColor” y “strokeWeight”. También habrás notado que ahora aparecen unos círculos en cada punto de la polyline esto significa que puedes arrastrar con el mouse estos puntos por el mapa para cambiar la forma de la polyline a libertad. Esto se logra con la propiedad “editable”.

Una opción de polyline que me gustaría mencionar es “strokeOpacity” que sirve para volver la polyline transparente. Según la documentación en línea se definen así :

strokeColor: Especifica un color HTML hexadecimal del formato "#FFFFFF". La clase Polyline no admite colores con nombre.

strokeOpacity : Especifica un valor fraccional numérico entre 0.0 y 1.0 (predeterminado) correspondiente a la opacidad del color de la línea.

strokeWeight  : Especifica el grosor del trazo de la línea en píxeles.

Ahora quisiera hablar un poco sobre la opción  ”path”, según la API se define de la siguiente manera :

path

Como puedes ver, segun la definicion podemos usar un arreglo de Latlng normal, a como lo hicimos en el ejemplo anterior  o un MVCArray .  ¿ Pero que es un MVCArray ?  

Bueno es un tipo de objeto en la API de google Maps, básicamente es un arreglo que contiene puntos Latlng,  pero la diferencia es que contiene métodos especiales para insertar, borrar  y obtener valores de sus elementos. La gran ventaja de usar un MVCArray en lugar de un arreglo normal, es que si modificamos nuestro MVCArray en cualquier momento, después de que la polyline fue  dibujada, esta se actualizará automáticamente con los nuevos valores que tenga el MVCArray , ya sea borrando un punto o agregando uno nuevo.

Si abrimos el “index.html” de la carpeta de práctica número “6”,  podemos ver que tenemos nuestra polyline dibujada en el mapa de color rojo, pero hacemos click en el botón “click me”,  podrás ver como la polyline se le resta un punto Latlng de su path, cada vez que haces click en el botón.  Ahora pasamos a ver el código:

//event click jquery
$('#actionButton').on('click',function(){   
    MVCArray.pop();
});   
// when the map is ready
google.maps.event.addListenerOnce(map, 'idle', function() {       
    MVCArray = new google.maps.MVCArray([
        new google.maps.LatLng(37.772323, -122.214897),
        new google.maps.LatLng(21.291982, -157.821856),
        new google.maps.LatLng(-18.142599, 178.431),
        new google.maps.LatLng(-27.46758, 153.027892)
    ]);
    var polyline = new google.maps.Polyline({
        path: MVCArray,
        strokeColor: "#FF0000",
        strokeWeight: 3,
        editable: true,
        map:map
    });       
});
   

Ok lo primero a notar en el archivo ”googlemaps.js” de carpeta número “6”, es que he definido la variable “MVCArray” de forma global para poder acceder a ella desde cualquier lugar de la aplicación.
Segundo para crear un MVCArray, usamos la clase google.maps.MVCArray y según la API  el único parámetro necesario es un arreglo de puntos Latlng. Una vez creado lo pasamos en la propiedad “path” de las opciones de nuestra Polyline.

Tercero en el evento click del botón, ejecutamos el método “pop” del objeto MVCArray, que habíamos creado anteriormente y guardado en la variable del mismo nombre. Lo que hace el método “pop” es remover el último elemento del arreglo y automáticamente nuestra polyline se actualiza con el nuevo conjunto de elementos en el MVCArray. Esto mismo lo podemos hacer con todos los métodos disponibles para un objeto MVCArray, que podemos consultar en la API. Por ejemplo : removeAt , push , setAt , etc.

Para finalizar les presento este código de ejemplo sacado de este enlace  en la documentación de Google Maps, sobre cómo agregar un flecha al final de nuestra polyline aplicado a nuestro ejemplo:

var lineSymbol = {
    path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW
};   
var polyline = new google.maps.Polyline({
    path: MVCArray,
    strokeColor: "#FF0000",
    icons: [{
    icon: lineSymbol,
    offset: '100%'
    }],
    map:map
});



Overlay :  Polygons


Polygons son una serie de puntos Latlngs, que tienen un punto inicial y un punto final  y que se conectan para formar un figura cerrada  en el mapa. Las polylines se pueden usar para marcar rutas y los polygons son muy útiles para marcar áreas geográficas en el mapa.



Ahora pasemos a ejecutar el archivo “index.html” de la carpeta de practica numero “7”, en el cual  podremos ver en el mapa un overlay polygon de 3 puntos, el cual es formado por el siguiente código.


var points = [
    new google.maps.LatLng(37.7671, -122.4206),
    new google.maps.LatLng(36.1131, -115.1763),
    new google.maps.LatLng(34.0485, -118.2568),
];       
var polygon = new google.maps.Polygon({
    paths: points,
    map: map
});

Al igual que la polyline, definimos un arreglo de puntos Latlng que forman la figura de nuestro polygon, para crear nuestro polygon usamos la clase “google.maps.Polygon”. El cual recibe  como parámetro un objeto con las opciones de la clase ”google.maps.Polygon”, de la misma manera como hicimos con el overlay polyline. En este caso, solo usamos la propiedad “paths” que son una secuencias de puntos Latlng  y “map” que es el mapa donde queremos dibujar nuestra overlay polygon. Debes de notar que en nuestro arreglo de Latlng no esta el punto final de cierre de nuestro polygon, esto es debido a que el punto inicial siempre es considerado el punto final de cierre del overlay polygon.

De esta manera, es que se crea un polygon simple. Si consultas la API de la clase ”google.maps.Polygon” Podrás notar que en las opciones, tenemos propiedades muy similares a las que tiene polyline, pero hay 2 propiedades que vale la pena discutir de polygon:

fillColor : Define el color del área dentro del polygon.
fillOpacity : Define la opacidad del área dentro del polygon.

var points = [
    new google.maps.LatLng(37.7671, -122.4206),
    new google.maps.LatLng(36.1131, -115.1763),
    new google.maps.LatLng(34.0485, -118.2568),
];
       
var polygon = new google.maps.Polygon({
    paths: points,
    map: map ,
    strokeColor: '#0000ff',
    strokeOpacity: 0.6,
    strokeWeight: 1,
    fillColor: '#40FF00',
    fillOpacity: 0.35
});


Si copias y pegas este código para reemplazar el anterior y refrescamos la página, veremos ahora como nuestro polygon tiene un área verde transparente y con las líneas de los bordes azules.

Entres todas las propiedades de polygon existe una que vale la pena mencionar es zIndex, esta propiedad sólo es útil cuando tienes varios polygons en el mapa y con esta propiedad puedes controlar el orden en el que son situados en el mapa. Por ejemplo un polygon con el valor de zIndex de 2 sera dibujado sobre el polygon que tenga el zIndex de 1.  Si no especificas el valor de esta propiedad los polygon se colocarán en el orden que se vaya ejecutando en el código.

Ahora vamos hacer algo interesante para practicar los eventos del usuario en nuestro mapa:

var points = [
    new google.maps.LatLng(37.7671, -122.4206),
    new google.maps.LatLng(36.1131, -115.1763),
    new google.maps.LatLng(34.0485, -118.2568),
];               
var polygon = new google.maps.Polygon({
    paths: points,
    map: map ,
    strokeColor: '#0000ff',
    strokeOpacity: 0.6,
    strokeWeight: 1,
    fillColor: '#40FF00',
    fillOpacity: 0.35
});       
google.maps.event.addListener(polygon, 'click', function() {
    alert('Hola soy el polygon');
});               
google.maps.event.addListener(polygon, 'mouseover', function() {
    polygon.setOptions({
        fillColor: '#0000ff',
        strokeColor: '#0000ff'
    });
});
google.maps.event.addListener(polygon, 'mouseout', function() {
    polygon.setOptions({
        fillColor: '#40FF00',
        strokeColor: '#0000ff',
    });
});


Ahora si copiamos y reemplazamos el código anterior, por este de arriba y refrescamos la página, podemos notar que al pasar el mouse por el overlay polygon cambia de color y al  retirarlo vuelve a su estado normal. También si hacemos click sobre él, nos abrirá una ventana que dice “Hola son el polygon”. Esto lo podemos lograr usando una propiedad común entres los overlays llamada “setOptions” que es para cambiar opciones cuando nosotros queramos .

Overlay :  Circle


Circle es otro overlay que podemos crear dentro de nuestro mapa. Es similar a un Polygon ya  que puedes definir colores, grosores y niveles de opacidad personalizados. A diferencia de un Polygon, en overlay circle no se definen paths. En su lugar tiene dos propiedades que definen su forma:

center : Especifica los valores de latitud y longitud en Google Maps (google.maps.LatLng) del centro del círculo.

radius:  Especifica el radio del círculo, en metros.

Ahora podemos abrir el archivo “index.html” de la carpeta de práctica numero “8”,  y podremos ver como en nuestro mapa ahora aparece un overlay circle, el cual es creado por el siguiente código:
   
google.maps.event.addListenerOnce(map, 'idle', function() {   
    circle = new google.maps.Circle({
        strokeColor: "#FF0000",
        strokeOpacity: 0.8,
        strokeWeight: 2,
        fillColor: "#FF0000",
        fillOpacity: 0.35,
        map: map,
        center: new google.maps.LatLng(34.052234, -118.243684),
        radius: 3844829
    });       
});

Para poder crear un circle, necesitamos usar la clase “google.maps.Circle” y pasamos un objeto con las opciones como lo hemos hecho antes. En este código podemos ver muchas propiedades similares que hemos usado anteriormente, las que tienes que notar son “center” y ”radius” que son las únicas propiedades obligatorias para crear un overlay cirlce.

Hasta aquí es todo con esta overlay no tenemos mucho que hablar sobre ella, solo que es un círculo que podemos usar en nuestro mapa.

Overlay :  Rectangle


Un overlay rectangle es muy similar a circle, hablando sobre las opciones que se pueden configurar. El único parámetro obligatorio de un rectangle es :

bounds: Es un objeto específico de Google Maps, que se crea con la clase “google.maps.LatLngBounds”, al cual necesitamos pasar 2 parámetros que son las coordenadas  “southwest” y  ”northeast” que corresponden a las esquinas suroeste y noreste del bounds según la API. La siguiente imagen ilustra cuales son estos puntos.

LatLngBounds(sw?:LatLng, ne?:LatLng)



En otras palabras, bounds es un rectángulo que define un área y sus esquinas son coordenadas geográficas definidas por Latlng, por lo tanto todo lo que se encuentra dentro  se considera dentro de sus límites ó bounds. Esto puede ser muy útil para calcular si un objeto está dentro de cierta área en el mapa, ya que algunos overlay poseen sus propios bounds como por ejemplo circle y polygon. Tengo que mencionar que el viewport de nuestro mapa donde aparecen todas las figuras también es un bounds, y cada vez que hacemos zoom y nos movemos por el mapa, ese bounds cambia constantemente. La siguiente imagen muestra en líneas punteadas negras los bounds imaginarios de circle y polygon, que aunque no los veamos en el visor los bounds siempre estan presente.







Para crear un bounds lo hacemos de la siguiente manera, usando la clase google.maps.LatLngBounds de Google Maps.

var bounds = new google.maps.LatLngBounds(
   new google.maps.LatLng(37.775,-122.419),
   new google.maps.LatLng(47.620,-73.986)
);

Recomiendo revisar los métodos del objeto bounds en la documentación de la API, que ya posee métodos muy útiles a tener en cuenta, como por ejemplo :
contains(latLng:LatLng)  que retorna true si un objeto Latlng esta dentro del bounds.

Ahora volviendo a nuestro overlay rectangle, vamos a abrir el “index.html” de la carpeta de practica numero “9”, donde vamos a ver un overlay rectangle dibujado en el mapa con el siguiente código:

google.maps.event.addListenerOnce(map, 'idle', function() {
    var bounds = new google.maps.LatLngBounds(
        new google.maps.LatLng(37.775,-122.419),
        new google.maps.LatLng(47.620,-73.986)
    );   
    rectangle = new google.maps.Rectangle({
            strokeColor: "#FF0000",
            strokeOpacity: 0.8,
            strokeWeight: 2,
            fillColor: "#FF0000",
            fillOpacity: 0.35,
            map: map,
            bounds: bounds
    });       
});

Algunos eventos a tener en cuenta de los overlay


Anteriormente vimos como crear eventos para nuestros overlay, ahora vale la pena revisar una tabla que nos muestra que tipo de eventos adicionales podemos capturar para ellos.  Según la documentación del API, cuando un overlay tiene la propiedad ”editable” en true, tenemos los siguientes eventos que podemos a capturar para realizar las cualquier acción.


Forma
Eventos
Círculo
radius_changed , center_changed
Polígono
insert_at , remove_at , set_at
Polilínea
insert_at , remove_at , set_at
Rectángulo
bounds_changed

Un ejemplo de como usarlo:

google.maps.event.addListener(circle, 'radius_changed', function() {
    //acciones que tu quieras realizar
});

Overlay : Ground


Con este tipo de overlay,  podemos crear un objeto que nos permitirá mostrar un imagen dentro del mapa, para crearlo usamos la clase “google.maps.GroundOverlay” que  permite especificar la URL de una imagen y el objeto LatLngBounds, donde la imagen será insertada en forma de parámetros. Ahora abramos el archivo “index.html” de la carpeta “10” donde podremos ver nuestro ejemplo en acción con el siguiente código.

var imageBounds  = new google.maps.LatLngBounds(
    new google.maps.LatLng(37.775,-122.419),
    new google.maps.LatLng(47.620,-73.986)
);
var imageLink = "http://wowslider.com/images/demo/pinboard-fly/data/images/desert_landscape.jpg";   
overlay = new google.maps.GroundOverlay(imageLink, imageBounds);
overlay.setMap(map);

Primero definimos el bounds para nuestra imagen, recuerda que las imágenes siempre son rectangulares por esa razón necesitamos un bounds, que es el lugar donde queremos colocar nuestra imagen. Después guardamos en una variable el link de nuestra imagen que  pasaremos como parámetro a la clase “google.maps.GroundOverlay”.

Hasta aquí, creo que no hay más que discutir sobre el código. Creamos nuestra instancia de la clase y pasamos sus 2 parámetros necesarios, seguido asignamos el mapa donde queremos que aparezca.

Hace unos meses modifique un ejemplo de Google Maps que permite al usuario ingresar un link de una imagen para insertarla en el mapa , la diferencia con el ejemplo anterior que vimos, es que permite redimensionarla y moverla a por todo el mapa , si quieres ver el código y el ejemplo funcionando visita este link :


Drawing Library


Bueno y llegamos al punto donde seguramente has pensado : ”voy crear una aplicación que permita al usuario dibujar formas dentro del mapa”. Si lo has hecho, ya habrás anticipado que necesitas crear cada boton de accion que dibuje cada overlay en el mapa, lo que se traduce en mucho trabajo por hacer.

Antes de que empieces con ese proyecto, déjame presentarte la “Drawing Library” de Google Maps, que son un conjunto de herramientas que permitirán al usuario dibujar todas las overlay en el mapa, sin que nosotros tengamos que escribir código. En palabras de Google Maps la definición sería :

La clase DrawingManager, proporciona una interfaz gráfica que permite que los usuarios dibujen polígonos, rectángulos, polilíneas, círculos y marcadores en el mapa.

Ok para comenzar a usar esta clase, lo primero que tenemos que hacer es cargar la “Drawing Library”  en nuestro “index.html” de la carpeta de práctica número “11”.

En nuestros ejemplos siempre cargamos Google Maps de la siguiente manera :

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>

Pero con esto, no estamos cargando la “Drawing library” aún, tenemos que agregar un parámetro adicional para cargar la “Drawing library” .

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=drawing"></script>

Con el código de arriba, cargamos la “Drawing library” pasando en la query string el parámetro “libraries” con el valor “drawing”. Ahora con nuestra “Drawing library” cargada podemos abrir nuestro “index.html” y veremos en viewport del mapa una caja de herramientas arriba con la podremos dibujar todas las overlay vistas anteriormente con solo 2 lineas de código:

google.maps.event.addListenerOnce(map, 'idle', function() {
    var drawingManager = new google.maps.drawing.DrawingManager();
    drawingManager.setMap(map);               
});

Para crear nuestra Toolbar de dibujo, usamos la clase “ google.maps.drawing.DrawingManager” y solamente necesitamos usar el método setMap() de la clase, para situarlo en el mapa en su posición por defecto. Algunas de la opciones que podemos pasar a la clase son:

drawingMode: Con esta propiedad podemos especificar qué herramienta será la inicial cuando cargue el mapa, el parámetro que recibe es una constante de la clase “google.maps.drawing.OverlayType” de las que podemos escoger las siguientes :

google.maps.drawing.OverlayType.MARKER
google.maps.drawing.OverlayType.CIRCLE
google.maps.drawing.OverlayType.POLYGON
google.maps.drawing.OverlayType.POLYLINE
google.maps.drawing.OverlayType.RECTANGLE

Ejemplo :

drawingManager = new google.maps.drawing.DrawingManager({
    drawingMode: google.maps.drawing.OverlayType.MARKER
});

drawingControl: Valor booleano para mostrar o ocultar las herramientas.

drawingControlOptions: Usamos esta propiedad para definir cuáles herramientas queremos mostrar y en qué posición en el viewport del mapa mostrar las herramientas.  Recibe como parámetro un objeto “google.maps.drawing.DrawingControlOptions”  que esta formado por 2 propiedades “drawingModes” donde especificamos cuales herramientas queremos mostrar  y ”position” donde especificamos la position en el viewport del mapa de las herramientas.

  • drawingModes : Acepta un arreglo donde cada elemento del arreglo, es una constante de la clase  “google.maps.drawing.OverlayType”  que vimos anteriormente:  MARKER , CIRCLE ,POLYGON , POLYLINE , RECTANGLE.

  • position : Acepta una constante de la clase “google.maps.ControlPosition” que podrian ser BOTTOM_CENTER , BOTTOM_LEFT , BOTTOM_RIGHT , LEFT_BOTTOM , LEFT_CENTER , LEFT_TOP , RIGHT_BOTTOM , RIGHT_CENTER , RIGHT_TOP , TOP_CENTER , TOP_LEFT , TOP_RIGHT .

Ejemplo :

drawingManager = new google.maps.drawing.DrawingManager({
    drawingControlOptions: {
        position: google.maps.ControlPosition.RIGHT_CENTER,
            drawingModes: [
                google.maps.drawing.OverlayType.MARKER,
                google.maps.drawing.OverlayType.CIRCLE
            ]
    }           
});

markerOptions, polygonOptions, polylineOptions, rectangleOptions : Todas estas opciones trabajan de la misma manera. Lo que hacen es definir la configuración de cada overlay que se dibujara en el mapa, cada una de estas opciones acepta un objeto con la configuración de su tipo de overlay específico que ya hemos visto anteriormente.

Un método de “Drawing library” muy útill es “setOptions()”,  el cual podemos usar para cambiar el comportamiento de nuestras herramientas, con solo pasar un objeto con las nuevas opciones que queremos configurar.

Ejemplo :

drawingManager.setOptions({
    drawingControl: false,
    drawingControlOptions: {
        position: google.maps.ControlPosition.BOTTOM_CENTER,
    }
});

Adicionalmente “Drawing library” nos ofrece eventos de los que podemos tomar ventaja para realizar ciertas acciones.

  • overlaycomplete : Este evento ocurre cuando cualquier tipo de overlay a sido dibujado en el mapa.
  • {tipo-overlay}complete : Este evento ocurre cuando un overlay específico ha sido dibujado en el mapa  donde tenemos que reemplazar el nombre del overlay entre las llaves por ejemplo : ”circlecomplete” , “rectanglecomplete” .

Si abrimos el archivo “index.html” de la carpeta practica numero “12”, podemos ver como cuando dibujamos un overlay rectangle ocurren 2 eventos , pero si dibujamos cualquier otro solo ocurre un evento con el siguiente código en el archivo “googlemaps.js”:

google.maps.event.addListenerOnce(map, 'idle', function() {       
    drawingManager = new google.maps.drawing.DrawingManager();       
    google.maps.event.addListener(drawingManager, 'rectanglecomplete', function(event)       {
        alert('event : Rectangle is complete');
    });
    google.maps.event.addListener(drawingManager, 'overlaycomplete', function(event) {
        alert('event : a overlay was drew');
    });       
    drawingManager.setMap(map);       
});

En el código vemos que pasamos el objeto “drawingManager”, con sus respectivos eventos que necesitamos para ejecutar acciones. El parámetro “event” que es pasado al callback cuando se ejecuta el evento, contiene un objeto con 2 propiedades:

type:  Que es una cadena de texto, donde nos describe el tipo de overlay.
overlay: El objeto overlay creado, podemos usar este objeto cuando queramos en nuestra aplicación.





No hay comentarios:

Publicar un comentario