Работа с картами в MapLibre GL JS MapLibre GL JS почти всегда выходит за рамки простого отображения тайлов и слоёв. Практические задачи требуют вычисления расстояний между точками, оценки времени в пути, построения маршрутов и анализа геометрии объектов прямо в браузере или в связке с серверными API.
Координаты в веб-картах задаются в системе WGS84:
Важно учитывать, что это сферическая модель Земли, поэтому прямое применение евклидовой геометрии приводит к ошибкам.
Типичная ошибка — вычисление расстояния как:
const dx = lon2 - lon1;
const dy = lat2 - lat1;
const distance = Math.sqrt(dx * dx + dy * dy);
Такой подход допустим только для локальных приближений на малых расстояниях, но непригоден для реальных картографических задач.
Для корректного расчёта расстояния по поверхности Земли используется формула гаверсинусов:
d = 2R ()
Где:
Реализация на Jav * aScript:
function toRad(value) {
return (value * Math.PI) / 180;
}
function getDistance(lat1, lon1, lat2, lon2) {
const R = 6371e3; // метры
const φ1 = toRad(lat1);
const φ2 = toRad(lat2);
const Δφ = toRad(lat2 - lat1);
const Δλ = toRad(lon2 - lon1);
const a =
Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
Этот метод обеспечивает достаточную точность для большинства задач интерфейсов карт.
В экосистеме веб-карт часто применяется Turf.js, предоставляющий готовые функции для геоаналитики.
Пример расчёта расстояния:
import { distance } from "@turf/turf";
const from = [37.6173, 55.7558]; // Москва
const to = [30.3141, 59.9386]; // Санкт-Петербург
const result = distance(from, to, { units: "kilometers" });
Turf.js автоматически учитывает кривизну Земли и поддерживает разные единицы измерения.
В MapLibre GL JS вычисления расстояний часто интегрируются с событиями карты.
Пример: измерение расстояния между кликами пользователя.
let points = [];
map.on("click", (e) => {
const { lng, lat } = e.lngLat;
points.push([lng, lat]);
if (points.length === 2) {
const from = points[0];
const to = points[1];
const dist = turf.distance(from, to, { units: "meters" });
console.log(`Расстояние: ${dist.toFixed(2)} м`);
points = [];
}
});
Типичный сценарий — интерактивный инструмент измерения длины маршрута.
Маршрут обычно представлен массивом координат:
const route = [
[30.31, 59.93],
[30.32, 59.94],
[30.34, 59.95]
];
Длина вычисляется суммированием сегментов:
import { lineString, length } from "@turf/turf";
const line = lineString(route);
const totalLength = length(line, { units: "kilometers" });
Этот подход используется для:
Время движения напрямую зависит от:
Базовая модель:
t =
Где:
Пример расчёта:
function estimateTime(distanceMeters, speedKmh) {
const speedMs = speedKmh * (1000 / 3600);
return distanceMeters / speedMs; // секунды
}
Более реалистичный вариант учитывает сегментацию маршрута:
function estimateRouteTime(route, speedKmh) {
let total = 0;
for (let i = 0; i < route.length - 1; i++) {
const segment = turf.distance(route[i], route[i + 1], {
units: "kilometers"
});
total += segment;
}
return (total / speedKmh) * 3600;
}
MapLibre GL JS не предоставляет встроенного маршрутизатора. Поэтому расчёт времени часто делегируется внешним сервисам:
Пример запроса к OSRM:
fetch(
"https://router.project-osrm.org/route/v1/driving/30.31,59.93;30.32,59.94?overview=false"
)
.then(res => res.json())
.then(data => {
const route = data.routes[0];
console.log("Distance:", route.distance);
console.log("Duration:", route.duration);
});
Результат включает:
Эти данные затем визуализируются в MapLibre:
map.addSource("route", {
type: "geojson",
data: geojsonRoute
});
map.addLayer({
id: "route-line",
type: "line",
source: "route",
paint: {
"line-width": 4
}
});
Для корректного отображения длинных маршрутов используется интерполяция.
Пример с Turf.js:
import { lineString, along, length } from "@turf/turf";
const line = lineString(route);
const lineLength = length(line);
const points = [];
for (let i = 0; i < lineLength; i += 1) {
const point = along(line, i);
points.push(point.geometry.coordinates);
}
Это позволяет:
Расчёт времени используется для синхронизации анимации:
let progress = 0;
function animate() {
const point = turf.along(line, progress, { units: "kilometers" });
map.getSource("moving-point").setData(point);
progress += 0.01;
requestAnimationFrame(animate);
}
Чем выше точность расчёта расстояния, тем стабильнее анимация.
При работе с расстояниями часто возникают проблемы:
Особенно критично:
Корректный подход всегда опирается на географические координаты, а не на пиксели карты.
В реальных системах время движения корректируется:
Модель усложняется до:
t =
где каждый сегмент маршрута имеет собственную скорость.
Такая модель используется в навигационных системах и логистике, интегрируемых с MapLibre через внешние API и собственные вычислительные модули.