В веб-картографии постоянно возникает необходимость преобразовывать координаты из одного представления в другое. Пользователь взаимодействует с картой через экранные пиксели, тогда как географические объекты хранятся в виде долготы и широты. Внутри движка карты дополнительно используются проекционные координаты и мировая система координат.
Mapbox GL JS предоставляет набор инструментов для преобразования между различными системами координат:
LngLat);Point);Подобные преобразования используются для:
Основной формат координат в Mapbox GL JS представлен классом
LngLat.
Пример создания объекта:
const point = new mapboxgl.LngLat(37.6176, 55.7558);
Параметры:
| Параметр | Значение |
|---|---|
| Longitude | Долгота |
| Latitude | Широта |
Важно помнить порядок:
[lng, lat]
а не
[lat, lng]
Правильно:
[37.6176, 55.7558]
Неправильно:
[55.7558, 37.6176]
Многие методы карты возвращают экземпляр LngLat.
Получение центра карты:
const center = map.getCenter();
console.log(center.lng);
console.log(center.lat);
Результат:
LngLat {
lng: 37.6176,
lat: 55.7558
}
Конвертация в массив:
const coords = center.toArray();
console.log(coords);
Результат:
[37.6176, 55.7558]
Конвертация в строку:
console.log(center.toString());
Результат:
"LngLat(37.6176, 55.7558)"
Для работы с экраном используется класс Point.
Он представляет положение объекта внутри контейнера карты в пикселях.
Структура:
Point {
x: 250,
y: 400
}
Где:
x — смещение по горизонтали;y — смещение по вертикали.Начало координат располагается в левом верхнем углу контейнера карты.
Схема:
(0,0)
┌───────────────────► X
│
│
│
▼
Y
Метод project() преобразует географические координаты в
экранные.
Синтаксис:
map.project(lngLat)
Пример:
const pixel = map.project([37.6176, 55.7558]);
console.log(pixel);
Результат:
Point {
x: 532,
y: 284
}
После этого координаты можно использовать для размещения DOM-элементов.
Пример:
const markerElement = document.getElementById('custom-marker');
const point = map.project([37.6176, 55.7558]);
markerElement.style.left = `${point.x}px`;
markerElement.style.top = `${point.y}px`;
Обратное преобразование выполняется методом
unproject().
Синтаксис:
map.unproject(point)
Пример:
const lngLat = map.unproject([500, 300]);
console.log(lngLat);
Результат:
LngLat {
lng: 37.6,
lat: 55.7
}
Таким образом можно определить координаты на карте по известному пикселю экрана.
Наиболее распространённый сценарий связан с обработкой событий мыши.
map.on('click', (event) => {
console.log(event.lngLat);
});
Объект события содержит уже вычисленные координаты.
Также доступны экранные координаты:
map.on('click', (event) => {
console.log(event.point);
});
Результат:
Point {
x: 600,
y: 350
}
Преобразование выполняется автоматически:
map.on('click', (event) => {
const pixel = event.point;
const coords = map.unproject(pixel);
console.log(coords);
});
Часто требуется получить обе формы координат одновременно.
map.on('mousemove', (event) => {
const lngLat = event.lngLat;
const point = map.project(lngLat);
console.log(lngLat);
console.log(point);
});
Схема преобразований:
LngLat
│
▼
project()
│
▼
Point
│
▼
unproject()
│
▼
LngLat
Во время перемещения мыши можно постоянно отслеживать положение указателя.
map.on('mousemove', (event) => {
const { lng, lat } = event.lngLat;
console.log(
lng.toFixed(6),
lat.toFixed(6)
);
});
Вывод:
37.617420 55.755790
37.617430 55.755800
37.617450 55.755810
Подобный механизм используется для создания координатной строки в интерфейсе ГИС.
Размеры контейнера:
const canvas = map.getCanvas();
console.log(canvas.width);
console.log(canvas.height);
Центр контейнера:
const centerPoint = {
x: canvas.width / 2,
y: canvas.height / 2
};
Получение географической точки в центре:
const centerLngLat = map.unproject(centerPoint);
console.log(centerLngLat);
Для вычисления видимой области необходимо преобразовать углы контейнера.
Левый верхний угол:
const northWest = map.unproject([0, 0]);
Правый нижний угол:
const canvas = map.getCanvas();
const southEast = map.unproject([
canvas.width,
canvas.height
]);
Получение координат:
console.log(northWest);
console.log(southEast);
Такой подход используется при реализации пользовательских запросов к серверу по видимой области карты.
Для получения прямоугольной области отображения удобнее использовать готовый метод.
const bounds = map.getBounds();
Получение углов:
const northEast = bounds.getNorthEast();
const southWest = bounds.getSouthWest();
Получение координат:
console.log(northEast.lng);
console.log(northEast.lat);
console.log(southWest.lng);
console.log(southWest.lat);
Объект:
LngLatBounds
представляет географическую область текущего окна карты.
Mapbox GL JS активно использует GeoJSON.
Преобразование точки:
const lngLat = map.getCenter();
const geojson = {
type: "Point",
coordinates: lngLat.toArray()
};
Результат:
{
"type": "Point",
"coordinates": [
37.6176,
55.7558
]
}
Исходная геометрия:
const feature = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [37.6176, 55.7558]
}
};
Создание объекта LngLat:
const lngLat = new mapboxgl.LngLat(
feature.geometry.coordinates[0],
feature.geometry.coordinates[1]
);
Упрощённый вариант:
const lngLat = feature.geometry.coordinates;
Поскольку большинство методов карты принимают массив координат напрямую.
Массив:
const coordinates = [37.6176, 55.7558];
Объект:
const lngLat = mapboxgl.LngLat.convert(
coordinates
);
Результат:
LngLat {
lng: 37.6176,
lat: 55.7558
}
Метод также работает с объектами:
const point = mapboxgl.LngLat.convert({
lng: 37.6176,
lat: 55.7558
});
Mapbox GL JS использует проекцию Web Mercator.
Она позволяет представить поверхность Земли на плоскости.
Особенности:
Географические координаты автоматически преобразуются в меркаторские значения при рендеринге.
Процесс выглядит следующим образом:
Longitude/Latitude
│
▼
Web Mercator
│
▼
World Coordinates
│
▼
Screen Pixels
Разработчику обычно не требуется выполнять эти вычисления вручную, поскольку движок делает их автоматически.
Для работы с трёхмерной графикой предусмотрен класс
MercatorCoordinate.
Создание объекта:
const mercator =
mapboxgl.MercatorCoordinate
.fromLngLat(
[37.6176, 55.7558]
);
Получение значений:
console.log(mercator.x);
console.log(mercator.y);
console.log(mercator.z);
Такие координаты используются:
Стандартные HTML-маркеры часто требуют ручного позиционирования.
const point = map.project([
37.6176,
55.7558
]);
Размещение:
element.style.transform =
`translate(${point.x}px, ${point.y}px)`;
При перемещении карты необходимо обновлять координаты.
map.on('move', updateMarker);
Функция:
function updateMarker() {
const point = map.project([
37.6176,
55.7558
]);
element.style.transform =
`translate(${point.x}px, ${point.y}px)`;
}
После преобразования географических координат в пиксели становится возможным вычислять экранные расстояния.
const p1 = map.project([
37.6176,
55.7558
]);
const p2 = map.project([
37.65,
55.78
]);
Расчёт:
const distance = Math.sqrt(
Math.pow(p2.x - p1.x, 2) +
Math.pow(p2.y - p1.y, 2)
);
console.log(distance);
Результат:
245.37
Значение будет выражено в пикселях текущего масштаба карты.
Экранные координаты зависят от:
zoom);bearing);pitch).Например:
const point = map.project([
37.6176,
55.7558
]);
После изменения масштаба:
map.zoomTo(12);
тот же географический объект получит другие экранные координаты.
По этой причине результаты project() нельзя кэшировать
на длительное время без пересчёта.
Неправильно:
[55.7558, 37.6176]
Правильно:
[37.6176, 55.7558]
После перемещения карты координаты необходимо пересчитывать.
Неправильно:
const point = map.project(coords);
// использование спустя несколько минут
Правильно:
map.on('move', () => {
const point = map.project(coords);
});
При ненулевом значении bearing экранные координаты
изменяются относительно стандартного положения карты.
map.setBearing(45);
После поворота результаты:
map.project(...)
будут отличаться от значений, полученных до вращения.
Координаты объекта event.clientX относятся ко всему окну
браузера.
document.addEventListener('click', (event) => {
console.log(event.clientX);
});
Для картографических вычислений предпочтительно использовать:
event.point
из событий Mapbox GL JS, поскольку они уже привязаны к контейнеру карты.