Resumen: en este post te mostraré a escuchar el cambio de ubicación de un dispositivo con JavaScript. Por ejemplo, vigilar el cambio de ubicación en un dispositivo móvil cuando el usuario se mueve, camina o conduce.
Vamos a usar JavaScript y la API ofrecida a través de navigator.geolocation
. Concretamente veremos la función watchPosition
.
Nota: recomiendo primero dar un repaso por mi otro post para ver la introducción al acceso a la ubicación desde JavaScript.
Si quieres ver lo que haremos al final del tutorial, puedes ver esta demostración. También puedes ver el repositorio en GitHub.
Cuando queremos obtener actualizaciones de la ubicación del dispositivo en JavaScript no llamamos al método getCurrentLocation
, mejor invocamos a watchPosition
para suscribirnos a un evento y recibir actualizaciones periódicas.
El método watchPosition
devuelve un id para que más tarde se pueda detener usando el método clearWatch
(así como setInterval y clearInterval)
Cabe mencionar que este método para vigilar la ubicación toma los mismos argumentos que el de getCurrentLocation
:
navigator.geolocation.watchPosition(onUbicacionConcedida, onErrorDeUbicacion, opcionesDeSolicitud);
Los dos primeros son callbacks, el primero en caso de éxito, el segundo en caso de error. El último argumento define las opciones de la suscripción a las actualizaciones de ubicación.
De nuevo lo digo, si no entiendes mucho esto, lee primero mi otro post.
Nota: el método onUbicacionConcedida
será llamado cada que haya actualizaciones de ubicación.
Ahora sí veamos un ejemplo de código.
Al inicio comprobamos que el navegador soporte la API de geolocation
.
Después definimos una variable en donde vamos a guardar el id que regrese watchPosition
, además de otras funciones como la que detiene el watcher y la que lo inicia.
La función onUbicacionConcedida
será llamada múltiples veces, cada que la ubicación se actualice.
const funcionInit = () => {
if (!"geolocation" in navigator) {
return alert("Tu navegador no soporta el acceso a la ubicación. Intenta con otro");
}
let idWatcher = null;
const onUbicacionConcedida = ubicacion => {
console.log(ubicacion);
}
const onErrorDeUbicacion = err => {
console.log("Error obteniendo ubicación: ", err);
}
const detenerWatcher = () => {
if (idWatcher) {
navigator.geolocation.clearWatch(idWatcher);
idWatcher = null;
}
}
const opcionesDeSolicitud = {
enableHighAccuracy: true, // Alta precisión
maximumAge: 0, // No queremos caché
timeout: 5000 // Esperar solo 5 segundos
};
idWatcher = navigator.geolocation.watchPosition(onUbicacionConcedida, onErrorDeUbicacion, opcionesDeSolicitud);
};
document.addEventListener("DOMContentLoaded", funcionInit);
Si queremos detener el watcher invocamos a clearWatch
. En ese mismo método convertimos a idWatcher
en null
.
Voy a mostrarte un ejemplo que al final se verá como en la imagen del inicio. Definimos un layout básico de Bootstrap 4:
<!doctype html>
<html lang="es">
<!--
Plantilla inicial de Bootstrap 4
@author parzibyte
Visita: parzibyte.me/blog
-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Vigilar y actualizar la ubicación del dispositivo con JavaScript">
<meta name="author" content="Parzibyte">
<title>Vigilar y actualizar la ubicación del dispositivo con JavaScript</title>
<!-- Cargar el CSS de Boostrap-->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous">
</head>
<body>
<!-- Termina la definición del menú -->
<main role="main" class="container">
<div class="row">
<!-- Aquí pon las col-x necesarias, comienza tu contenido, etcétera -->
<div class="col-12">
<h1>Vigilar la ubicación con JavaScript</h1>
<a href="//parzibyte.me/blog" target="_blank">By Parzibyte</a>
<br>
<button id="btnIniciar" class="btn btn-info">Iniciar</button>
<button id="btnDetener" class="btn btn-danger">Detener</button>
<br>
<strong>Latitud: </strong> <span id="latitud"></span>
<strong>Longitud: </strong> <span id="longitud"></span>
<br>
<pre id="log"></pre>
</div>
</div>
</main>
<script src="script.js">
</script>
</body>
</html>
Fíjate en los botones, pues uno inicia las actualizaciones de ubicación y otro las detiene.
También tenemos unos span
que muestran la última latitud y longitud obtenida, además de una etiqueta pre
para loguear.
Todo eso lo obtenemos con JavaScript, agregamos listeners de los click de los botones e interactuamos con la ubicación del usuario:
/**
Programado por Luis Cabrera Benito
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
Blog: https://parzibyte.me/blog
Ayuda: https://parzibyte.me/blog/contrataciones-ayuda/
Contacto: https://parzibyte.me/blog/contacto/
*/const funcionInit = () => {
if (!"geolocation" in navigator) {
return alert("Tu navegador no soporta el acceso a la ubicación. Intenta con otro");
}
let idWatcher = null;
const $latitud = document.querySelector("#latitud"),
$longitud = document.querySelector("#longitud"),
$btnIniciar = document.querySelector("#btnIniciar"),
$btnDetener = document.querySelector("#btnDetener"),
$log = document.querySelector("#log");
const onUbicacionConcedida = ubicacion => {
console.log(ubicacion);
const coordenadas = ubicacion.coords;
$latitud.innerText = coordenadas.latitude;
$longitud.innerText = coordenadas.longitude;
loguear(`${ubicacion.timestamp}: ${coordenadas.latitude},${coordenadas.longitude}`);
}
const loguear = texto => {
$log.innerText += "\n" + texto;
};
const onErrorDeUbicacion = err => {
$latitud.innerText = "Error obteniendo ubicación: " + err.message;
$longitud.innerText = "Error obteniendo ubicación: " + err.message;
console.log("Error obteniendo ubicación: ", err);
}
const detenerWatcher = () => {
if (idWatcher) {
navigator.geolocation.clearWatch(idWatcher);
idWatcher = null;
}
}
const opcionesDeSolicitud = {
enableHighAccuracy: true, // Alta precisión
maximumAge: 0, // No queremos caché
timeout: 5000 // Esperar solo 5 segundos
};
$btnIniciar.addEventListener("click", () => {
detenerWatcher();
idWatcher = navigator.geolocation.watchPosition(onUbicacionConcedida, onErrorDeUbicacion, opcionesDeSolicitud);
});
$btnDetener.addEventListener("click", detenerWatcher);
$latitud.innerText = "Cargando...";
$longitud.innerText = "Cargando...";
};
document.addEventListener("DOMContentLoaded", funcionInit);
Como ves, es el mismo código de hace un momento pero ahora hemos agregado interacción con el DOM.
Al final tendremos una web que se ve así:
De esta manera podemos ver el camino que un usuario recorre, saber si un dispositivo llegó a determinado lugar, etcétera.
Como puedes ver, a la izquierda está el timestamp indicando cuándo fue obtenida la ubicación.
Recuerda, esta es la parte 2 de alguna forma. Si quieres ver lo básico, mira este post.
El código lo puedes ver en GitHub y la demostración la puedes ver aquí.
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…
Esta web usa cookies.
Ver comentarios
Como puedo obtener los datos longitud y latitud con 15 digitos a la derecha de la coma en vez de 6 para tener mas exactitud
Hola. Si tiene alguna consulta puede hacérmela llegar en https://parzibyte.me/#contacto
Hola,
Como podria hacer para que el script o el proceso no se detenga en el celular cuando la pantalla no está activa (estando el celular prendido).
Gracias.
Crees que se podría hacer con una app hibrida?
Sí
Hola. No creo que se pueda, por las limitaciones de los navegadores. Podría ser con una app nativa, pero desde el navegador lo veo complejo.
Saludos :)