Point и LngLat

При работе с картами практически любая операция связана с координатами и экранными позициями. Для этих целей в Mapbox GL JS используются два фундаментальных класса:

  • LngLat — представляет географические координаты точки на поверхности Земли.
  • Point — представляет координаты точки на экране или внутри контейнера карты.

Эти классы используются практически во всех подсистемах библиотеки: при позиционировании маркеров, обработке событий мыши, анимации камеры, преобразовании координат и вычислении расстояний.


Класс LngLat

Объект LngLat хранит географические координаты в формате:

new mapboxgl.LngLat(longitude, latitude);

Где:

  • longitude — долгота;
  • latitude — широта.

Пример:

const location = new mapboxgl.LngLat(37.6176, 55.7558);

console.log(location.lng);
console.log(location.lat);

Результат:

37.6176
55.7558

Порядок координат

В Mapbox GL JS всегда используется порядок:

[longitude, latitude]

а не:

[latitude, longitude]

Правильно:

[37.6176, 55.7558]

Неправильно:

[55.7558, 37.6176]

Это одна из наиболее распространённых ошибок при работе с картографическими библиотеками.


Создание объекта LngLat

Через конструктор

const point = new mapboxgl.LngLat(
    37.6176,
    55.7558
);

Через массив координат

Во многих API допускается использование массива:

const center = [37.6176, 55.7558];

map.setCenter(center);

Внутри библиотеки такой массив автоматически преобразуется в объект LngLat.


Свойства объекта LngLat

lng

Содержит долготу.

const position = new mapboxgl.LngLat(37.6176, 55.7558);

console.log(position.lng);

Результат:

37.6176

lat

Содержит широту.

console.log(position.lat);

Результат:

55.7558

Метод toArray()

Преобразует объект в массив координат.

const point = new mapboxgl.LngLat(
    37.6176,
    55.7558
);

const array = point.toArray();

console.log(array);

Результат:

[37.6176, 55.7558]

Метод полезен при взаимодействии с GeoJSON и внешними API.


Метод toString()

Возвращает строковое представление координат.

const point = new mapboxgl.LngLat(
    37.6176,
    55.7558
);

console.log(point.toString());

Пример результата:

LngLat(37.6176, 55.7558)

Такое представление удобно использовать для отладки.


Метод wrap()

Долгота может выходить за диапазон:

-180 ... 180

Например:

const point = new mapboxgl.LngLat(
    220,
    55
);

Координата 220° эквивалентна координате -140°.

Метод wrap() автоматически приводит долготу к допустимому диапазону.

const wrapped = point.wrap();

console.log(wrapped.lng);

Результат:

-140

Пример использования:

const current = map.getCenter().wrap();

Это особенно полезно на картах с бесконечной прокруткой по горизонтали.


Метод distanceTo()

Позволяет вычислить расстояние между двумя географическими точками.

const moscow = new mapboxgl.LngLat(
    37.6176,
    55.7558
);

const spb = new mapboxgl.LngLat(
    30.3351,
    59.9343
);

const distance = moscow.distanceTo(spb);

console.log(distance);

Результат возвращается в метрах.

Пример вывода:

633021.5

То есть примерно:

633 км

Использование LngLat в центре карты

Координаты центра карты задаются через объект LngLat либо массив.

const map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v12',
    center: [37.6176, 55.7558],
    zoom: 10
});

Внутри библиотеки значение будет преобразовано в LngLat.


Получение центра карты

const center = map.getCenter();

console.log(center);

Результат:

LngLat

Получение отдельных координат:

console.log(center.lng);
console.log(center.lat);

Использование в методе flyTo()

map.flyTo({
    center: new mapboxgl.LngLat(
        30.3351,
        59.9343
    ),
    zoom: 12
});

Либо сокращённая запись:

map.flyTo({
    center: [30.3351, 59.9343]
});

Использование в методе panTo()

map.panTo(
    new mapboxgl.LngLat(
        37.6176,
        55.7558
    )
);

Использование в маркерах

Каждый маркер хранит географическое положение как объект LngLat.

Создание маркера:

new mapboxgl.Marker()
    .setLngLat([37.6176, 55.7558])
    .addTo(map);

Получение координат:

const marker = new mapboxgl.Marker()
    .setLngLat([37.6176, 55.7558]);

const position = marker.getLngLat();

console.log(position.lng);
console.log(position.lat);

Использование в событиях карты

При клике карта возвращает координаты точки на поверхности Земли.

map.on('click', (event) => {
    console.log(event.lngLat);
});

Объект:

LngLat

Получение координат:

map.on('click', (event) => {
    console.log(event.lngLat.lng);
    console.log(event.lngLat.lat);
});

Класс Point

Если LngLat описывает положение на Земле, то Point описывает положение внутри контейнера карты.

Координаты измеряются в пикселях.

Создание объекта:

const point = new mapboxgl.Point(
    300,
    150
);

Здесь:

x = 300 px
y = 150 px

Координатная система Point

Начало координат находится в левом верхнем углу контейнера карты.

(0,0)
 ┌─────────────────────► X
 │
 │
 │
 ▼
 Y

Поэтому:

new mapboxgl.Point(0, 0);

соответствует левому верхнему углу карты.


Свойства Point

x

Горизонтальная координата.

const point = new mapboxgl.Point(250, 100);

console.log(point.x);

Результат:

250

y

Вертикальная координата.

console.log(point.y);

Результат:

100

Получение Point из события мыши

При клике по карте объект события содержит экранную позицию курсора.

map.on('click', (event) => {
    console.log(event.point);
});

Результат:

Point

Получение координат:

map.on('click', (event) => {
    console.log(event.point.x);
    console.log(event.point.y);
});

Разница между point и lngLat

При клике карта возвращает оба объекта.

map.on('click', (event) => {
    console.log(event.point);
    console.log(event.lngLat);
});

Например:

Point(450, 320)

и

LngLat(37.6176, 55.7558)

Первый объект показывает положение курсора внутри HTML-контейнера.

Второй показывает реальное положение точки на поверхности Земли.


Преобразование Point в LngLat

Метод unproject() преобразует экранные координаты в географические.

const point = new mapboxgl.Point(
    300,
    200
);

const lngLat = map.unproject(point);

console.log(lngLat);

Результат:

LngLat

Схема преобразования:

Point → LngLat

Преобразование LngLat в Point

Обратная операция выполняется методом project().

const point = map.project(
    [37.6176, 55.7558]
);

console.log(point);

Результат:

Point

Схема:

LngLat → Point

Практический пример преобразований

map.on('click', (event) => {
    const screenPoint = event.point;

    const geoPoint = map.unproject(screenPoint);

    console.log(screenPoint);
    console.log(geoPoint);
});

Возможный результат:

Point(412, 289)
LngLat(37.6176, 55.7558)

Арифметические операции Point

Объекты Point поддерживают ряд математических операций.

add()

Сложение координат.

const a = new mapboxgl.Point(10, 20);
const b = new mapboxgl.Point(5, 3);

const result = a.add(b);

console.log(result);

Результат:

Point(15, 23)

sub()

Вычитание координат.

const result = a.sub(b);

Результат:

Point(5, 17)

mult()

Умножение координат.

const result = a.mult(2);

Результат:

Point(20, 40)

div()

Деление координат.

const result = a.div(2);

Результат:

Point(5, 10)

Определение позиции объекта на экране

Частая задача — вычислить экранную позицию географической точки.

const lngLat = [37.6176, 55.7558];

const point = map.project(lngLat);

console.log(point.x);
console.log(point.y);

Такой подход используется при:

  • создании собственных HTML-оверлеев;
  • рисовании элементов поверх карты;
  • синхронизации карты с DOM-элементами;
  • создании пользовательских анимаций.

Использование Point в queryRenderedFeatures()

Метод поиска объектов может принимать экранную точку.

Поиск объектов под курсором:

map.on('click', (event) => {
    const features =
        map.queryRenderedFeatures(
            event.point
        );

    console.log(features);
});

Поиск внутри области:

const bbox = [
    new mapboxgl.Point(100, 100),
    new mapboxgl.Point(300, 300)
];

const features =
    map.queryRenderedFeatures(bbox);

Здесь поиск выполняется по прямоугольной области экрана.


Взаимосвязь Point и LngLat

Оба класса описывают одну и ту же точку в разных системах координат.

Схематично процесс выглядит следующим образом:

Географические координаты
        ↓
      LngLat
        ↓ project()
        ↓
       Point
        ↓
 Экран контейнера

Обратное преобразование:

Экран контейнера
       ↓
      Point
       ↓ unproject()
       ↓
     LngLat
       ↓
Географические координаты

Именно через постоянные преобразования между LngLat и Point Mapbox GL JS связывает географическое пространство карты с пикселями браузерного окна, обеспечивая работу маркеров, всплывающих окон, пользовательских интерфейсов, анимаций и интерактивных событий.