Manual de HTML: Geolocalización HTML5 en aplicaciones web

En el pasado, para detectar la localización de un dispositivo cliente desde una aplicación web, era necesario inspeccionar la dirección IP del cliente y averiguar, usualmente mediante un servicio externo, dónde se encontraba el dispositivo.

Sin embargo, junto con el HTML5, el W3C ha desarrollado un conjunto de APIs que permiten obtener la información de posicionamiento geográfico con JavaScript, desde el lado del cliente del dispositivo, es decir, un iPhone, un Android o incluso los navegadores de escritorio convencionales.

La funcionalidad de estas APIs depende del grado de implementación en los navegadores web, pero actualmente la mayoría de los navegadores modernos ya están adoptando estas funcionalidades y prestan soporte nativo a la geolocalización HTML5.

Recursos

La API de geolocalización no identifica cómo se ha determinado la información de ubicación. Dicha información puede obtenerse vía GPS, por triangulación de antenas de telefonía o puntos de acceso Wi-FI, mediante la dirección IP u otras técnicas, así como combinando varias de ellas.

Si el dispositivo no dispone de GPS, el navegador utilizará triangulación de antenas de telefonía, la dirección IP o los puntos de acceso Wi-FI cercanos y pasará esa información a un servicio externo de geolocalización para obtener la posición.

Si el dispositivo dispone de GPS, el navegador es libre de utilizarlo, pero no está obligado a ello, por lo que no está garantizado que el navegador use geolocalización basada en GPS simplemente porque dispone de un chip GPS. En caso de priorizar la precisión utilizará el GPS, pero si prioriza la rapidez o un menor consumo de energía utilizará otros métodos.

Desconocer cómo se logró la geolocalización no suele ser un problema, pero la exactitud de la información de ubicación puede variar mucho dependiendo de la técnica utilizada.

La API de geolocalización reside en el objeto navigator en JavaScript:
- window.navigator.geolocation

La API de geolocalización proporciona dos maneras de trabajar:

  • Método navigator.geolocation.getCurrentPosition: permite obtener una única posición.
  • Método navigator.geolocation.watchPosition: permite obtener la posición reiteradamente, cada vez que el dispositivo cambia de ubicación. Se cancela con el método navigator.geolocation.clearWatch.

La API de geolocalización define varias propiedades para el objeto position, pero sólo tres de ellas han sido implementadas consistentemente por la mayoría de navegadores:
- position.coords.latitude
- position.coords.longitude
- position.coords.accuracy

Ejemplo con getCurrentPosition()

El método getCurrentPosition() permite obtener la localización actual del cliente.

Vamos a ver un ejemplo con getCurrentPosition():

  1. La etiqueta DTD <!DOCTYPE html> define la página como un documento HTML5:
    <!DOCTYPE html>
  1. El evento JavaScript onclick del botón btnGet inicia el proceso de consulta de la ubicación actual llamando a la función get_current_position():
    <div>
        <button id="btnGet" onclick="get_current_position()">Find my location</button>
    </div>

    Esto es lo que se ve en este punto:

    Geolocation HTML5

  1. Usaremos el objeto navigator.geolocation para detectar si el navegador soporta geolocalización HTML5:
    if (navigator.geolocation) {
        // geolocation IS available
        navigator.geolocation.getCurrentPosition(success, error, options);
    } else {
        // geolocation IS NOT available
        geo_is_not_available();
    }
  1. El método getCurrentPosition() acepta tres parámetros:
    navigator.geolocation.getCurrentPosition(success, error, options);

    Cuando se llama a este método, si tiene éxito ejecuta la función success pasándole el objeto position como argumento. Si el intento falla, ejecuta la función error (si existe) pasándole el objeto error como argumento.

    El parámetro options es una cadena que permite establecer algunas opciones de geolocalización, como:

    • maximumAge: tiempo (en milisegundos) para almacenar en caché la posición obtenida. Valores: 0 (por defecto).
    • timeout: tiempo (en milisegundos) máximo de espera hasta que el servicio de ubicación responda. Valores: 0 (por defecto).
    • enableHighAccuracy: establece si el navegador debe intentar utilizar los servicios de localización de alta precisión (por ejemplo, GPS) cuando sean compatibles con el navegador y el dispositivo. Valores: true, false (por defecto).
  1. La función geo_success() se encarga de hacer algo con el objeto position. Por ejemplo, podría mostrar un mensaje emergente con los datos obtenidos:
    function geo_success(position) {
        alert('Latitude: ' + position.coords.latitude + '\xB0\n' +
              'Longitude: ' + position.coords.longitude + '\xB0\n' +
              'Accuracy: ' + position.coords.accuracy + ' m');
    }

    Esto es lo que veríamos:

    Geolocation HTML5 alert

    Otra opción sería mostrar un mapa, por ejemplo de Google Static Map API:

    function geo_success(position) {
        var latitude  = position.coords.latitude;
        var longitude = position.coords.longitude;
        var accuracy = position.coords.accuracy;
     
        document.getElementById("out").innerHTML = '<p>Latitude: ' + latitude + '&deg;<br>Longitude: ' + longitude + '&deg;<br>Accuracy: ' + accuracy + ' m</p>';
     
        var img = new Image();
        img.src = "http://maps.google.com/maps/api/staticmap?sensor=false&center=" + latitude + "," + longitude + "&zoom=14&size=600x200&markers=color:blue|label:S|" + latitude + ',' + longitude;
        document.getElementById("out").appendChild(img);
    }

    Este sería el resultado:

    Geolocation HTML5 map

  1. La función geo_error() se encarga de manejar los errores. Puede ocurrir un error si el usuario no comparte los datos de geolocalización (PERMISSION_DENIED), si el sistema no puede detectar la posición actual (POSITION_UNAVAILABLE), si se supera el tiempo máximo de espera (TIMEOUT), un error desconocido (UNKNOWN_ERROR) o por otros motivos. Por ejemplo, para mostrar el error haremos:
    function geo_error(error) {
       alert('ERROR(' + error.code + '): ' + error.message);
    }

    Si se produce algún error nos mostrará un aviso:

    Geolocation HTML5 error

    Debemos tener en cuenta que el navegador pide autorización al usuario para compartir la ubicación con la aplicación, por lo que si el usuario no comparte los datos de geolocalización obtendremos un error:

    Geolocation HTML5 permission

  1. Si el navegador no soporta geolocalización HTML5 se ejecutará la función geo_is_not_available(). Por ejemplo, podría mostrar una alerta emergente con un mensaje de error:
    function geo_is_not_available() {
        alert('Geolocation is not supported by your browser');
    }

    En un navegador que no soporte geolocalización HTML5 veremos este aviso:

    Geolocation HTML5 is not available

  1. Geolocalización basada en la dirección IP

    En aquellos navegadores que no soportan la geolocalización HTML5, para conocer la ubicación del cliente tendremos que utilizar un servicio de geolocalización externa basado en la dirección IP. Estos servicios mapean las direcciones IP a ubicaciones geográficas utilizando grandes bases de datos de geolocalización.

    Generalmente hacen un buen trabajo, pero a veces pueden sufrir problemas debido a que la dirección IP está asociada a una ubicación incorrecta, la dirección IP sólo se puede asociar a un área geográfica muy amplia o la dirección IP no aparece en la base de datos y no puede ser mapeada.

    Aunque cuando se utiliza un servicio de geolocalización externa la precisión no es tan buena como cuando se usa la geolocalización nativa del dispositivo, e incluso puede no funcionar el servicio, cuando el GPS o la triangulación no están disponibles son una buena alternativa.

    Existen muchos servicios de geolocalización externa. Por ejemplo, podemos combinar l2.io para obtener la IP del cliente y geoplugin.com para la geolocalización basada en IP.

    Para obtener la IP del cliente con l2.io incluiremos una etiqueta <script> que al cargar la URL asigna a la variable global my_ip, pasada como parámetro, el valor de la IP del cliente:

    <script type="text/javascript" src="http://l2.io/ip.js?var=my_ip"></script>

    En JavaScript podremos usar la variable global my_ip:

    // my_ip: direccion IP obtenida recurriendo a un servicio externo
    alert(my_ip);

    Una vez que tenemos la IP del cliente, para la geolocalización basada en IP con geoplugin.com incluiremos una etiqueta <script> que nos proporcionará una serie de funciones de geolocalización basadas en IP, que podremos utilizar en nuestra página:

    <script type="text/javascript" language="JavaScript" src="http://www.geoplugin.net/javascript.gp"></script>

    En JavaScript podremos usar diversas funciones de geolocalización, como:

    var my_latitude    = geoplugin_latitude();    // '42.814098'
    var my_longitude   = geoplugin_longitude();   // '-1.6412'
    var my_city        = geoplugin_city();        // 'Pamplona'
    var my_region      = geoplugin_region();      // 'Navarre'
    var my_countryName = geoplugin_countryName(); // 'Spain'

    Una vez que tengamos la localización del cliente, enviaremos el resultado a la función geo_success():

    var position = {  
        coords : {  
            latitude: my_latitude,  
            longitude: my_longitude  
         },  
         address : {  
             city: my_city,  
             region: my_region,  
             country: my_countryName  
         }  
    };  
    geo_success(position);

El ejemplo completo del método getCurrentPosition() será el siguiente:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://l2.io/ip.js?var=my_ip"></script>
<script type="text/javascript" language="JavaScript" src="http://www.geoplugin.net/javascript.gp"></script>
<script>
function get_current_position() {
    document.getElementById("out").innerHTML = "<p>Locating...</p>";
 
    var geo_options = {enableHighAccuracy:true, maximumAge:30000, timeout:27000};
    if (navigator.geolocation) {
        // geolocation IS available
        navigator.geolocation.getCurrentPosition(geo_success, geo_error, geo_options);
    } else {
        // geolocation IS NOT available
        geo_is_not_available();  
    }
}
 
function geo_success(position) {
    var latitude  = position.coords.latitude;
    var longitude = position.coords.longitude;
    var accuracy  = position.coords.accuracy;
 
    document.getElementById("out").innerHTML = '<p>Latitude: ' + latitude + '&deg;<br>Longitude: ' + longitude + '&deg;<br>Accuracy: ' + accuracy + ' m</p>';
 
    var img = new Image();
    img.src = "http://maps.google.com/maps/api/staticmap?sensor=false&center=" + latitude + "," + longitude + "&zoom=14&size=600x200&markers=color:blue|label:S|" + latitude + ',' + longitude;
    document.getElementById("out").appendChild(img);
}
 
function geo_error(error) {
    document.getElementById("out").innerHTML = '<p>ERROR(' + error.code + '): ' + error.message + '</p>';
}
 
function geo_is_not_available() {
    var my_status      = geoplugin_status();      // '200'
    var my_latitude    = geoplugin_latitude();    // '42.814098'
    var my_longitude   = geoplugin_longitude();   // '-1.6412'
    var my_city        = geoplugin_city();        // 'Pamplona'
    var my_region      = geoplugin_region();      // 'Navarre'
    var my_countryName = geoplugin_countryName(); // 'Spain'
 
    if (my_status == 404 ) {
        // 200 - OK
        // 206 - Only country data returned, no city values found
        // 404 - No data found for the IP
        var error = {
            code : 404,
            message : "Error 404 - No data found for the IP"
        };
        geo_error(error);
        return;
    }
 
    var position = {
        coords : {
            latitude: my_latitude,
            longitude: my_longitude
        },  
        address : {
            city: my_city,
            region: my_region,
            country: my_countryName
        }
    };
    geo_success(position);
}
</script>
</head>
<body>
<div>
    <button id="btnGet" onclick="get_current_position()">Find my location</button>
</div>
<div id="out"></div>
</body>
</html>

Ejemplo con watchPosition() y clearWatch()

Los métodos watchPosition() y clearWatch() permiten obtener la ubicación cada vez que el dispositivo cambia de ubicación, en vez de recibir sólo una localización.

Vamos a ver un ejemplo con watchPosition() y clearWatch():

  1. El método watchPosition() tiene los mismos parámetros que el método getCurrentPosition(). La diferencia está en que el método watchPosition() vuelve a proporcionar la ubicación e invocar las funciones callback (success o error, si existe) cada vez que la posición del dispositivo cambia.

    El método watchPosition() devuelve un valor entero que identifica de forma unívoca el proceso de vigilancia:

    watchProcess = navigator.geolocation.watchPosition(success, error, options);
  1. Cuando se llama al método clearWatch() con el identificador que devuelve el método watchPosition(), entonces watchPosition() deja de solicitar nuevas posiciones y deja de invocar las funciones callback:
    navigator.geolocation.clearWatch(watchProcess);

El ejemplo completo del método watchPosition() será el siguiente:

<!DOCTYPE html>
<html>
<head>
<script>
var watchProcess = null;
 
function init_watch_position() {
    document.getElementById("out").innerHTML = "<p>Locating...</p>";
 
    var geo_options = {enableHighAccuracy:true, maximumAge:30000, timeout:27000};
 
    if (navigator.geolocation) {
        // geolocation IS available
        if (watchProcess == null) {  
            watchProcess = navigator.geolocation.watchPosition(geo_success, geo_error, geo_options);  
        }  
    } else {
        // geolocation IS NOT available
        geo_is_not_available();  
    }
}
 
function stop_watch_position() {
    if (watchProcess != null) {  
        navigator.geolocation.clearWatch(watchProcess);  
        watchProcess = null;
    } 
}
 
function geo_success(position) {
    var latitude  = position.coords.latitude;
    var longitude = position.coords.longitude;
    var accuracy  = position.coords.accuracy;
 
    document.getElementById("out").innerHTML = '<p>Latitude: ' + latitude + 
'&deg;<br>Longitude: ' + longitude + '&deg;<br>Accuracy: ' + accuracy + ' m</p>';
 
    var img = new Image();
    img.src = "http://maps.google.com/maps/api/staticmap?sensor=false&center=" + latitude + "," + longitude + "&zoom=14&size=600x200&markers=color:blue|label:S|" + latitude + ',' + longitude;  
    document.getElementById("out").appendChild(img);
}
 
function geo_error(error) {
    document.getElementById("out").innerHTML = '<p>ERROR(' + error.code + '): ' + error.message + '</p>';
}
 
function geo_is_not_available() {
    document.getElementById("out").innerHTML = "<p>Geolocation is not supported by your browser</p>";
}
</script>
</head>
<body>
<div>
    <button id="btnInitWatch" onclick="init_watch_position()">Monitor my location</button>
    <button id="btnStopWatch" onclick="stop_watch_position()">Stop monitoring</button>
</div>
<div id="out"></div>
</body>
</html>

Artículos en la categoría "Manual de HTML"

  1. Manual de HTML: Cómo tener una web
  2. Manual de HTML: Cabecera
  3. Manual de HTML: Estilos CSS
  4. Manual de HTML: Cajas (div)
  5. Manual de HTML: Texto
  6. Manual de HTML: Glosarios y Listas
  7. Manual de HTML: Enlaces
  8. Manual de HTML: Tablas
  9. Manual de HTML: Imágenes
  10. Manual de HTML: Frames (marcos)
  11. Manual de HTML: Colores HTML
  12. Manual de HTML: Colores seguros para la web
  13. Manual de HTML: Formularios
  14. Manual de HTML: Fuentes
  15. Manual de HTML: Objetos
  16. Manual de HTML: Eventos y scripts
  17. Manual de HTML: Caracteres especiales
  18. Manual de HTML: Unidades
  19. Manual de HTML: URL encoding
  20. Manual de HTML: Responsive Web Design (diseño web adaptativo)
  21. Manual de HTML: Geolocalización HTML5 en aplicaciones web

2 Comments:

  1. Muy buen aporte, gracias

  2. Maravilloso aporte…
    No se si sería mucho pedir, y desde mi desconocimiento del Javascrip…
    Me gustaría añadir a este código un boton (despues de un “Stop monitoring”), para lanzar la longitud y latitud a otro fichero php, para recoger el dato como GET o POST…
    De no ser posible esto, propongo subir a un Base de datos Mysql estos dos datos….
    Gracias…