Área de trabajo

Para empezar usaremos el mismo área de trabajo que el capítulo 1 (Google Maps API V3 introducción y primeros pasos) y capítulo 2 (Marcadores, posicionar una imagen en el mapa). Luego iremos modificándolo conforme a lo que vayamos trabajando.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>test</title>
	<style>
	*{ margin: 0; padding: 0; }
	html, body, #map{
		width: 100%;
		height: 100%;
	}
	</style>
	<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&amp;language=es"></script>
	<script type="text/javascript" src="js/map.js"></script>
</head>
<body>
	<div id="map"></div>
</body>
</html>

Dentro del archivo map.js, es donde estaremos trabajando los ejemplos de javascript.

zIndex

Cuando se van creando los InfoWindow, el último creado se muestra sobre el anterior. Por lo regular una forma de evitarlo, es usando la misma instancia del objeto creado y así solo se puede visualizar uno. Pero si deseamos mostrar varios a la misma vez, entonces ¿cómo podemos hacer para seleccionar un InfoWindow y este se coloque encima de los anteriores?

Conforme a la clase de InfoWindow podemos ver en el área de eventos que solo están disponibles: closeclick, content_changed, domready, position_changed y zindex_changed. En ningún momento se mencionó el evento click y es el que necesitamos. Una solución es que cuando se seleccione algún elemento dentro del InfoWindow, este se pueda colocar encima de todos los demas (luego ampliaremos como trabajar HTML y CSS en el InfoWindow):

window.onload = function(){
	var options = {
		zoom: 14
		, center: new google.maps.LatLng(18.470338, -66.123503)
		, mapTypeId: google.maps.MapTypeId.ROADMAP
	};

	var map = new google.maps.Map(document.getElementById('map'), options);

	var n=1;
	var markers = [
		{
			'position':new google.maps.LatLng(18.470338, -66.123503)
			, 'info':'<div id="contentInfoWindow' + n++ + '" style="width: 300px; height: 300px; border: 1px solid #000;"></div>'
		},
		{
			'position':new google.maps.LatLng(18.464008, -66.117776)
			, 'info':'<div id="contentInfoWindow' + n++ + '" style="width: 300px; height: 300px; border: 1px solid #000;"></div>'
		},
		{
			'position':new google.maps.LatLng(18.470826, -66.136205)
			, 'info':'<div id="contentInfoWindow' + n++ + '" style="width: 300px; height: 300px; border: 1px solid #000;"></div>'
		}
	];

	n=1;
	for(var i in markers){
		marker = new google.maps.Marker({
			position: markers[i]['position']
			, map: map
		});
		popup = new google.maps.InfoWindow({
			content: markers[i]['info']
			, zIndex: n
		});
		popup.open(map, marker);
		(function(id, popup){
			google.maps.event.addListener(popup, 'domready', function(){
				google.maps.event.addDomListener(document.getElementById('contentInfoWindow' + id), 'click', function(){
					popup.setZIndex(n++);
				});
			})
		})(n++, popup);
	}
};

Si seleccionamos cualquier área dentro del elemento <div> que está en el contenido del InfoWindow, podemos ver que la burbuja que seleccionemos se coloca encima de todos los mencionados. Esto lo logramos:

  • Colocando primero en qué zIndex debe estar cuando se creen. Este paso es necesario para evitar sorpresas en el momento de seleccionar los elementos. Si no se coloca, el zIndex está indefinido y al seleccionar un elemento este se coloca por debajo de todos los elementos hasta que todos tengan definidos el zIndex
  • Una forma de hacer referencia a un valor en específico y no a la variable es encapsulando el valor. Esto lo hicimos creando una función anónima (con dos argumentos) entre paréntesis, luego colocamos otros parétesis y dentro de estos, los valores a usar (conforme a los argumento declarados en la función)
  • Como las peticiones son asincrónicas, debemos esperar que los elementos declarados en el InfoWindow se carguen por lo que debemos hacer uso del evento domready de la clase InfoWindow. Una vez cargados los elementos le indicamos que queremos usar el método addDomListener y usar el evento click, de esta forma podemos seleccionar el elemento que deseamos
  • Por último modificamos el valor del zIndex del InfoWindow que seleccionamos, con el método setZIndex indicando el último valor numérico que se encuentra en la variable n

HTML y CSS

Dentro del InfoWindow podemos colocar diferentes tipos de datos, por ejemplo HTML y modificarlo con CSS. Modificamos el archivo que contiene el área de trabajo a que quede:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>test</title>
	<style>
	*{ margin: 0; padding: 0; }
	html, body, #map{
		width: 100%;
		height: 100%;
	}
	img{ border: 0; }

	.contentMap{
		width: 630px;
		border: 1px solid #336699;
		max-height:415px;
		overflow:auto;
	}
	.contentImg{
		float: left;
		width: 300px;
		margin-right: 10px;
		text-align: center;
	}
	.contentImg a{
		color: #369;
		font-size: 12px;
	}
	.contentTxt{
		float: left;
		width: 300px;
	}
	.clear{ clear: both; }
	</style>
	<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&amp;language=es"></script>
	<script type="text/javascript" src="js/map.js"></script>
</head>
<body>
	<div id="map"></div>
</body>
</html>

En el archivo map.js colocamos:

window.onload = function(){
	var options = {
		zoom: 14
		, center: new google.maps.LatLng(18.470338, -66.123503)
		, mapTypeId: google.maps.MapTypeId.ROADMAP
	};

	var map = new google.maps.Map(document.getElementById('map'), options);

	var n=1;
	var markers = [
		{
			'position':new google.maps.LatLng(18.470338, -66.123503)
			, 'info':'<div id="contentInfoWindow' + n++ + '" class="contentMap">\
						<div class="contentImg">\
							<img src="http://www.maestrosdelweb.com/images/2011/04/SanJuan.jpg" title="San Juan Morro" />\
							Autor desconocido\
							<img src="http://www.maestrosdelweb.com/images/2011/04/SanJuan2.jpg" title="San Juan Morro" />\
							<a href="http:[email protected]/2134221308/">Tomada por blucolt</a>\
						</div>\
						<div class="contentTxt">\
						<h2>San Juan Morro</h2>\
							<p>\
								En la cima del Antiguo San Juan, encontrarás al Fuerte San Felipe del Morro,\
								más conocido como El Morro. Esta construcción perteneciente al siglo XVI, fue\
								hecha para proteger a la ciudad de los ataques por mar, siendo uno de los elementos\
								más representativos de la antigua ciudad. Probablemente haya sido el monumento más\
								famoso en los tiempos de las colonias españolas y ahora la fortaleza sobresale en una\
								isleta rocosa.\
							</p>\
						</div>\
						<div class="clear"></div>\
					</div>'
		},
		{
			'position':new google.maps.LatLng(18.464008, -66.117776)
			, 'info':'<div id="contentInfoWindow' + n++ + '" class="contentMap">\
						<div class="contentImg">\
							<img src="http://www.maestrosdelweb.com/images/2011/04/SanJuan3.jpg" title="San Juan Parque de las Palomas" />\
							<a href="http://www.flickr.com/photos/coltharp/2133445467/in/photostream/">Tomada por blucolt</a>\
							<img src="http://www.maestrosdelweb.com/images/2011/04/Sanjuan4.jpg" title="San Juan Parque de las Palomas" />\
							autor desconocido\
						</div>\
						<div class="contentTxt">\
						<h2>San Juan Parque de las Palomas</h2>\
							<p>\
								Sobre una de las murallas antiguas de la ciudad, con vista desde lo alto hacia el\
								Paseo de la Princesa, es el lugar perfecto para disfrutar de una vista espectacular\
								de la Bahía de San Juan, de la ciudad y de las montañas.\
							</p>\
						</div>\
						<div class="clear"></div>\
					</div>'
		},
		{
			'position':new google.maps.LatLng(18.470826, -66.136205)
			, 'info':'<div id="contentInfoWindow' + n++ + '" class="contentMap">\
						<div class="contentImg">\
							<img src="http://www.maestrosdelweb.com/images/2011/04/ToaBaja.jpg" title="Toa Baja Isla de Cabras" />\
							autor desconocido\
							<img src="http://www.maestrosdelweb.com/images/2011/04/ToaBaja2.jpg" title="Toa Baja Isla de Cabras" />\
							<a href="http://www.flickr.com/photos/arturodonate/2825560234/">Tomada por arturodonate</a>\
						</div>\
						<div class="contentTxt">\
						<h2>Toa Baja Isla de Cabras</h2>\
							<p>\
								Debido a su localización estratégica en la entrada de la bahía de San Juan, Isla de Cabras\
								proveía un punto estratégico para un fuego cruzado en conjunto con el Fuerte San Felipe del Morro\
								en el otro lado de la bahía, para así prevenir que navíos invasores entraran.\
							</p>\
						</div>\
						<div class="clear"></div>\
					</div>'
		}
	];

	n=1;
	for(var i in markers){
		marker = new google.maps.Marker({
			position: markers[i]['position']
			, map: map
			, zIndex: n
		});
		popup = new google.maps.InfoWindow({
			content: markers[i]['info']
			, zIndex: n
		});
		popup.open(map, marker);
		(function(id, popup){
			google.maps.event.addListener(popup, 'domready', function(){
				google.maps.event.addDomListener(document.getElementById('contentInfoWindow' + id), 'click', function(){
					popup.setZIndex(n++);
				});
			})
		})(n++, popup);
	}
};

Notas:

  • Es buena programación el separar los archivos, como por ejemplo el de CSS. Para este material estaremos trabajando el CSS y HTML junto, para facilitar la enseñanza
  • El tamaño del InfoWindow es una combinación del contenido, el estilo que le hayas dado y del tamaño del mapa. Si el tamaño del InfoWindow no cabe en el tamaño establecido para el mapa, el API va a reducirlo para que se acomode

Añadir video de Youtube

Las etiquetas object tienden a sobre-ponerse a las demás. Una forma de evitarlo es llamar la etiqueta object una vez el InfoWindow esté al frente de todos los demás. Modificamos primero el área de trabajo para trabajar las etiquetas con CSS y añadimos el API de youtube:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>test</title>
	<style>
	*{ margin: 0; padding: 0; }
	html, body, #map{
		width: 100%;
		height: 100%;
	}
	img{ border: 0; }

	.contentMap{
		width: 630px;
		border: 1px solid #336699;
		max-height:415px;
		overflow:auto;
	}
	.contentImg{
		float: left;
		width: 300px;
		margin-right: 10px;
		text-align: center;
	}
	.contentImg a{
		color: #369;
		font-size: 12px;
	}
	.contentTxt{
		float: left;
		width: 300px;
	}
	.clear{ clear: both; }
	.youtube{ cursor: pointer; }
	</style>
	<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&amp;language=es"></script>
	<script type="text/javascript" src="http://swfobject.googlecode.com/svn/trunk/swfobject/swfobject.js"></script>
	<script type="text/javascript" src="js/map.js"></script>
</head>
<body>
	<div id="map"></div>
</body>
</html>

Luego modificamos el archivo map.js:

window.onload = function(){
	var options = {
		zoom: 14
		, center: new google.maps.LatLng(18.470338, -66.123503)
		, mapTypeId: google.maps.MapTypeId.ROADMAP
	};

	var map = new google.maps.Map(document.getElementById('map'), options);

	var n=1;
	var markers = [
		{
			'position':new google.maps.LatLng(18.470338, -66.123503)
			, 'info':'<div id="contentInfoWindow' + n + '" class="contentMap">\
						<div class="contentImg">\
							<a id="zoom' + n + '" href="#">Zoom</a>\
							<img src="http://www.maestrosdelweb.com/images/2011/04/SanJuan.jpg" title="San Juan Morro" />\
							Autor desconocido\
							<img src="http://www.maestrosdelweb.com/images/2011/04/SanJuan2.jpg" title="San Juan Morro" />\
							<a href="http:[email protected]/2134221308/">Tomada por blucolt</a>\
						</div>\
						<div class="contentTxt">\
						<h2>San Juan Morro</h2>\
							<p>\
								En la cima del Antiguo San Juan, encontrarás al Fuerte San Felipe del Morro,\
								más conocido como El Morro. Esta construcción perteneciente al siglo XVI, fue\
								hecha para proteger a la ciudad de los ataques por mar, siendo uno de los elementos\
								más representativos de la antigua ciudad. Probablemente haya sido el monumento más\
								famoso en los tiempos de las colonias españolas y ahora la fortaleza sobresale en una\
								isleta rocosa.\
							</p>\
							<div id="youtube' + n++ + '" class="youtube"></div>\
						</div>\
						<div class="clear"></div>\
					</div>'
			, 'youtube':'xKiaeLhBhvk'
		}
		, {
			'position':new google.maps.LatLng(18.464008, -66.117776)
			, 'info':'<div id="contentInfoWindow' + n + '" class="contentMap">\
						<div class="contentImg">\
							<a id="zoom' + n + '" href="#">Zoom</a>\
							<img src="http://www.maestrosdelweb.com/images/2011/04/SanJuan3.jpg" title="San Juan Parque de las Palomas" />\
							<a href="http://www.flickr.com/photos/coltharp/2133445467/in/photostream/">Tomada por blucolt</a>\
							<img src="http://www.maestrosdelweb.com/images/2011/04/Sanjuan4.jpg" title="San Juan Parque de las Palomas" />\
							autor desconocido\
						</div>\
						<div class="contentTxt">\
						<h2>San Juan Parque de las Palomas</h2>\
							<p>\
								Sobre una de las murallas antiguas de la ciudad, con vista desde lo alto hacia el\
								Paseo de la Princesa, es el lugar perfecto para disfrutar de una vista espectacular\
								de la Bahía de San Juan, de la ciudad y de las montañas.\
							</p>\
							<div id="youtube' + n++ + '" class="youtube"></div>\
						</div>\
						<div class="clear"></div>\
					</div>'
			, 'youtube':'7NvCsS1Kt_s'
		}
		, {
			'position':new google.maps.LatLng(18.470826, -66.136205)
			, 'info':'<div id="contentInfoWindow' + n + '" class="contentMap">\
						<div class="contentImg">\
							<a id="zoom' + n + '" href="#">Zoom</a>\
							<img src="http://www.maestrosdelweb.com/images/2011/04/ToaBaja.jpg" title="Toa Baja Isla de Cabras" />\
							autor desconocido\
							<img src="http://www.maestrosdelweb.com/images/2011/04/ToaBaja2.jpg" title="Toa Baja Isla de Cabras" />\
							<a href="http://www.flickr.com/photos/arturodonate/2825560234/">Tomada por arturodonate</a>\
						</div>\
						<div class="contentTxt">\
						<h2>Toa Baja Isla de Cabras</h2>\
							<p>\
								Debido a su localización estratégica en la entrada de la bahía de San Juan, Isla de Cabras\
								proveía un punto estratégico para un fuego cruzado en conjunto con el Fuerte San Felipe del Morro\
								en el otro lado de la bahía, para así prevenir que navíos invasores entraran.\
							</p>\
							<div id="youtube' + n++ + '" class="youtube"></div>\
						</div>\
						<div class="clear"></div>\
					</div>'
			, 'youtube':'PZpF3FShJyc'
		}
	];

	n=1;
	var currentId;
	for(var i in markers){
		marker = new google.maps.Marker({
			position: markers[i]['position']
			, map: map
			, zIndex: n
		});
		popup = new google.maps.InfoWindow({
			content: markers[i]['info']
			, zIndex: n
		});
		popup.open(map, marker);
		(function(id, marker, popup, video){
			google.maps.event.addListener(popup, 'domready', function(){
				var a = document.getElementById('zoom' + id);
				a.onclick = function(){
					map.setMapTypeId(google.maps.MapTypeId.SATELLITE);
					map.setCenter(marker.getPosition());
					map.setZoom(16);
					return false;
				}

				var youtube = getImage(video, id);

				google.maps.event.addDomListener(youtube, 'click', function(){
					var object = document.createElement('object');
					object.id = 'player' + id;

					this.innerHTML = '';
					this.appendChild(object);

					// método de youtube
					swfobject.embedSWF(
						'http://www.youtube.com/v/' + video + '?f=user_uploads&app=youtube_gdata&rel=1&border=0&fs=1&autoplay=1',
						('player' + id), '300', '255', '9.0.0', false, 
						false, {allowfullscreen: 'true'});
				});

				google.maps.event.addDomListener(document.getElementById('contentInfoWindow' + id), 'click', function(){
					if(id != currentId){
						popup.setZIndex(n++);
						currentId = id;
					}
				});

				google.maps.event.addListener(popup, 'zindex_changed', function(){
					for(var ii in markers){
						if(currentId == (parseInt(ii) + 1)){
							getImage(markers[ii]['youtube'], (parseInt(ii) + 1));
						}
					}
				});

				currentId = id;
			});
		})(n++, marker, popup, markers[i]['youtube']);
	}
};

function getImage(video, id){
	var img = document.createElement('img');
	img.src = 'http://img.youtube.com/vi/' + video + '/0.jpg';
	img.width = '300';
	img.height = '255';

	var youtube = document.getElementById('youtube' + id);
	youtube.innerHTML = '';
	youtube.appendChild(img);

	return youtube;
}



¿Qué es lo que hace? Si pulsamos en la imagen de la derecha de cada InfoWindow se ejecuta el evento click del addDomListener que mira la etiqueta <div> que contiene el id youtube{n}, donde {n} puede ser uno de los tres elementos creados que tiene el contenido de youtube. Se crea la etiqueta object, se añade el video correspondiente y luego se añade la etiqueta object a la etiqueta que tiene el id youtube{n}.

Si queremos ver otra burbuja, seleccionamos la que deseamos y se ejecutan dos eventos, el que contiene el id contentInfoWindow{n}, este tiene todo el contenido del InfoWindow y el evento zindex_changed que verifica si hubo algún cambio en el zIndex del InfoWindow. Este último vuelve a colocar las imagenes en el elemento <div> con el id youtube{n} en aquel InfoWindow que no se encuentre alfrente.

También se añadió un enlace llamado Zoom. Lo que hace es cambiar el tipo de mapa, acercarlo más y centrar el mapa al marcador.

Añadir mapa

Podemos crear un mapa, en el InfoWindow, mostrándolo con más detalle. Modificamos el área de trabajo:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>test</title>
	<style>
	*{ margin: 0; padding: 0; }
	html, body, #map{
		width: 100%;
		height: 100%;
	}

	.contentMap{
		width: 400px;
		height: 400px;
		border: 1px solid #336699;
	}
	</style>
	<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&amp;language=es"></script>
	<script type="text/javascript" src="js/map.js"></script>
</head>
<body>
	<div id="map"></div>
</body>
</html>

El map.js lo modificamos así:

window.onload = function(){
    var options = {
        zoom: 14
        , center: new google.maps.LatLng(18.470338, -66.123503)
        , mapTypeId: google.maps.MapTypeId.ROADMAP
    };
 
    var map = new google.maps.Map(document.getElementById('map'), options);
 
    var n=1;
    var markers = [
        {
            'position':new google.maps.LatLng(18.470338, -66.123503)
            , 'info':'<div id="contentInfoWindow' + n++ + '" class="contentMap"></div>'
        },
        {
            'position':new google.maps.LatLng(18.464008, -66.117776)
            , 'info':'<div id="contentInfoWindow' + n++ + '" class="contentMap"></div>'
        },
        {
            'position':new google.maps.LatLng(18.470826, -66.136205)
            , 'info':'<div id="contentInfoWindow' + n++ + '" class="contentMap"></div>'
        }
    ];
 
    n=1;
    for(var i in markers){
        marker = new google.maps.Marker({
            position: markers[i]['position']
            , map: map
        });
        popup = new google.maps.InfoWindow({
            content: markers[i]['info']
            , zIndex: n
        });
        popup.open(map, marker);
        (function(id, popup, marker){
            google.maps.event.addListener(popup, 'domready', function(){
				var div = document.createElement('div');
				div.style.width = '100%';
				div.style.height = '100%';
				var root = document.getElementById('contentInfoWindow' + id);
				root.appendChild(div);

				var divOptions = {
					zoom: 17
					, center: marker.getPosition()
					, mapTypeId: google.maps.MapTypeId.HYBRID
					, disableDefaultUI: true
					, draggable: false
				};

				var divMap = new google.maps.Map(div, divOptions);
				var divMarker = new google.maps.Marker({
					position: marker.getPosition()
					, map: divMap
					, clickable: false
				});

                google.maps.event.addDomListener(root, 'click', function(){
                    popup.setZIndex(n++);
                });
            })
        })(n++, popup, marker);
    }
};