useGeoLocation Composable
Reactive geolocation tracking with watch position and error handling
Code
import { ref, onUnmounted, type Ref } from 'vue';
interface GeoLocation {
latitude: Ref<number | null>;
longitude: Ref<number | null>;
accuracy: Ref<number | null>;
altitude: Ref<number | null>;
altitudeAccuracy: Ref<number | null>;
heading: Ref<number | null>;
speed: Ref<number | null>;
timestamp: Ref<number | null>;
isLoading: Ref<boolean>;
error: Ref<GeolocationPositionError | null>;
isWatching: Ref<boolean>;
}
export function useGeoLocation(
options: PositionOptions = { enableHighAccuracy: false, timeout: 10000, maximumAge: 30000 }
): GeoLocation {
const latitude = ref<number | null>(null);
const longitude = ref<number | null>(null);
const accuracy = ref<number | null>(null);
const altitude = ref<number | null>(null);
const altitudeAccuracy = ref<number | null>(null);
const heading = ref<number | null>(null);
const speed = ref<number | null>(null);
const timestamp = ref<number | null>(null);
const isLoading = ref(false);
const error = ref<GeolocationPositionError | null>(null);
const isWatching = ref(false);
let watchId: number | null = null;
// Update position data
const updatePosition = (pos: GeolocationPosition) => {
const coords = pos.coords;
latitude.value = coords.latitude;
longitude.value = coords.longitude;
accuracy.value = coords.accuracy;
altitude.value = coords.altitude;
altitudeAccuracy.value = coords.altitudeAccuracy;
heading.value = coords.heading;
speed.value = coords.speed;
timestamp.value = pos.timestamp;
isLoading.value = false;
error.value = null;
};
// Handle position error
const handleError = (err: GeolocationPositionError) => {
error.value = err;
isLoading.value = false;
isWatching.value = false;
};
// Get current position once
const getCurrentPosition = __TOKEN_36__ () => {
__TOKEN_37__ (!navigator.geolocation) {
error.value = new Error('Geolocation is not supported by your browser') as GeolocationPositionError;
return;
}
isLoading.value = true;
try {
const pos = await new Promise<GeolocationPosition>((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, options);
});
updatePosition(pos);
} __TOKEN_44__ (err) {
handleError(err as GeolocationPositionError);
}
};
// Watch position changes
const watchPosition = () => {
__TOKEN_46__ (!navigator.geolocation || isWatching.value) return;
isWatching.value = true;
isLoading.value = true;
watchId = navigator.geolocation.watchPosition(
updatePosition,
handleError,
options
);
};
// Clear watch
const clearWatch = () => {
__TOKEN_49__ (watchId !== null && navigator.geolocation) {
navigator.geolocation.clearWatch(watchId);
watchId = null;
}
isWatching.value = false;
};
// Toggle watch position
const toggleWatch = () => {
__TOKEN_51__ (isWatching.value) {
clearWatch();
} else {
watchPosition();
}
};
// Cleanup
onUnmounted(() => {
clearWatch();
});
return {
latitude,
longitude,
accuracy,
altitude,
altitudeAccuracy,
heading,
speed,
timestamp,
isLoading,
error,
isWatching,
getCurrentPosition,
watchPosition,
clearWatch,
toggleWatch
};
}
// Usage example
// const { latitude, longitude, getCurrentPosition } = useGeoLocation();
// getCurrentPosition().then(() => {
// console.log('Location:', latitude.value, longitude.value);
// });