La possibilità di individuare la posizione corrente di un dispositivo apre la strada a innumerevoli applicazioni: dalla ricerca di esercizi pubblici intorno alla località in cui si trova l'utente al suggerimento di itinerari, dalla pubblicità locale alle previsioni meteo geolocalizzate. Da un punto di vista tecnico, il rilevamento della posizione di un dispositivo è basato su diversi approcci: sfruttando la presenza di hardware GPS dedicato, utilizzando dati dedotti dalla rete wireless e/o cellulare, analizzando l'indirizzo IP.
Indipendentemente dall'approccio utilizzato, possiamo gestire con JavaScript le informazioni fornite dal sistema con un'approccio uniforme grazie alle API di geolocalizzazione definite dal W3C.
Occorre tener presente che, indipendentemente dal supporto del rilevamento della posizione corrente, l'utente deve esplicitamente autorizzare il browser o l'applicazione mobile a fornire informazioni sulla propria posizione.
La prima cosa da fare per accedere alla posizione corrente dell'utente è verificare il supporto della specifica funzionalità. Analogamente a come abbiamo visto anche per altre funzionalità, ciò può essere fatto molto semplicemente verificando l'esistenza dell'oggetto geolocation
:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(mostraPosizione);
}
Dall'esempio vediamo come, nel caso in cui il supporto alla geolocalizzazione sia presente, invochiamo il metodo getCurrentPosition() dell'oggetto geolocation. Nella sua forma più semplice, il metodo prevede un argomento che rappresenta la funzione di callback da invocare non appena sono disponibili le informazioni sulla posizione corrente.
Nel nostro caso la funzione mostraPosizione()
potrebbe essere definita come nel seguente esempio:
function mostraPosizione(posizione) {
console.log("Latitudine: " + posizione.coords.latitude);
console.log("Longitudine: " + posizione.coords.longitude);
}
La funzione prevede l'argomento posizione
che rappresenta le informazioni passate dal sistema sulla posizione dell'utente. Nel nostro caso utilizziamo la latitudine e la longitudine, ma l'oggetto prevede anche altre proprietà, come riepilogato nella seguente tabella:
Campo | Descrizione |
---|---|
coords.latitude |
la latitudine espressa come valore decimale |
coords.longitude |
la longitudine espressa come valore decimale |
coords.accuracy |
il livello di accuratezza nel calcolo della posizione espressa in metri |
coords.altitude |
l'altitudine espressa in metri |
coords.altitudeAccuracy |
il livello di accuratezza nel calcolo dell'altitudine espressa in metri |
coords.heading |
la direzione del movimento del dispositivo espressa in gradi di discostamento in senso orario dal nord |
coords.speed |
la velocità del movimento del dispositivo espressa in metri al secondo |
timestamp |
la data e ora del rilevamento della posizione |
Come possiamo vedere, le specifiche prevedono un'ampia gamma di informazioni relative alla posizione dell'utente e al suo movimento. Tuttavia non è detto che tutte queste informazioni siano disponibili dal momento che dipendono dall'hardware adottato dal dispositivo. Le uniche proprietà che devono essere garantite sono coords.latitude
, coords.longitude
, coords.accuracy
e timestamp
.
Si possono verificare situazioni in cui, pur essendo supportato il rilevamento della posizione, il dispositivo non è in grado di fornirci le relative informazioni. Situazioni del genere si possono verificare ad esempio se l'utente non ha autorizzato il browser o l'applicazione all'utilizzo della funzionalità, se l'utente è offline o non ha attivato il rilevatore GPS o è in una posizione fuori campo di rilevazione, ecc.
In questi casi sarebbe opportuno gestire la situazione ed eventualmente segnalare all'utente l'impossibilità di effettuare il rilevamento della posizione. A questo scopo il metodo getCurrentPosition()
prevede la possibilità di passare come secondo parametro la funzione di callback da eseguire quando si verifica un errore:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(mostraPosizione, gestisciErrore);
}
La funzione gestisciErrore()
riceve un oggetto error il cui campo code
indica la causa dell'errore:
function gestisciErrore(error) {
switch(error.code) {
case error.PERMISSION_DENIED:
console.log("Permesso negato dall'utente");
break;
case error.POSITION_UNAVAILABLE:
console.log("Impossibile determinare la posizione corrente");
break;
case error.TIMEOUT:
console.log("Il rilevamento della posizione impiega troppo tempo");
break;
case error.UNKNOWN_ERROR:
console.log("Si è verificato un errore sconosciuto");
break;
}
}
Tra le varie cause di errore vediamo la situazione in cui il rilevamento della posizione corrente impiega troppo tempo tanto da superare un timeout. In base alle specifiche W3C non è previsto un timeout predefinito per il rilevamento della posizione. Per impostarlo occorre passare al metodo getCurrentPosition()
un terzo parametro:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(mostraPosizione, gestisciErrore, opzioni);
}
Il parametro opzioni
è un oggetto che può prevedere le seguenti proprietà:
Proprietà | Descrizione | enableHighAccuracy |
valore booleano che abilita o meno un'alta accuratezza nel rilevamento della posizione |
---|---|
timeout |
quantità massima di millisecondi entro cui ottenere informazioni sulla posizione corrente |
maximumAge |
il tempo espresso in millisecondi per cui è possibile riutilizzare una posizione precedentemente rilevata |
Mentre il significato della proprietà timeout
dovrebbe essere abbastanza autoesplicativo, per le proprietà enableHighAccuracy
e maximumAge
proviamo a dare qualche informazione in più.
Accuratezza ed errore del rilevamento
Abbiamo detto che le informazioni sulla posizione dell'utente vengono calcolate sfruttando diversi approcci: informazioni di rete, rilevatori GPS, ecc. Ciascuno di questi approcci ha un proprio livello di accuratezza.
- con l'indirizzo IP l'accuratezza è scarsa: in genere si riesce ad identificare un territorio come una città se non una provincia;
- con la rete cellulare molto dipende dalla densità di celle presenti intorno all'utente: l'accuratezza potrebbe andare dall'ordine di centinaia di metri fino ad alcuni chilometri;
- il sistema GPS offre invece una precisione dell'ordine di qualche metro.
Un dispositivo cerca di sfruttare tutte le opzioni disponibili fornendo l'informazione ottenuta più velocemente, non necessariamente quindi la più precisa. Impostando la proprietà enableHighAccuracy
a true
chiediamo di ottenere la posizione più precisa possibile, anche a costo di attendere un po' di più.
Per cercare di ottimizzare la velocità di recupero delle informazioni sulla posizione corrente da un lato e di preservare il consumo di batteria per i dispositivi mobili dall'altro, è possibile fare in modo di memorizzare in una sorta di cache dedicata l'ultimo rilevamento effettuato ed indicare tramite la proprietà maximumAge
per quanto tempo riutilizzare l'informazione per le successive richieste.
Questo vuol dire, ad esempio, che le seguenti impostazioni richiedono un'elevata accuratezza del rilevamento, che una posizione può essere considerata valida per un minuto e che un rilevamento deve essere completato entro cinque secondi:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
mostraPosizione,
gestisciErrore,
{
enableHighAccuracy: true,
maximumAge: 60000,
timeout: 5000
});
}
Naturalmente le diverse impostazioni dipendono dal tipo di applicazione che sviluppiamo.
Se ad esempio la nostra applicazione fornisce informazioni meteo, non è necessario utilizzare un'elevata accuratezza nel rilevamento della posizione e possiamo riutilizzare l'ultimo rilevamento per diversi minuti o anche qualche ora.
watchPosition
Se invece dobbiamo fornire informazioni per guidare l'utente su un percorso, allora abbiamo bisogno di avere la sua posizione precisa e di rilevarla continuamente. In questo caso può aiutarci il metodo watchPosition() in alternativa a getCurrentPosition()
.
Infatti mentre getCurrentPosition()
richiede attivamente la posizione corrente, watchPosition()
ottiene automaticamente la posizione corrente ogni volta che c'è una variazione. Entrambi i metodi prevedono gli stessi parametri, tuttavia watchPosition()
restituisce un valore numerico che identifica la watch
associata:
var watch;
if (navigator.geolocation) {
watch = navigator.geolocation.watchPosition(
mostraPosizione,
gestisciErrore,
{
enableHighAccuracy: true,
maximumAge: 10000,
timeout: 2000
});
}
Il metodo watchPosition()
funziona in maniera del tutto analoga al metodo setInterval()
per la gestione dei timer. In maniera altrettanto analoga, se vogliamo interrompere il rilevamento continuo della posizione utilizzeremo il metodo clearWatch()
passandogli l'identificatore della watch
da eliminare:
navigator.geolocation.clearWatch(watch);