Guardando puntos de interés arrastrables de Google Maps V3
Este artículo demuestra cómo crear puntos de interés en Google Maps con la API Directions y guardarlos para que puedan visualizarse en un momento futuro en la UI (interfaz de usuario).
Google Maps V3 cuenta con un servicio mediante el cual podemos mostrar la dirección desde un punto de partida hasta un punto de llegada, el cual se puede arrastrar para modificar el trayecto. Con el ratón, el usuario podrá alterar la ruta según sus necesidades. Esto significa modificar el trayecto predeterminado proporcionado por Google. El usuario podrá entonces crear puntos de interés entre el trayecto predeterminado y mostrarlos para diferenciar la ruta actual de la modificada. Para fines de desarrollo, Google permite un máximo de ocho puntos de interés.
El aspecto de la aplicación final será el siguiente:

Prerrequisitos: antes de comenzar, asegúrese de que el JDK y Glassfish 3.1 estén instalados y configurados en su equipo junto con el IDE Eclipse.
Ejecute el IDE Eclipse y seleccione un espacio de trabajo (workspace) donde desee crear el proyecto.
1º Haga clic en File-> New-> Dynamic Web Project. (Figura 2)

2º Elija un nombre para el proyecto (GDirections). Figura 3

Mantenga la configuración tal como se muestra en la Figura 4.

Finalice el proyecto haciendo clic en el botón Finish. Figura 5

Añada al directorio Web-Inf/lib todas las librerías de resteasy. Figura 6

Cree la clase dentro de la carpeta src, br.com.rezende.map.services.DirectionsServices, y añada el archivo index.jsp dentro de WebContent. Figura 7

Añada una carpeta script en WebContent. Figura 8

Añada el archivo json2.js a la carpeta script. Figura 9

El mapa de la izquierda (Figura 1) es donde se creó el trayecto predeterminado, el cual permite alterar y añadir 8 puntos de interés. Para modificar dicho trayecto y añadir puntos de interés, mueva el ratón sobre la línea amarilla y espere a que aparezca el círculo. Arrastre el círculo en cualquier dirección y suelte el botón del ratón. De esta forma, el usuario podrá alterar la ruta con solo arrastrar el círculo con el ratón y crear nuevos puntos de interés. Al hacer clic en el botón «Guardar», un servicio almacena la cadena «JSON» en una variable para que pueda ser recuperada posteriormente. No estamos utilizando bases de datos en este momento, ya que el enfoque de este artículo es únicamente demostrar cómo se utiliza la API Google Directions.
Código y Explicación
Puede utilizar el mismo código escrito en este artículo.
Es necesario que tenga ciertos conocimientos sobre Google Maps V3, tales como mostrar el mapa dentro de un elemento <div> y centrarlo pasando la latitud y la longitud como parámetros al objeto del mapa.
Vea a continuación la explicación del flujo realizado.
En el archivo web.xml añada las siguientes líneas:
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
En la clase creada anteriormente, DirectionsServices, añada el siguiente código.
@Path('/rest/directionsWS')
public class DirectionsServices {
private static String gMapsJson;
@GET
@Produces('application/json')
@Path('/render')
public String render() {
String resp = gMapsJson;
System.out.println('Foi');
return resp;
}
@GET
@Path('/save/{param}')
@Produces('application/json')
public String save(@PathParam('param') String json) {
this.gMapsJson = json;
return gMapsJson;
}
}
Incluya el siguiente código en la sección de cabecera de su index.jsp. El primero incluirá la API de Google Maps V3 y el segundo se utiliza para crear una cadena JSON a partir de una matriz de objetos.
<script type='text/javascript' src='https://maps.google.com/maps/api/js?sensor=false'></script>
<script src='json2.js'></script>
Esta matriz de objetos convierte los puntos de interés al formato JSON y posteriormente detendrá el servidor y los guardará en nuestra variable estática.
Aún dentro de index.jsp, cree un elemento div con un id igual a map_canvas y sus estilos. Cree también un botón para invocar una función Javascript que guardará los puntos de interés. Cuando se inicialice la página, esta misma llamará a la función Javascript initialize(), la cual cargará el mapa predeterminado que se muestra en el lado izquierdo de la Figura 1.
<body onload='initialize()'>
<form id='form'>
<div class='contents' style='width: 90%; margin: 0px auto;'>
<div class='maindiv' style='width: 100%;'>
<table width='100%' border='0' cellspacing='0' cellpadding='0'>
<tr>
<td width='49%' style='padding: 3px; color: #993333;'>Haga clic en el trayecto amarillo y arrástrelo a otra ubicación.</td>
<td width='2%' style='padding: 3px; color: #993333;'> </td>
<td width='49%' style='padding: 3px; color: #993333;'>Haga clic en el botón cargar para mostrar el trayecto guardado.</td>
</tr>
<tr>
<td><div id='map_canvas' style='width: 100%; height: 250px;'></div></td>
<td> </td>
<td><div id='map_ren' style='width: 100%; height: 250px;'></div></td>
</tr>
<tr>
<td style='text-align: center; padding-top: 10px;'>
<input type='button' value='Salvar' id='save' name='save'/>
</td>
<td style='text-align: center;'> </td>
<td style='text-align: center; padding-top: 10px;'>
<input type='button' id='render' name='render' value='Render' />
</td>
</tr>
</table>
</div>
</div>
</form>
</body>
Añada al archivo index.jsp las funciones y variables Javascript que se utilizarán para representar («plotar») los mapas y los trayectos.
<script type='text/javascript'>
var directionDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
var data = {};
var polylineOptionsActual = {
strokeColor : '#FFF000',
strokeOpacity : 1.0,
strokeWeight : 6
};
var directionDisplay2;
var directionsService2 = new google.maps.DirectionsService();
var map2;
var polylineOptionsActual2 = {
strokeColor : '#FF0000',
strokeOpacity : 1.0,
strokeWeight : 6
};
function initialize() {
var blumenau = new google.maps.LatLng(-26.889005, -49.070641);
var florianopolis = new google.maps.LatLng(-27.566721, -48.551537);
directionsDisplay = new google.maps.DirectionsRenderer({
polylineOptions : polylineOptionsActual,
'draggable' : true
});
directionsDisplay2 = new google.maps.DirectionsRenderer({
polylineOptions : polylineOptionsActual2,
'draggable' : false
});
var myOptions = {
zoom : 12,
mapTypeId : google.maps.MapTypeId.HYBRID,
center : blumenau
};
map = new google.maps.Map(document.getElementById('map_canvas'),
myOptions);
map2 = new google.maps.Map(document.getElementById('map_ren'),
myOptions);
directionsDisplay.setMap(map);
directionsDisplay2.setMap(map2);
directionsService.route({
'origin' : blumenau,
'destination' : florianopolis,
'travelMode' : google.maps.DirectionsTravelMode.DRIVING
}, function(res, sts) {
if (sts == 'OK') {
directionsDisplay.setDirections(res);
}
});
}
function setroute(os) {
var wp = [];
for ( var i = 0; i < os.waypoints.length; i++)
wp[i] = {
'location' : new google.maps.LatLng(os.waypoints[i][0],
os.waypoints[i][1]),
'stopover' : false
};
directionsService2.route({
'origin' : new google.maps.LatLng(os.start.lat, os.start.lng),
'destination' : new google.maps.LatLng(os.end.lat, os.end.lng),
'waypoints' : wp,
'travelMode' : google.maps.DirectionsTravelMode.DRIVING
}, function(res, sts) {
if (sts == 'OK')
directionsDisplay2.setDirections(res);
});
}
$(function() {
$('#save').click(
function() {
var w = [], wp;
var rleg = directionsDisplay.directions.routes[0].legs[0];
data.start = {
'lat' : rleg.start_location.lat(),
'lng' : rleg.start_location.lng()
};
data.end = {
'lat' : rleg.end_location.lat(),
'lng' : rleg.end_location.lng()
};
var wp = rleg.via_waypoints;
for ( var i = 0; i < wp.length; i++) {
w[i] = [ wp[i].lat(), wp[i].lng() ];
}
data.waypoints = w;
var str = JSON.stringify(data);
$.get(
'http://localhost:48080/GDirections/rest/directionsWS/save/'
+ str, function(data) {
});
alert('Trayecto Guardado.');
});
$('#render')
.click(
function() {
$.get(
'http://localhost:48080/GDirections/rest/directionsWS/render',
function(data) {
setroute(data);
});
});
});
</script>
Las variables declaradas para Google Maps deben contener información sobre el lugar de partida, el lugar de llegada y los puntos de interés en latitud y longitud. A continuación, se debe inicializar el mapa pasando el identificador («id») de dónde se mostrará, el nivel de zoom, el tipo de mapa y la ubicación central.
La función route de DirectionsService trazará una ruta desde el punto de partida hasta el de llegada, en el modo «driving» (conducción). Enviará una solicitud al servidor de Google y obtendrá el camino como resultado, representando la información visualmente. En la función de devolución de llamada (callback), si la respuesta es correcta (ok), se asigna a setdirections la función que dibujará el trayecto en Google Maps a través de directionsDisplay.
Al hacer clic en el botón «Guardar», la función save crea una cadena JSON y la envía para que sea almacenada en la variable del WebService.
Cuando el usuario arrastra el trayecto, se crea un nuevo punto de interés en el objeto, lo que modifica la matriz de puntos de interés.
Para actualizar dicha lista, se ha creado un bucle («loop») que almacena únicamente la latitud y la longitud de los puntos de interés. De este modo, la información LatLng del punto de interés se guarda en la propiedad «locations». Finalmente, el objeto data se convertirá en una cadena JSON mediante el método stringify.
El WebService DirectionsServices recibirá, a través del método save, la cadena JSON enviada como parámetro y almacenará la nueva información en el objeto gMapsJson.
Cuando el usuario haga clic en el botón Render, la función Javascript asociada solicitará al WebService un objeto de tipo cadena JSON para dibujar la ruta almacenada previamente.
La función Javascript setroute recibirá el objeto de tipo cadena JSON proveniente del servidor.
Será necesario crear un objeto que contenga los puntos de latitud y longitud de salida y llegada, así como los puntos de interés.
Con estos puntos, creamos un objeto con origen y destino y le indicamos al mapa que trace las rutas. Una vez mapeado este trayecto, es necesario mostrarlo mediante la llamada a setDirections dentro de la función de devolución de llamada (callback).
Conclusión
La API de Google Maps es muy sencilla de utilizar y se puede emplear para desarrollos dentro de un límite de accesos diarios. Puede consultar la documentación en línea: aquí.
Trabajar en conjunto con la API Google Directions permite enrutar trayectos, calcular rutas de antemano y dar estilo a los objetos que se dibujarán en el mapa. Es una excelente alternativa para el mercado latinoamericano e internacional. Cuenta con un conjunto de 1397 municipios brasileños en un servicio en línea, muchos de ellos actualizados con datos del año 2012.
Al tratarse de un servicio en línea, las actualizaciones de los mapas ya vienen incluidas.
Otra ventaja es que no se requiere almacenamiento local de los mapas.
Descarga del código fuente y bibliotecas: El código fuente se puede obtener aquí
Andre Meirelles de Rezende
Arquitecto de Software

