Mapa de Google señalando varios puntos mediante jQuery y/o Prototype

Hace unos días que estoy para escribir este artículo pero por una cosa u otra se me queda en el tintero. Pero de hoy no pasa así que aquí va.

A raiz de intentar incluir el módulo GMap de Drupal, en un proyecto reciente, me vi en la necesidad de generar una nueva clave para incluir un mapa de google. Cual fué mi sorpresa al ver que esto ya no era posible desde la publicación de la versión 3 de la API de Google Maps. Tras dar alguna que otra vuelta por la documentación de esta conseguí crear el ejemplo básico de un mapa de Google usando API v3  ( lo cierto es que es bastante sencillo de crear y nos evitan el tener que crear la clave para cada dominio donde alojemos el mapa).

Pero me quedó el gusanillo de poder tener un mapa con varios puntos así que me puse a ello: teniendo un documento XML con los puntos y sus localizaciones:

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<!-- http://geoco.org/espana-es.html -->
<puntos>
	<punto>
		<titulo><![CDATA[Santander]]></titulo>
		<desc><![CDATA[Santander, home sweet home]]></desc>
		<url>http://www.ayto-santander.es</url>
		<latitud>43.464</latitud>
		<longitud>-3.8</longitud>
	</punto>	
	<punto>
		<titulo><![CDATA[Barcelona]]></titulo>
		<desc><![CDATA[Barcelona, capital de Cataluña]]></desc>
		<url>http://www.bcn.es/</url>
		<latitud>41.38</latitud>
		<longitud>2.18</longitud>
	</punto>	
	<punto>
		<titulo><![CDATA[Mérida]]></titulo>
		<desc><![CDATA[Cuidad monumental y arqueológica]]></desc>
		<url>http://www.merida.es/</url>
		<latitud>38.92</latitud>
		<longitud>-6.33</longitud>
	</punto>		
</puntos>

los cargaría con javascript ( la primera opción, no os mentiré, fue hacerlo con Prototype -porque tenía un ejemplo de lectura de un XML hecho con él, y luego con jQuery) y los mostraría en un sencillo documento HTML.

Carga de los datos con Prototype.

Si véis el contenido del fichero javascrpipt que realiza el proceso, xml.js , veréis algo como esto:

function obtenerPuntos( )
{
	var url = 'js/puntos.xml';
	var myAjax = new Ajax.Request( url, { method: 'get', onComplete: renderResultsPuntos });
}

Que no es otra cosa que la lectura del fichero XML, con los datos, mediante Ajax y la asignación de esta lectura al objeto myAjax que se utiliza en la función que pinta el mapa, renderResultsPuntos().

function renderResultsPuntos(responseXMLSec)
{
	var myZona = new Array();
	var marker = new Array();
	var contentString = new Array();
	var infowindow = new Array();
	var xml  = responseXMLSec.responseXML.documentElement;
	var miDiv = document.getElementById('puntos-place'); 
	
	var ptoMadrid = new google.maps.LatLng(40, -3.5); // Centramos el mapa en Madrid.
	var myOptions = {
		zoom: 6,
		center: ptoMadrid,
		mapTypeId: google.maps.MapTypeId.ROADMAP
	}
	var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	for (i = 0; i < xml.getElementsByTagName('punto').length; i++)
	{
		var item = xml.getElementsByTagName('punto')[i]; // Accedemos al objeto XML seccion
		var urlDir = item.getElementsByTagName('url')[0].firstChild.data;
		var titulo = item.getElementsByTagName('titulo')[0].firstChild.data;
		var texto = limpiaStr(item.getElementsByTagName('desc')[0].firstChild.data);
		
		myZona[i] = new google.maps.LatLng(
item.getElementsByTagName('latitud')[0].firstChild.data,
item.getElementsByTagName('longitud')[0].firstChild.data); 
		contentString[i] = '<div class="google-content">'+
			'<h2>' + titulo + '</h2>'+
			'<div class="bodyContent">'+
			'<p>' +  texto + '</p>'+
			'<p>URL: <a href="'+urlDir+'">' +  urlDir + '</a></p>'+
			'</div>'+
			'</div>';
		infowindow[i] = new google.maps.InfoWindow({ content: contentString[i] });
		marker[i] = new google.maps.Marker({ position: myZona[i], map: map, title: titulo });
		eval ( "google.maps.event.addListener( marker[" + i + "], 'click', function() { infowindow["+i+"].open( map, marker["+i+"] ); })");
	}
}

Con lo que la creación de un mapa de Goole con Prototype queda completa.

Carga de los datos con jQuery.

En el caso de crear el mapa de Google con jQuery, ejecutamos el proceso dentro de la función, pintaMapa(), que realiza la petición Ajax al fichero de datos y, cuando esta se haya completado, pinta el mapa, ver fichero jquery.xml.

var myZona = new Array();
var marker = new Array();
var contentString = new Array();
var infowindow = new Array();

$(document).ready(function() {  
	pintaMapa("map_canvas");
});

// general options for all ajax request
$.ajaxSetup({
	type: "GET",
	statusCode: {
		404: function() {
			alert("page not found");
		},
		500: function() { 
			alert("Server error");
		}
	}
});
function pintaMapa(destID) {
	
	if ( $('#' + destID).length = 0 ) { return;}
	$.ajax({
		dataType: 'text html',
		url: 'js/puntos.xml'
	})
	.done(function(data){
		xmlDoc = $.parseXML( data );
		$xml = $( xmlDoc );
		$puntos = $xml.find( "punto" );
		if  ( $puntos.length > 0 ) {
			var ptoCentro = new google.maps.LatLng(40, -3.5); // Madrid, aprox!!!
			var myOptions = {
				zoom: 6,
				center: ptoCentro,
				mapTypeId: google.maps.MapTypeId.ROADMAP
			}
			var map = new google.maps.Map(document.getElementById(destID), myOptions);
			var i = 0;
			$.each ( $puntos, function() {
				var titulo = $(this).find("titulo").text();
				var url = $(this).find("url").text();
				myZona[i] = new google.maps.LatLng($(this).find("latitud").text(), $(this).find("longitud").text()); 
				contentString[i] = '<div class="google-content">'+
					'<h2>' + titulo + '</h2>'+
					'<div class="bodyContent">'+
					'<p>' +  $(this).find("desc").text() + '</p>'+
					'<p>URL: <a href="'+url+'">' +  url + '</a></p>'+
					'</div>'+
					'</div>';
				infowindow[i] = new google.maps.InfoWindow({ content: contentString[i] });
				marker[i] = new google.maps.Marker({ position: myZona[i], map: map, title: titulo });
				eval ( "google.maps.event.addListener( marker[" + i + "], 'click', function() { infowindow["+i+"].open( map, marker["+i+"] ); })");
				i++;
			});
		}
	});
}

Una de las diferencias entre generar el mapa con Prototype o con jQuery es que en este segundo caso las variables donde se almacenan los puntos deben ser globales a todos el script. Antes de acabar deciros que  seguro que el codigo fuente es muy mejorable pero por lo menos funciona.