Определение местоположения пользователя в Mapbox GL JS опирается на взаимодействие браузерного Geolocation API и встроенных инструментов библиотеки Mapbox GL JS. Основная задача заключается в получении координат устройства, их отображении на карте и последующем обновлении в реальном времени с учётом изменения позиции.
В основе механизма лежит объект navigator.geolocation,
который предоставляет доступ к данным GPS, Wi-Fi и сетевого
позиционирования устройства. Mapbox GL JS не выполняет геолокацию
самостоятельно, а интегрируется с этим API через контролы и
пользовательскую логику.
В Mapbox GL JS предусмотрен встроенный компонент управления
геолокацией — GeolocateControl. Он обеспечивает:
Базовая инициализация выполняется добавлением контролла к экземпляру карты.
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [0, 0],
zoom: 2
});
const geolocate = new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true,
showAccuracyCircle: true,
showUserHeading: true
});
map.addControl(geolocate);
Поведение контроля геолокации определяется набором параметров, влияющих на точность, производительность и UX.
Объект, передаваемый напрямую в Geolocation API:
enableHighAccuracy — использование более точных методов
определения координат (GPS вместо сетевых данных);timeout — максимальное время ожидания получения
координат;maximumAge — допустимое время кэширования позиции.positionOptions: {
enableHighAccuracy: true,
timeout: 6000,
maximumAge: 0
}
Высокая точность увеличивает энергопотребление и время получения данных, но критична для навигационных сценариев.
Режим непрерывного отслеживания положения. При включении карта автоматически обновляет позицию при каждом изменении координат.
trackUserLocation: true
Механизм основан на watchPosition, что позволяет
получать поток обновлений вместо одноразового запроса.
Отображение окружности погрешности определения координат. Радиус зависит от качества сигнала и источника данных.
showAccuracyCircle: true
Этот элемент визуально интерпретирует точность позиционирования, особенно важную при использовании сетевых методов определения координат.
Отображение направления движения устройства при наличии данных компаса.
showUserHeading: true
Используется преимущественно на мобильных устройствах с поддержкой гироскопа и магнитометра.
GeolocateControl предоставляет события, позволяющие обрабатывать жизненный цикл получения координат.
geolocate — успешное получение позиции;error — ошибка геолокации;trackuserlocationstart — начало отслеживания;trackuserlocationend — завершение отслеживания.geolocate.on('geolocate', (position) => {
const { longitude, latitude, accuracy } = position.coords;
console.log(longitude, latitude, accuracy);
});
geolocate.on('error', (error) => {
console.error(error.message);
});
В ряде случаев требуется прямой доступ к
navigator.geolocation без использования встроенного
UI-компонента Mapbox GL JS. Это даёт полный контроль над логикой
обновления данных и их отображением.
navigator.geolocation.getCurrentPosition(
(position) => {
const { longitude, latitude } = position.coords;
map.flyTo({
center: [longitude, latitude],
zoom: 14
});
},
(error) => {
console.error(error.message);
},
{
enableHighAccuracy: true
}
);
const watchId = navigator.geolocation.watchPosition(
(position) => {
const { longitude, latitude } = position.coords;
userMarker.setLngLat([longitude, latitude]);
},
(error) => {
console.error(error);
},
{
enableHighAccuracy: true,
maximumAge: 1000
}
);
// остановка отслеживания
navigator.geolocation.clearWatch(watchId);
Для визуализации позиции обычно используется слой или маркер. Mapbox
GL JS предоставляет два основных подхода: Marker и
GeoJSON source.
const userMarker = new mapboxgl.Marker({
color: '#2E86AB'
})
.setLngLat([0, 0])
.addTo(map);
При обновлении координат маркер перемещается без пересоздания объекта:
userMarker.setLngLat([longitude, latitude]);
Более гибкий способ — создание источника и слоя.
map.on('load', () => {
map.addSource('user-location', {
type: 'geojson',
data: {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [0, 0]
}
}
});
map.addLayer({
id: 'user-location-layer',
type: 'circle',
source: 'user-location',
paint: {
'circle-radius': 8,
'circle-color': '#007cbf'
}
});
});
Обновление координат:
map.getSource('user-location').setData({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [longitude, latitude]
}
});
Поле accuracy в объекте coords задаёт
радиус неопределённости в метрах. Чем выше значение, тем менее точное
определение.
Типичные сценарии интерпретации:
Визуализация точности обычно реализуется через окружность вокруг маркера пользователя.
Автоматическое перемещение камеры реализуется через методы
flyTo или easeTo.
map.flyTo({
center: [longitude, latitude],
zoom: 15,
speed: 1.2,
curve: 1
});
Для плавного сопровождения перемещения используется обновление центра
при каждом событии watchPosition.
Geolocation API возвращает структурированные ошибки с кодами:
1 — доступ запрещён пользователем;2 — позиция недоступна;3 — превышен таймаут.Пример обработки:
navigator.geolocation.getCurrentPosition(
successCallback,
(error) => {
switch (error.code) {
case error.PERMISSION_DENIED:
console.log('Доступ к геолокации запрещён');
break;
case error.POSITION_UNAVAILABLE:
console.log('Позиция недоступна');
break;
case error.TIMEOUT:
console.log('Превышено время ожидания');
break;
}
}
);
Поведение геолокации зависит от платформы:
При отсутствии разрешения GeolocateControl не активирует
отслеживание и возвращает событие ошибки.
Геолокация часто комбинируется с состоянием карты:
Пример привязки к радиусу поиска:
map.on('geolocate', (e) => {
const center = [e.coords.longitude, e.coords.latitude];
map.setFilter('points-of-interest', [
'distance',
center,
5000
]);
});
При использовании watchPosition важно учитывать частоту
обновлений:
Практика заключается в балансировке параметров
maximumAge и обработки событий с throttling:
let lastUpdate = 0;
navigator.geolocation.watchPosition((pos) => {
const now = Date.now();
if (now - lastUpdate < 1000) return;
lastUpdate = now;
userMarker.setLngLat([
pos.coords.longitude,
pos.coords.latitude
]);
});