domingo, 20 de abril de 2008

Incorporando Google Maps en Application Express

Diversos artículos pueden encontrarse en Internet acerca de cómo implementar Google Maps en Oracle Application Express (APEX). Desafortunadamente, la mayoría son algo básicos y se limitan a cargar un mapa dentro de una región, no teniendo interacción con la base de datos.

En esta oportunidad vamos a ver cómo lograr desplegar puntos dinámicamente en un mapa a partir de datos almacenados en una tabla. Únicamente se requieren conocimientos básicos de Application Express, PL/SQL y Javascript.

Este artículo no pretende mostrar todas las funcionalidades de la API de Google Maps, sino resolver el problema puntual de programación en Oracle, luego dependerá de las habilidades Javascript del programador y de conocer a fondo las funcionalidades que brinda esta maravillosa API.

Aclarado esto, comencemos, paso a paso:

Paso 1: Tener APEX instalado.

Lo primero es tener APEX instalado, ya que necesitaremos la URL o IP para el paso siguiente.
Si tienen duda si APEX está instalado en su base de datos, ver mi artículo anterior.

Paso 2: Solicitar una clave en Google Maps.

Ir a la siguiente direccion http://code.google.com/apis/maps/signup.html para registrarnos y solicitar un código que necesitamos para utilizar el servicio. En el registro, se debe ingresar la URL donde será utilizado Google Maps.
Por ejemplo, si utilizamos el espacio gratuito Oracle Apex, podemos ingresar la URL http://apex.oracle.com/pls/otn/. Si se está desarrollando localmente (en la propia máquina) puede registrarse la IP 127.0.0.1, pero cuando finalice el desarrollo habrá que solicitar una nueva clave con la URL de producción, ya que Google requiere que el sitio registrado sea de acceso público.
El código generado será referenciado desde de nuestro script.

Paso 3: Manos a la obra con APEX!

En nuestra nueva aplicación APEX, como primer paso debemos crear una página.

Editar los atributos de la página y en el campo Enfoque de Cursor elegir el valor No enfocar Cursor.

En la sección Cabecera HTML, incluir el siguiente script reemplazando nuestra clave:
<script src="http://maps.google.com/maps?file=api&v=2&key=la_clave_de_google_maps&hl=es"
type="text/javascript"></script>
<script type="text/javascript">

//<![CDATA[

function load() {
if (GBrowserIsCompatible()) {
miMapa();
}
}

//]]>
</script>
En este javascript acabamos de definir la función load, la cual invoca a otra función miMapa que crearemos más adelante.

En el campo Atributo de Cuerpo HTML de Página, pegar lo siguiente:
onload="load();" onunload="GUnload();"
  • Se puede observar cómo en el evento onload de la página, se invoca a la función load incluída en el cabezal HTML.
Hecho esto, guardar los cambios efectuados en la página

Ahora queda la parte interesante, ya que deberemos crear la función miMapa la cual ejecutará la carga del mapa y los puntos de referencia extraídos de la base de datos. Esta función será generada por un bloque anónimo PL/SQL el cual será ejecutado cada vez que se carga la página.
Para este ejemplo, se creó una sencilla tabla geopuntos la cual contiene información sobre los puntos de referencia que queremos desplegar en nuestro mapa:
id_punto     NUMBER(10)    NOT NULL
latitud NUMBER(18,15) NOT NULL
longitud NUMBER(18,15) NOT NULL
descripcion VARCHAR2(100)
  • La precisión de latitud y longitud es adecuada para almacenar coordenadas geográficas de Google Maps.
  • Cada punto puede enriquecerse con valiosa información como pueden ser imagenes, archivos, links, íconos, etc.
  • Se recomienda consultar la extensa documentación y tutoriales que brinda Google Maps en su sitio oficial.
En el área Presentación de Página, en la sección Procesos, vamos a implementar nuestro bloque PL/SQL.
Crear un nuevo proceso de tipo PL/SQL. En Atributos de Proceso, ingresar un nombre cualquiera y elegir el valor En Carga, Antes de Cabecera. Clickear siguiente, y en Proceso, incluir el siguiente bloque:
DECLARE
CURSOR cr_puntos IS select * from puntosmapa;
BEGIN
htp.p('<script type="text/javascript">');
htp.p('//<![CDATA[');

htp.p('function crearMarca(lat, long, descr) {');
htp.p(' var point = new GLatLng(lat,long);');
htp.p(' var opts = {title: descr};');
htp.p(' var mark = new GMarker(point,opts);');
htp.p(' GEvent.addListener(mark, "click", function() {
mark.openInfoWindowHtml(''<div><B>'' + descr + ''</B><BR>Lat: '' + lat +
''<BR>Long: '' + long + ''</div>'');');
htp.p(' });');
htp.p('return mark;');
htp.p('}');

htp.p('function miMapa() {');
htp.p('var map = new GMap2(document.getElementById("map"));');
htp.p('map.addControl(new GLargeMapControl());');
htp.p('map.addControl(new GMapTypeControl());');
htp.p('map.addControl(new GOverviewMapControl());');
htp.p('map.setCenter(new GLatLng(-22.915739,-43.22912), 11);');

-- Recorro cursor e inserto los puntos
FOR punto IN cr_puntos
LOOP
htp.p('var marker = crearMarca('||to_char(punto.latitud,'999.9999999999999999')||','
||to_char(punto.longitud,'999.9999999999999999')||',"'||punto.descripcion||'");');
htp.p('map.addOverlay(marker);');
END LOOP;
htp.p('}');

htp.p('//]]>');
htp.p('</script>');
END;
Este es el punto neurálgico de la aplicación: en este bloque PL/SQL resolvemos la consulta a la base de datos, la creación del mapa y la publicación de los puntos de referencia extraídos. Notar el uso de la función PL/SQL htp.p(). Así como DBMS_OUTPUT.PUT_LINE envia caracteres a la salida en pantalla, la función htp.p envía cadenas de caracteres al browser, y esto precisamente lo que necesitamos ya que queremos construir el Javascript a ser ejecutado en la carga de la página.

Puede apreciarse la sencillez de esta implementación, en pocas líneas crea un mapa, lo centra y carga los controles básicos de zoom. La particularidad en este caso es el FOR LOOP, el cual recorre un cursor definido sobre la tabla, y en cada iteración define una marca "publicando" Javascript en tiempo de ejecución. Cada referencia tiene un toolTip cuando se pasa el mouse por encima y un globo informativo que se abre al clickear sobre la marca.

Y eso es todo, tras guardar el proceso (dejar el resto de los valores por defecto), hemos concluído nuestra aplicación y ya está lista para ser explorada.

Las posibilidades son muchísimas, y cuanto más se profundice sobre la documentación, mejores funcionalidades podremos lograr en APEX.

Un ejemplo implementado
Hice una página de demostración para que puedan ver que realmente funciona. En mi tabla de datos tengo almacenados puntos turísticos de Río de Janeiro, ciudad donde vivo actualmente :)

Para saber las coordenadas geográficas de un punto en la tierra, podemos utilizar por ejemplo la página Geocoder.

Hay mucha documentación y ejemplos disponibles sobre Google Maps y realmente es fácil comenzar a obtener resultados sorprendentes.

Finalmente le agradezco a Emilio Le Mener por su ayuda en Javascript.

Espero que este tutorial haya sido útil y puedan comenzar a implementar sin problemas con APEX y Google Maps.
Ver también:
Google Maps API
Presentación Google Developer Day 2007

6 comentarios:

maria.deliska dijo...

muito obrigado

carla dijo...

Hola, tengo una duda. Hay direcciones o ciudades de mi pais que no estan cargadas en googlemaps, es decir si las busco me sale un mensaje que no encontro nada. Yo tengo una Base de Datos que contiene como parametos la latitud-longitud de cada lugar que necesito y lo que quiero es poder pasar estos parametros para que se pinte en googlemaps, es posible hacer eso?. o solo se puede si la direccion existe en googlemaps.

lfer dijo...

Carla, solamente necesitas una latitud y una longitud para colocar una marca en Google Maps. Si tu dirección no aparece en Google Maps puedes encontrar las coordenadas visualmente o en Geocoder.
Una vez que tienes la base de datos con las coordenadas predefinidas entonces no tendras problemas en mostrar tu mapa.
Si tu pregunta respecta a funcionalidad de Google Maps, puedes consultar en el grupo de Google destinado para eso, AQUI

Saludos

Oscar Amelunge dijo...

te falta un paso en tu articulo, y es de poner una region html con un div con id="map"

my dijo...

Hi,

I can't seem to get the last bit to work, where you have a PL/SQL process. Please help.

Francisco Alberto dijo...

Hola, muy buena tu ayuda, yo necesito obtener la Longitud y Latitud desde una direccion ( PAIS, PROVINVIA, CIUDAD, CALLE Y ALTURA) pasadas por la aplicación. ya con estos datos usaria la función que explicas aqui. Que puedo usar para obtenerlas sin usar aplicaciones externas a la Long y Lat ? Gracias