Архитектура Turf.js основана на функциональной композиции и работе с GeoJSON-структурами. Каждый модуль представляет собой чистую функцию, принимающую геометрические объекты и возвращающую новый GeoJSON-результат без побочных эффектов. Такой подход формирует естественную основу для расширения библиотеки через внешние модули, которые в практическом использовании воспринимаются как плагины.
Ключевая особенность расширений заключается в сохранении совместимости с типами GeoJSON и внутренними утилитами Turf, такими как обработка координат, вычисление метаданных и нормализация геометрий.
В Turf.js отсутствует жёстко формализованная система регистрации плагинов. Расширение реализуется через стандартные механизмы JavaScript-модулей:
Плагин в контексте Turf.js — это модуль, который:
Типовой модуль расширения строится вокруг одной или нескольких геопространственных функций.
import { featureCollection } from "@turf/helpers";
import bbox from "@turf/bbox";
/**
* Пользовательская функция пространственной обработки
*/
export function customEnvelope(features) {
const bounds = bbox(features);
const [minX, minY, maxX, maxY] = bounds;
return featureCollection([
{
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [[
[minX, minY],
[maxX, minY],
[maxX, maxY],
[minX, maxY],
[minX, minY]
]]
},
properties: {}
}
]);
}
В данном случае используется стандартная функция bbox, а
результат формируется вручную через featureCollection.
Подобный подход сохраняет совместимость с экосистемой Turf.
Turf предоставляет набор вспомогательных модулей, которые часто используются при создании расширений:
@turf/helpers — создание GeoJSON объектов@turf/invariant — проверка типов входных данных@turf/meta — итерация по координатам и геометриям@turf/boolean-* — пространственные предикаты@turf/distance, @turf/area — базовые
измеренияПример использования @turf/meta:
import { coordEach } from "@turf/meta";
/**
* Подсчёт общего количества координат во всех геометриях
*/
export function countCoordinates(geojson) {
let count = 0;
coordEach(geojson, () => {
count += 1;
});
return count;
}
Использование coordEach обеспечивает корректную работу
со всеми типами геометрий без необходимости ручного обхода вложенных
структур.
Одной из ключевых задач при создании расширений является валидация GeoJSON. Turf использует строгую модель типов, и нарушение структуры приводит к некорректным результатам.
import { isGeoJSON } from "@turf/invariant";
/**
* Проверка корректности входного объекта
*/
export function safeProcess(input) {
if (!isGeoJSON(input)) {
throw new Error("Некорректный GeoJSON объект");
}
return input;
}
Такая проверка предотвращает попадание в вычисления структур, не соответствующих спецификации GeoJSON.
Расширения Turf часто строятся как композиция существующих функций. Это позволяет избегать дублирования логики и повышает предсказуемость поведения.
import area from "@turf/area";
import centroid from "@turf/centroid";
/**
* Обогащение геометрии метаданными
*/
export function enrichWithMetrics(feature) {
const computedArea = area(feature);
const center = centroid(feature);
return {
...feature,
properties: {
...feature.properties,
area: computedArea,
center: center.geometry.coordinates
}
};
}
Функциональная композиция позволяет создавать расширения без модификации исходных объектов библиотеки.
Для удобства распространения расширений часто формируется единый объект, имитирующий структуру Turf.
import * as helpers from "@turf/helpers";
import { customEnvelope } from "./customEnvelope";
import { enrichWithMetrics } from "./metrics";
export const myTurf = {
...helpers,
customEnvelope,
enrichWithMetrics
};
Такой подход позволяет использовать расширения как единый модуль:
myTurf.customEnvelope(data);
Большинство плагинов ориентировано на обработку коллекций объектов. FeatureCollection является базовым контейнером в Turf.
import { featureCollection } from "@turf/helpers";
/**
* Фильтрация объектов по произвольному условию
*/
export function filterFeatures(collection, predicate) {
const filtered = collection.features.filter(predicate);
return featureCollection(filtered);
}
Сохранение структуры FeatureCollection критично для совместимости с другими функциями Turf.
Расширения Turf должны учитывать производительность при работе с большими наборами геоданных. Основные принципы:
Пример оптимизированной обработки:
import { coordEach } from "@turf/meta";
/**
* Быстрое преобразование координат без создания промежуточных структур
*/
export function shiftCoordinates(geojson, dx, dy) {
coordEach(geojson, (coord) => {
coord[0] += dx;
coord[1] += dy;
});
return geojson;
}
Несмотря на прямую модификацию координат, подобные операции допустимы при контролируемом использовании, если входной объект заранее клонирован.
Для расширений, ориентированных на промышленное использование, типизация играет ключевую роль.
import { Feature, FeatureCollection, Polygon } from "geojson";
export function validatePolygon(
feature: Feature<Polygon>
): boolean {
return feature.geometry.type === "Polygon";
}
Типизация GeoJSON позволяет избежать ошибок на этапе компиляции и улучшает интеграцию с редакторами кода.
Плагины Turf обычно оформляются как отдельные npm-пакеты с минимальной зависимостью от внешнего состояния.
Типичная структура пакета:
turf-custom-plugin/
├── src/
│ ├── index.js
│ ├── metrics.js
│ └── envelope.js
├── package.json
├── README.md
Основной файл экспорта:
export { customEnvelope } from "./envelope";
export { enrichWithMetrics } from "./metrics";
Корректно реализованные расширения учитывают следующие принципы:
Подобные требования обеспечивают интеграцию плагинов в существующие геопространственные пайплайны без необходимости модификации базовой библиотеки.