Работа с Leaflet

Leaflet и Turf.js часто применяются совместно для построения интерактивных карт, где визуализация данных дополняется пространственными вычислениями в браузере. Такая связка позволяет выполнять геоаналитику без серверной обработки, включая измерения расстояний, построение буферов, проверку пересечений и анализ полигонов.

Leaflet использует систему координат WGS84 в виде широты и долготы, но внутри рендеринга применяет проекцию Web Mercator (EPSG:3857). Turf.js работает исключительно в географических координатах WGS84 (longitude, latitude).

Ключевое правило интеграции — единый формат входных данных:

  • Leaflet: [lat, lng]
  • Turf.js: [lng, lat]

Ошибки в порядке координат являются наиболее частой причиной некорректных геометрических вычислений.

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

const leafletPoint = [55.751244, 37.618423];
const turfPoint = turf.point([leafletPoint[1], leafletPoint[0]]);

Отображение геометрий Turf.js на карте Leaflet

Геометрии, создаваемые Turf.js, могут быть напрямую добавлены на карту после преобразования в GeoJSON-слой.

const point = turf.point([37.618423, 55.751244]);

L.geoJSON(point).addTo(map);

Аналогично работают полигоны и линии:

const line = turf.lineString([
  [37.61, 55.75],
  [37.62, 55.76],
  [37.63, 55.77]
]);

L.geoJSON(line).addTo(map);

Leaflet автоматически интерпретирует GeoJSON и отображает его через L.geoJSON.

Геодезические расстояния

Turf.js предоставляет точные расчёты расстояний по поверхности Земли, используя сферическую модель.

const from = turf.point([37.618423, 55.751244]);
const to = turf.point([30.31413, 59.93863]);

const distance = turf.distance(from, to, { units: 'kilometers' });

Результат может быть использован для:

  • отображения расстояния между маркерами
  • фильтрации объектов по радиусу
  • построения маршрутов

Интеграция с Leaflet:

L.marker([55.751244, 37.618423]).addTo(map);
L.marker([59.93863, 30.31413]).addTo(map);

const line = turf.lineString([
  [37.618423, 55.751244],
  [30.31413, 59.93863]
]);

L.geoJSON(line, {
  style: { color: 'blue' }
}).addTo(map);

Построение буферных зон

Буферизация используется для создания зоны влияния вокруг объекта.

const center = turf.point([37.618423, 55.751244]);
const buffer = turf.buffer(center, 5, { units: 'kilometers' });

L.geoJSON(buffer, {
  style: {
    color: 'red',
    fillOpacity: 0.2
  }
}).addTo(map);

Буфер может применяться для:

  • анализа доступности объектов
  • определения зон покрытия
  • фильтрации точек внутри области

Проверка пересечений

Turf.js позволяет определять пересечения геометрий.

const poly1 = turf.polygon([[
  [37.6, 55.75],
  [37.7, 55.75],
  [37.7, 55.80],
  [37.6, 55.80],
  [37.6, 55.75]
]]);

const poly2 = turf.polygon([[
  [37.65, 55.77],
  [37.75, 55.77],
  [37.75, 55.82],
  [37.65, 55.82],
  [37.65, 55.77]
]]);

const intersects = turf.booleanIntersects(poly1, poly2);

Результат используется для:

  • анализа конфликтующих территорий
  • проверки наложения зон доставки
  • геозонирования

В Leaflet отображение:

L.geoJSON(poly1, { style: { color: 'green' } }).addTo(map);
L.geoJSON(poly2, { style: { color: 'orange' } }).addTo(map);

Генерация случайных точек в пределах полигона

Turf.js позволяет создавать выборки точек внутри заданной области.

const polygon = turf.polygon([[
  [37.6, 55.75],
  [37.7, 55.75],
  [37.7, 55.80],
  [37.6, 55.80],
  [37.6, 55.75]
]]);

const points = turf.randomPoint(50, { bbox: turf.bbox(polygon) });

L.geoJSON(points).addTo(map);

Такие данные применяются для:

  • симуляции пользовательской активности
  • тестирования кластеризации
  • генерации демо-данных

Кластеризация точек

При работе с большим количеством объектов Leaflet часто использует кластеризацию, а Turf.js помогает предварительно анализировать плотность.

const points = turf.randomPoint(200, {
  bbox: [37.5, 55.7, 37.8, 55.9]
});

L.geoJSON(points, {
  pointToLayer: (feature, latlng) => {
    return L.circleMarker(latlng, {
      radius: 4
    });
  }
}).addTo(map);

Дополнительно можно вычислять плотность:

const clustered = turf.clustersDbscan(points, 0.5, {
  units: 'kilometers'
});

Геометрические преобразования

Turf.js предоставляет операции трансформации объектов:

const poly = turf.polygon([[
  [37.6, 55.75],
  [37.7, 55.75],
  [37.7, 55.80],
  [37.6, 55.80],
  [37.6, 55.75]
]]);

const scaled = turf.transformScale(poly, 1.5);

Результат легко визуализируется через Leaflet:

L.geoJSON(scaled, {
  style: { color: 'purple', fillOpacity: 0.3 }
}).addTo(map);

Слойные структуры и управление GeoJSON

Leaflet предоставляет мощный механизм управления слоями, который напрямую работает с GeoJSON-структурами Turf.js.

const geoLayer = L.geoJSON(null, {
  style: feature => ({
    color: feature.properties.color || 'blue'
  })
}).addTo(map);

geoLayer.addData(turf.point([37.61, 55.75]));
geoLayer.addData(turf.point([37.62, 55.76]));

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

  • динамического обновления данных
  • потоковой загрузки геометрий
  • интерактивных аналитических интерфейсов

Работа с линиями и маршрутизацией

Turf.js позволяет интерполировать точки вдоль линии:

const route = turf.lineString([
  [37.618, 55.751],
  [37.62, 55.76],
  [37.65, 55.78]
]);

const segment = turf.along(route, 2, { units: 'kilometers' });

В Leaflet:

L.geoJSON(route, { color: 'blue' }).addTo(map);
L.geoJSON(segment, { color: 'red' }).addTo(map);

Анализ внутри полигона

Проверка принадлежности точки:

const pt = turf.point([37.618423, 55.751244]);

const poly = turf.polygon([[
  [37.6, 55.75],
  [37.7, 55.75],
  [37.7, 55.80],
  [37.6, 55.80],
  [37.6, 55.75]
]]);

const inside = turf.booleanPointInPolygon(pt, poly);

Используется для:

  • геозон доступа
  • ограничения пользовательских действий
  • аналитики распределения объектов

Производительность при больших наборах данных

При интеграции Turf.js с Leaflet ключевым фактором становится оптимизация:

  • предварительная фильтрация данных через bounding box
  • использование кластеризации вместо отдельных маркеров
  • ограничение частоты пересчётов геометрий
  • использование Web Workers для тяжёлых операций Turf.js

Пример фильтрации:

const bbox = [37.5, 55.7, 37.8, 55.9];

const filtered = points.features.filter(p =>
  turf.booleanPointInPolygon(p, turf.bboxPolygon(bbox))
);

Комбинирование динамических слоёв и аналитики

Связка Leaflet и Turf.js позволяет строить интерактивные аналитические интерфейсы, где каждое изменение карты сопровождается перерасчётом геометрий.

map.on('click', (e) => {
  const clicked = turf.point([e.latlng.lng, e.latlng.lat]);
  const buffer = turf.buffer(clicked, 3, { units: 'kilometers' });

  L.geoJSON(buffer, {
    style: { color: 'cyan', fillOpacity: 0.2 }
  }).addTo(map);
});

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

  • анализа пользовательских кликов
  • построения зон влияния в реальном времени
  • интерактивных гео-дашбордов