Programación Web. Integración con APIs

Sesión 5. Google Maps

Google Maps es el nombre de un servicio gratuito de Google. Es un servidor de aplicaciones de mapas en Web. Ofrece imágenes de mapas desplazables, así como fotos por satélite del mundo entero e incluso la ruta entre diferentes ubicaciones. Google Maps posee una API abierta y documentada que podemos encontrar en: https://developers.google.com/maps/documentation/javascript/?hl=es

En este curso vamos a estudiar la última versión de la API de GoogleMaps, la versión v3, que difiere en gran medida con la anterior versión v2. Como en la red la versión v2 sigue teniendo una importante cuota de uso, recordad que si se desea estudiar esta versión (la v2) en los materiales del curso de años anteriores se dispone de toda la documentación necesaria.

La versión v3 del API de JavaScript de Google Maps es un servicio gratuito disponible para cualquier sitio web que, a su vez, sea gratuito para el consumidor.

Conceptos previos

Antes de empezar a trabajar con GoogleMaps, vamos a estudiar las funciones closure en Javascript, debido a su comportamiento particular con respecto a las funciones en otros lenguajes de programación y teniendo en cuenta el uso que vamos a hacer de ellas al trabajar en GoogleMaps.

Las funciones closure son funciones declaradas dentro de otra función. Tienen como particularidad que pueden utilizar las variables de la función padre como si estuvieran declaradas dentro de la misma (se saltan el ámbito local de la función). Al finalizar la función padre, la variables de esta que se haya tomado en la función closure no son recolectadas si la función está referenciada en alguna parte del código.

En el siguiente fragmento de código podemos ver como la variable variableFuncionPrincipal puede ser llamada dentro de una función con ámbito menor functionClosure de manera que si devolvemos un puntero de la función funcionClosure al volverla a llamar no se recolecta la variable variableFuncionPrincipal.

<html>
   <head>
      <script>
         function funcionPrincipal() {
            // esta varible no deberia ser accesible por otras funciones
            var varibleFuncionPrincipal =
               "[VALOR DE UNA VARIALBE DE FUNCION PRINCIPAL]";

            var funcionClosure = function() {
               // al ser un closure podemos acceder a variables de la funcion padre;
               alert("Accedemos a una variable de la funcion principal "
                  + varibleFuncionPrincipal);
            }
            // al devolver un puntero de la funcion padre,
            // el closure tiene una referencia a la variable
            // variableFuncionPrincipal a si que no se recolecta.
            return funcionClosure;
         }
         //llamamos a la funcion principal y recogemos la
         //referencia a la funcion closure
         var funcionClosure = funcionPrincipal();
         //por ultimo realizamos la llamada.
         funcionClosure();
      </script>
   </head>
</html>

Otro uso muy interesante de las funciones closure es la posibilidad de guardar el estado interno de algo. Podemos ver un ejemplo:

var crearContador = function() {
  var contador, f;
  contador = 0;
  f = function () {
    contador += 1;
    return contador;
  };
  return f;
};
var contador = crearContador();
/* contador es una función que no recibe argumentos y devuelve una cuenta */

var a = contador(); // a = 1
var b = contador(); // b = 2
var c = contador(); // c = 3

var contador2 = crearContador(); //crea otro contador más
var d = contador2(); // d = 1
var e = contador2(); // e = 2;
var f = contador();  // f = 4, por usar el primer contador

Este ejemplo nos da una idea de cómo los datos son tratados de forma privada dentro del closure. En la función crearContador el único código que tiene acceso a la variable contador es el de la función interna. Así, esta variable contador permanece privada e inaccesible desde cualquier otro lugar del código.

Clave de API de Google

Recientemente Google ha creado un sistema de autentificación para desarrolladores de sus distintas APIs. La generación de estas claves es, en principio, gratuita. Aunque también existe una versión de pago con opciones adicionales. Utilizar una clave de API te permite controlar cómo utiliza tu aplicación el API de Google Maps y asegurarte de que Google puede ponerse en contacto contigo con respecto a tu aplicación si fuese necesario.

Para generar una clave para el API de Google Maps deberemos realizar los siguientes pasos:

  • Paso 1. Accede a la página de la consola de las API (https://console.developers.google.com) e inicia sesión con tu cuenta de Google.

  • Paso 2. Creamos un nuevo proyecto y le damos un nombre, por ejemplo, UAZonMap-[nombrealumno]

Nuevo proyecto

  • Paso 3. Hacemos click en la opción APIs del apartado APIs y autentificación del menú de la izquierda. Pinchamos sobre el enlace a Google Maps JavaScript API v3 y después en el botón Habilitar API

  • Paso 4. A continuación vamos al menú Credenciales y hacemos click en el botón Crear clave nueva en la sección correspondiente a Acceso a clave pública que podemos encontrar en la parte inferior de la ventana.

  • Paso 5. Nos aparecerá un cuadro de diálogo como el que se muestra en la siguiente Figura en la que se nos pregunta para qué vamos a utilizar la clave. En nuestro caso haremos click en la opción Clave de navegador.

Nueva clave

  • Paso 6. En la siguiente pantalla podremos indicar las restricciones de los dominios desde los que se puede utilizar esta clave. Esto nos asegura que nuestra aplicación no va a ser ejecutada en dominios distintos a los que nosotros queramos, elevando así la seguridad. Si dejamos este campo vacío la clave podrá ser utilizada desde cualquier sitio. Si más adelante queremos modificar o añadir más restricciones podremos hacerlo desde el botón Editar referencias permitidas

Referencias

En el menú Credenciales tendremos ya disponible el ID de la clave que acabamos de crear y que será el que utilicemos en los diferentes ejemplos y ejercicios de este capítulo.

Creando nuestro primer mapa

Lo primero que debemos hacer es incluir el servicio de GoogleMaps en nuestro proyecto, al ser un servicio online no es necesario descargarlo de ningún site, basta con incluir la siguiente línea dentro de la cabecera de nuestras páginas cambiando donde aparece YOUR_API_KEY en el siguiente ejemplo por nuestra clave google:

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

Si estamos haciendo uso del protocolo SSL para proteger el contenido de los datos de los usuarios de nuestra web, el código anterior provocará advertencias de seguridad en los navegadores. En este caso, deberemos cargar la API segura de Google Maps mediante el protocolo HTTPS:

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

La variable sensor hace mención a la posible auto-detección del sitio, esto es común en teléfonos móviles ( y GoogleMaps está preparado para ellos) pero como nosotros nos centraremos en el desarrollo para navegadores de escritorio siempre dejaremos esta variable a false. Una vez hemos cargado GoogleMaps en nuestra web, para poder ver una mapa en ella solamente tenemos que crear un elemento <div> (que será donde irá el mapa) y asignarle el mapa de la siguiente forma:

var mapa = new google.maps.Map(document.getElementById("mapa"));

Por último debemos establecer la posición del mapa (si se encuentra en Alicante o Madrid), el nivel de zoom y el tipo de mapa:

var miPosicion = new google.maps.LatLng(38.34, -0.48)
mapa.setCenter(miPosicion); mapa.setZoom(10);
mapa.setMapTypeId(google.maps.MapTypeId.ROADMAP);

El nivel de zoom empieza en 0, el nivel más alejado en el que tendremos una vista de todo el mapa de la tierra, y se irá incrementando para irnos acercando al punto visualizado.

Como se puede observar, utilizamos los métodos setCenter, setZoom y setMapTypeId para establecer los parámetros del mapa. Esto también es posible realizarlo mediante un objeto mapOptions inicianizándolo de la siguiente manera y pasándoselo al constructor del mapa:

var mapOptions = {
  center: new google.maps.LatLng(38.34, -0.48),
  zoom: 10,
  mapTypeId: google.maps.MapTypeId.ROADMAP
};
var mapa = new google.maps.Map(document.getElementById("mapa"), mapOptions);

En la siguiente imagen se muestra nuestro mapa. Recordad que podéis visitar la API de googleMaps v3 si queréis ver las diferentes opciones (pj: los tipos de mapa existentes, en el ejemplo ponemos el callejero ROADMAP, pero se puede usar el satelite SATELLITE). En este apartado de la API tenéis la información mas común https://developers.google.com/maps/documentation/javascript/maptypes?hl=es.

Ejemplo de mapa de Google Maps

El código completo de una página simple que utilice el API de Google Maps para cargar un mapa centrado en Alicante podría ser el siguiente, recordando cambiar YOUR_API_KEY por la clave de Google APIs que hemos tratado antes.

<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <script src="http://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=false" type="text/javascript"></script>
  </head>

  <body>
    <div id="mapa" style="width: 550px; height: 450px"></div>
    <script type="text/javascript">
      var mapOptions = {
        center: new google.maps.LatLng(38.34, -0.48),
        zoom: 10,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      };
      var mapa = new google.maps.Map(document.getElementById("mapa"), mapOptions);
    </script>
  </body>
</html>

Obteniendo coordenadas

Como se ha podido ver en el ejemplo de nuestro primer mapa, a la hora de posicionarse en un él es necesario conocer las coordenadas del lugar, tanto longitud como latitud. Normalmente sabremos la dirección de un lugar (pj: Castellana 1, Madrid, España) pero desconoceremos las coordenadas.

Para transformar una dirección escrita en coordenadas, googleMaps posee la clase Geocoder. Si hacemos una llamada a esta clase pasando una dirección, con una función callback nos devuelve las coordenadas. Esto lo haremos de la siguiente forma:

var direccion = "Alicante, España";
geocoder.geocode( { 'address': direccion}, function(results, status) {
   if (status == google.maps.GeocoderStatus.OK) {
      alert("los valores de latitud y longitud son: "
         +results[0].geometry.location);
   } else {
      alert(direccion + " no encontrado, error:"+ status);
   }
});

Como se puede ver, a partir de la dirección “Alicante, España”, GoogleMaps nos ha devuelto las coordenadas de la ciudad. Podemos hacer un pequeño ejemplo con un formulario, de tal forma que podamos escribir una dirección mundial cualquiera y GoogleMaps nos devuelva las coordenadas:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html;
         charset=ISO-8859-1">
      <title>Ejemplo para calcular longitud y latitud</title>
      <script src="http://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=false" type="text/javascript"></script>
   </head>
   <body>
      <script>
         function verDireccion()
         {
            geocoder = new google.maps.Geocoder();
            //recatamos la direccion
            direccion= document.getElementById("dir").value;
            verLongitudyLatitud(direccion);
            return false;
         }

         function verLongitudyLatitud(direccion)
         {
            //llamamos al metodo geocode con la dirección
            //pasada por parametro
            geocoder.geocode( { 'address': direccion},
               function(results, status) {
               if (status == google.maps.GeocoderStatus.OK) {
                  alert("los valores de latitud y longitud son: "
                     +results[0].geometry.location);
               } else {
                  alert(direccion + " no encontrado, error:"+ status);
               }
            });
         }
      </script>
      <form onSubmit="return verDireccion();">
         Escribir la direccion
         <input id="dir" type="text" value="" />
         <input type="submit" value="buscar"/>
      </form>
   </body>
</html>

Ejemplo formulario y Google Maps

Poniendo marcadores en nuestros mapas

Es útil marcar sitios de interés dentro de un mapa. GoogleMaps posee la clase Marker que crea estos “puntos/marcadores”. Para crear un marcador debemos escribir el siguiente código (recordad que la variable posicion es de tipo LatitudLongitud -mirad como lo creamos en el primer ejemplo- y mapa es nuestro mapa).

var punto = new google.maps.Marker({position:posicion,map:mapa});

Cuando creamos un punto, podemos asociar acciones al mismo, por ejemplo el evento click nos mostrará un texto aclarativo. En el siguiente ejemplo, primero creamos una ventana de información “infoWindow” donde podemos escribir tanto texto plano como Html. Después asociamos mostrar la ventana informativa al evento “click” sobre el marcador.

var infoWin = new google.maps.InfoWindow({content: 'Alicante'});
google.maps.event.addListener(punto, 'click',
function() {infoWin.open(mapa,punto);});

En el siguiente ejemplo ponemos un marcador en Alicante y una ventana informativa que se mostrará al pinchar sobre el marcador con el texto “Esta es la ciudad de Alicante”:

<html>
   <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
      <title>Segundo Ejemplo Google Maps</title>
      <script src="http://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=false" type="text/javascript"></script>
   </head>
   <body>
      <div id="mapa" style="width: 550px; height: 450px"></div>
      <script type="text/javascript">
         // Mostramos el Mapa
         //creamos un mapa y lo asociamos al div 'mapa'
         var mapa = new google.maps.Map(document.getElementById("mapa"));
         //coordenadas, en este caso Alicante
         var miPosicion = new google.maps.LatLng(38.346041, -0.484756);
         mapa.setCenter(miPosicion);
         mapa.setZoom(10); //zoom
         mapa.setMapTypeId(google.maps.MapTypeId.ROADMAP); //poner el tipo
         //Creamos un punto:
         var posicion = new google.maps.LatLng(38.346041, -0.484756);
         var punto = new google.maps.Marker(
            {position:posicion,map:mapa,title:'Alicante'});
         //Informacion del marcador
         var infoWin = new google.maps.InfoWindow(
            {content: 'Es la ciudad de <b>Alicante</b>'});
         //Asociar el infoWin al click sobre el marcador
         google.maps.event.addListener(punto, 'click', function() {
            infoWin.open(mapa,punto);
         });
      </script>
   </body>
</html>

Ejemplo marcador en Google Maps

Podemos completar el ejemplo anterior con dos mejoras importantes. Por un lado vamos a dotar a nuestros marcadores de iconos propios, para ello solo debemos utilizar la opción “icon” al crear nuestros marcadores:

new google.maps.Marker({position:posicion,map:mapa,icon:'ico.jpg'});

Después, haciendo uso de la clase geocode, insertaremos varios marcadores indicando solamente la dirección de los mismos. Para ello utilizaremos dos funciones, una primera llamada ponerPunto que recogerá la dirección del punto que queremos crear y obtendrá las coordenadas. Ya con las coordenadas llamará a la función crearPunto que creará los puntos en el lugar indicado y además les asignará una ventana informativa donde se lea la dirección (escrita) del punto. El código resultante sería el siguiente:

<html>
   <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
      <title>Ejemplo Google Maps 4</title>
      <script src="http://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=false" type="text/javascript"></script>
   </head>
   <body>
      <div id="mapa" style="width: 550px; height: 450px"></div>
      <script type="text/javascript">
         function ponerPunto(direccion)
         {
            geocoder.geocode( { 'address': direccion},
               function(results, status) {
               if (status == google.maps.GeocoderStatus.OK) {
                  //creamos el marcador y pasamos informacion del mismo
                  crearPunto(results[0].geometry.location,direccion);
               } else {
                  alert(direccion + " no encontrado, error:"+ status);
               }
            });
         }

         function crearPunto(posicion,info)
         {
            //Creamos un punto:
            var punto = new google.maps.Marker(
               {position:posicion,map:mapa,icon:'ico.jpg'});
            //Informacion del marcador
            var infoWin = new google.maps.InfoWindow({content: 'direccion: '+info});
            //Asociar el infoWin al click sobre el marcador
            google.maps.event.addListener(punto, 'click', function() {
               infoWin.open(mapa,punto);
            });
         }

         //creamos un mapa y lo asociamos al div 'mapa'
         var mapa = new google.maps.Map(document.getElementById("mapa"));
         //coordenadas, en este caso Alicante
         var miPosicion = new google.maps.LatLng(38.346041, -0.484756);
         mapa.setCenter(miPosicion);
         //zoom
         mapa.setZoom(10);
         //poner el tipo ROADMAP, SATELLITE ...
         mapa.setMapTypeId(google.maps.MapTypeId.ROADMAP);
         var geocoder = new google.maps.Geocoder();
         //añadimos los nuevos puntos
         ponerPunto("alicante, españa");
         ponerPunto("elche, españa");
         ponerPunto("santa pola, españa");
      </script>
   </body>
</html>

Ejemplo marcador usando icono propio en Google Maps

GoogleMaps y Ajax

            Hasta ahora hemos visto como ir posicionando puntos que escribíamos
            directamente en el código de cliente (Javascript). Esta solución es
            correcta a la hora de mostrar la localización de un punto en concreto
            (pj: en una web de presentación la localización de la empresa). Pero
            para poder utilizar el potencial de GoogleMaps vamos a necesitar
            cargar datos desde nuestro servidor mediante AJAX. Un ejemplo claro de
            esto sería mostrar en un mapa la posición (mediante marcadores) de los
            usuarios de una web.



            Nos vamos a ayudar del formato XML y las llamadas AJAX para crear
            dinámicamente los
            puntos que recibamos de un fichero XML externo. Utilizaremos la librería
            jQuery para realizar la petición AJAX y leer el XML respectivamente.
            Recordad que aunque en este ejemplo se lea un fichero XML ya creado,
            desde PHP podemos generar ficheros XML dinámicos con la información de
            nuestra base de datos.

Nuestro fichero XML contendrá la siguiente información:

<?xml version="1.0" encoding="utf-8"?>
<puntos>
   <puntos direccion="Alicante, España"/>
   <puntos direccion="Benidorm, España"/>
   <puntos direccion="Elche, España"/>
</puntos>
            Ahora modificaremos el código del anterior ejemplo (en el que se
            generaban marcadores a partir de direcciones) para leer la información
            de forma remota mediante AJAX. El resultado es el siguiente:
<html>
   <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
      <title>Ejemplo Google Maps 4</title>
      <script src="http://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=false" type="text/javascript"></script>
      <script src="jquery.js" type="text/javascript"></script>
   </head>
   <body>
      <div id="mapa" style="width: 550px; height: 450px"></div>
      <script type="text/javascript">
          function ponerPunto(direccion)
         {
            geocoder.geocode( { 'address': direccion},
               function(results, status) {
               if (status == google.maps.GeocoderStatus.OK) {
                  //creamos el marcador y pasamos informacion del mismo
                  crearPunto(results[0].geometry.location,direccion);
               } else {
                  alert(direccion + " no encontrado, error:"+ status);
               }
            });
         }

         function crearPunto(posicion,info)
         {
            //Creamos un punto:
            var punto = new google.maps.Marker(
               {position:posicion,map:mapa,icon:'ico.jpg'});
            //Informacion del marcador
            var infoWin = new google.maps.InfoWindow({content:
               'direccion: '+info});
            //Asociar el infoWin al click sobre el marcador
            google.maps.event.addListener(punto, 'click', function() {
               infoWin.open(mapa,punto);
            });
         }

         function leerPuntos(response)
         {
            puntos = response.getElementsByTagName("puntos");

            for(var i=0; i < puntos.length; i++)
            {
               if(puntos[i].getAttribute("direccion") != null){
                  direccion = puntos[i].getAttribute("direccion");
                  ponerPunto(direccion);
               }
            }
         }

         //creamos un mapa y lo asociamos al div 'mapa'
         var mapa = new google.maps.Map(document.getElementById("mapa"));
         //coordenadas, en este caso Alicante
         var miPosicion = new google.maps.LatLng(38.346041, -0.484756);
         mapa.setCenter(miPosicion);
         //zoom
         mapa.setZoom(10);
         //poner el tipo ROADMAP, SATELLITE ...
         mapa.setMapTypeId(google.maps.MapTypeId.ROADMAP);
         var geocoder = new google.maps.Geocoder();

         // Leer del XML los puntos a mostrar
         $.get("puntos.xml",null,leerPuntos);
      </script>
   </body>
</html>

Ejercicios Sesión 5

Normas de entrega

Es fundamental para poder corregir los ejercicios de esta sesión que estén disponibles online ya que su funcionamiento depende de ello al estar integrados con Google+. Por este motivo cada alumno subirá sus ejercicios a http://proyectos.proweb.ua.es/[siglas-del-alumno]/apisweb2/sesion6

En este directorio el alumno incluirá un fichero index.html con una estructura similar a lo que se muestra en el siguiente ejemplo:

<ul>
<li><a href='s6_eje1/index.html' target='_blank'>Ejercicio 1: – Social
Plugin: Button +1 </a></li>
...

Ejercicio 1. Integrar el ejemplo de comunicación de GoogleMaps con base de datos en el proyecto (Uazon).

Partiendo el ejemplo visto en clase, debemos integrar los códigos en nuestro proyecto uazon. El objetivo del ejercicio es crear una sección mapa usuarios donde se muestre un mapa con la localización de los usuarios registrados en Uazon.

Enlazar en el index.html de la entrega, la sección mapa usuarios para poder acceder directamente.

Ejercicio 2. Ampliar el primer ejercicio, diferenciando los usuarios activos de los demás (Uazon) (Optativo)

Aprovechando el ejercicio hecho en sesiones anteriores que mostraba el numero de usuarios activos en el portal, añadir un icono especial a los usuarios que están activos a la hora de integrar nuestro mapa de Google Maps en el proyecto.