Jugando con AngularJS y Google Maps

9
33406

Jugando con AngularJS y Google Maps.

0. Índice de contenidos.


1. Introducción

Ya tuvimos la ocasión de hablar de AngularJS en anteriores tutoriales. Pese a ser un framework relativamente joven, el impacto que ha tenido en la comunidad de desarrollo web ha sido tremendo hasta el punto de que, a día de hoy, es probablemente uno de los temas que más interesan a los desarrolladores.

El API de Google para mapas es algo más veterano que Angular pero siempre es un recurso muy recurrido en determinados tipos de aplicativos. Con el API de Geolocalización de HTML5 o los dispositivos móviles sus posibilidades son incluso mayores.

En este tutorial aprenderemos a crear y manipular mapas de una manera muy sencilla en nuestros desarrollos web basados en AngularJS gracias a la librería de directivas angular-google-maps.


2. Entorno.

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2.2 Ghz Intel Core I7, 8GB DDR3).
  • Sistema Operativo: Mac OS X Mavericks 10.9
  • NetBeans IDE 8.0
  • AngularJS 1.2.26
  • angular-google-maps 1.2.2
  • Google Chrome 37
  • Mozilla Firefox 32
  • Opera Browser 12.16
  • Safari Browser 7

3. Angular Google Maps.

Angular Google Maps es una excelente librería de directivas AngularJS que nos permite integrar de una manera relativamente sencilla Google Maps en nuestros desarrollos AngularJS.

Aunque no es la única librería de este tipo, probablemente si que sea la que nos ofrezca una mayor funcionalidad a la hora de tratar los mapas. Será la librería que utilizaremos en este tutorial.

4. Configuración.

Existen dos formas de configurar nuestro proyecto: de manera manual o automática haciendo uso de bower. En nuestro caso lo haremos de forma manual.

Para ello, en la raíz de nuestro proyecto crearemos un directorio js/ y en su interior un subdirectorio lib/ donde meteremos las librerías que necesitará nuestro proyecto. Son las siguientes:

Además, necesitaremos hacer uso del API Javascript para Google Maps.

Por último, crearemos en el directorio js/ un fichero map.js donde crearemos nuestro módulo para controlar el mapa (AngularJS) y, a la altura del directorio js/, un fichero index.html.

Project Structure

Para poder empezar a trabajar, nuestro fichero index.html quedaría así:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>AngularJS / Google Maps Tutorial

        <!-- AngularJS -->
        <script src="js/lib/angularjs.min.js?v=1.2.26"></script>

        <!-- Google Maps Javascript API -->
        <script src="http://maps.google.com/maps/api/js?sensor=false"></script>

        <!-- angular-google-maps -->
        <script src="js/lib/lodash.underscore.min.js?v=2.4.1"></script>
        <script src="js/lib/angular-google-maps.min.js?v=1.2.2"></script>

        <!-- Custom angular module -->
        <script src="js/map.js?v=1.0"></script>
    </head>
    <body>
        
    </body>
</html>

5. Creando nuestro mapa.

Una vez que ya tenemos todo lo necesario para empezar a trabajar, vamos a crear un sencillo mapa. Nuestro mapa tendrá un único marker (un marcador en un punto de coordenadas concreto del mapa), un zoom por defecto y estará centrado en las coordenadas de dicho marker.

Para ello creamos en nuestra vista (fichero .html) el mapa gracias a la directiva: google-map y añadimos en su interior el marcador mediante marker.

<!DOCTYPE html>
<html ng-app="AngularGoogleMap" >
    <head>
        <meta charset="utf-8"/>
        <title>AngularJS / Google Maps Tutorial</title>
        <!-- AngularJS -->
        <script src="js/lib/angularjs.min.js?v=1.2.26"></script>

        <!-- Google Maps -->
        <script src="http://maps.google.com/maps/api/js?sensor=false"></script>

        <!-- angular-google-maps -->
        <script src="js/lib/lodash.underscore.min.js?v=2.4.1"></script>
        <script src="js/lib/angular-google-maps.min.js?v=1.2.2"></script>

        <!-- Custom angular module -->
        <script src="js/map-module.js"></script>
        <style>
            .angular-google-map-container {
                position: absolute;
                top: 0;
                bottom: 0;
                right: 0;
                left: 0;    
            }
        </style>
    </head>
    <body ng-controller="MapCtrl">
    <google-map center="map.center" 
    			zoom="map.zoom" 
    			draggable="true" 
    			options="map.options" 
    			control="map.control">
		<marker coords="marker.coords" options="marker.options" idkey="marker.id" ></marker>        
    </google-map>
</body>
</html>

Como podemos observar en las líneas 29 y 34, hemos añadido un elemento google-map que contiene otro elemento marker, que no son más que directivas de la librería angular-google-maps que hemos añadido en la línea 14.

Dentro de la directiva google-map destacamos las siguientes propiedades:

  • center: expresión que, al ser evaluada, debe tomar el valor de un objeto con las propiedades: «latitude» y «longitude», que representarán las coordenadas del centro de nuestro mapa.
  • zoom: valor o expresión que indicará el nivel de zoom de nuestro mapa. Debe ser un número entre 1 y 20.
  • dragable: booleano que indicará si podemos arrastrar el mapa.
  • options: expresión que, al ser evaluada, tomará el valor de un objeto con propiedades adicionales del mapa. Se corresponden con las que ofrece el API de Google.
  • control: propiedad que vincularemos a un objeto en nuestro controlador (vía $scope) y que nos proporcionará métodos de utilidades como obtener una instancia del mapa o refrescarlo.

Y en la directiva marker observamos estas propiedades:

  • coords: expresión que deberá resolverse del mismo modo que la propiedad center (latitud y longitud) que vimos anteriormente y que indicará las coordenadas donde se posicione nuestro marcador.
  • idkey: identificador único que tendrá nuestro marcador.
  • options: expresión que, al ser evaluada, devolverá opciones adicionales que proporcionaremos a nuestro marcador.

Ya tenemos todo lo que necesitamos en nuestra vista. Ahora vincularemos el mapa a nuestro controlador. Para ello crearemos un fichero map-module.js con un módulo llamado «AngularGoogleMap» y un controlador «MapCtrl» a los que referenciábamos anteriormente con las directivas ng-app y ng-controller.

var app = angular.module('AngularGoogleMap', ['google-maps']);

app.controller('MapCtrl', ['$scope', function ($scope) {

	$scope.map = {
		center: {
			latitude: 40.454018, 
			longitude: -3.509205
		}, 
		zoom: 12,
		options : {
			scrollwheel: false
		},
		control: {}
	};
	$scope.marker = {
		id: 0,
		coords: {
			latitude: 40.454018,
			longitude: -3.509205
		},
		options: {
			draggable: true
		}
	};
}]);

Como vemos lo único que hacemos es vincular, a través el objeto $scope, las propiedades de nuestras directivas google-map y marker a nuestro controlador mediante un objeto «map» y otro objeto «marker».

Y con esto ya tendríamos nuestro mapa.


Simple Map

6. Añadiendo markers.

Vamos a complicar ligeramente la cosa creando un mapa que nos permita añadir marcadores dinámicamente a nuestro mapa.

Lo primero que haremos será sustituir la directiva marker por markers. Nuestro mapa en la vista quedaría de la siguiente forma.

<google-map center="map.center" 
			zoom="map.zoom" 
			draggable="true" 
			options="map.options" 
			control="map.control">
	<markers models="map.markers" coords="'self'" options="'options'" isLabel="true">
	</markers>
</google-map>

Observamos que la directiva markers viene con algunas propiedades:

  • models: expresión que, al ser evaluada, debe referenciar un array de markers que serán añadidos al mapa.
  • coords: cadena de caracteres que indica el nombre de la propiedad de cada objeto marker del array que contiene las coordenadas del marcador. La palabra reservada «self» indica que, tanto la latitud (latitude) como la longitud (longitude) del marcador están directamente como propiedades el objeto marker (no contenidas en otro objeto).
  • options: expresión que, al ser evaluada, devolverá opciones adicionales que proporcionaremos a cada marcador.
  • isLabel: expresión que, al ser evaluada, nos devolverá un booleano indicando si nuestros markers pueden llevar etiqueda con texto o no.

6.1 Por coordenadas.

Para añadir un marcador por coordenadas hacemos algo como lo siguiente:

app.controller('MapCtrl', ['$scope', function ($scope) {

	var markerId = 0;

	function refresh(marker) {
		$scope.map.control.refresh({latitude: marker.latitude,
		longitude: marker.longitude});
	}
        
	function create(latitude, longitude) {
		var marker = {
			options: {
				animation: 1,
				labelAnchor: "28 -5",
				labelClass: 'markerlabel'    
			},
			latitude: latitude,
			longitude: longitude,
			id: ++markerId          
		};
		return marker;        
	}

	function invokeSuccessCallback(successCallback, marker) {
		if (typeof successCallback === 'function') {
			successCallback(marker);
		}
	}

	function createByCoords(latitude, longitude, successCallback) {
		var marker = create(latitude, longitude);
		invokeSuccessCallback(successCallback, marker);
	}
	    
	createByCoords(40.454018, -3.509205, function (marker) {
		marker.options.labelContent = 'Autentia';
		$scope.autentiaMarker = marker;
		refresh(marker);
	});
	$scope.map = {
		center: {
			latitude: $scope.autentiaMarker.latitude,
			longitude: $scope.autentiaMarker.longitude
		},
		zoom: 12,
		markers: [],
		control: {},
		options: {
			scrollwheel: false
		}
	};

	$scope.map.markers.push($scope.autentiaMarker);        

}]);

Podemos destacar varias cosas en el anterior código.

Observamos que en el objeto map de nuestro $scope hemos definido un array de markers, al que tendremos que añadir los diferentes marcadores que queremos que aparezcan en nuestro mapa.

Observamos que tenemos una función createByCoords que recibirá la latitud y la longitud de nuestro marcador además de una función de callback que recibirá nuestro marker y en la que decidiremos qué hacer con él. Lógicamente lo que haremos será presentarlo en el mapa añadiéndolo al array de markers.

Por último, podríamos destacar la función create que recibe una latitud y una longitud a partir de las cuales, construirá nuestro marcador. Observamos que tiene diferentes propiedades, entre las que destacan: labelAnchor y labelClass, que nos permitirán que podamos añadir una etiqueta a nuestro marcador. El contenido de la etiqueta se lo indicaremos con la propiedad labelContent. Observamos que la función está preparada para devolver un identificador de marcador distinto en cada uno que creemos. Si creamos varios marcadores con el mismo identificador sólo se añadirá uno al mapa.


Dynamic marker

6.2 Por posición actual.

Siguiendo un poco la línea de lo que hemos hecho en el punto anterior y haciendo uso del API de Geolocalización de HTML5 podríamos obtener nuestra posición actual y marcarla en el mapa.

function createByCurrentLocation(successCallback) {
	if (navigator.geolocation) {
		navigator.geolocation.getCurrentPosition(function (position) {
			var marker = create(position.coords.latitude, position.coords.longitude);
			invokeSuccessCallback(successCallback, marker);
		});
	} else {
		alert('Unable to locate current position');
	}
}

createByCurrentLocation(function (marker) {
	marker.options.labelContent = 'You´re here';
	$scope.map.markers.push(marker);
	refresh(marker);
});


Dynamic marker

6.3 Por dirección.

Y por último, gracias al servicio de geocodificación que nos ofrece el API Javascript de Google Maps, podríamos obtener un marcador por una dirección dada. Ej: Concha Espina 1, Madrid.

function createByAddress(address, successCallback) {
	var geocoder = new google.maps.Geocoder();
	geocoder.geocode({'address' : address}, function (results, status) {
		if (status === google.maps.GeocoderStatus.OK) {
			var firstAddress = results[0];
			var latitude = firstAddress.geometry.location.k;
			var longitude = firstAddress.geometry.location.B;
			var marker = create(latitude, longitude);
			invokeSuccessCallback(successCallback, marker);
		} else {
			alert("Unknown address: " + address);
		}
	});
}

Podéis VER EL EJEMPLO EN FUNCIONAMIENTO AQUÍ.

7. Referencias.


8. Conclusiones.

En este tutorial hemos visto lo sencillo que es trabajar con Google Maps y AngularJS gracias a la librería de directivas angular-google-maps. Si no estás muy acostumbrado a trabajar con AngularJS debes saber que Angular es bastante «celoso» con el uso de librerías externas que manipulen o interactuen con elementos del DOM. En vez de utilizar directamente estas librerías, la recomendación general suele ser hacerlo mediante el uso de directivas de AngularJS.

Cualquier duda en la sección de comentarios.

Espero que este tutorial os haya sido de ayuda. Un saludo.

Miguel Arlandy

marlandy@autentia.com

Twitter: @m_arlandy

9 COMENTARIOS

  1. Buenas Miguel Excelente tutorial. Tengo una pregunta si quisiera hacer polilíneas y poligonos con esta directiva de google maps como la podria hacer? Espero respuesta. Gracias

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad