Библиотека Turf.js построена как набор независимых модулей, каждый из которых реализует одну геопространственную операцию над данными формата GeoJSON. Такой подход позволяет формировать собственные функции, следуя тем же соглашениям: чистые входы и выходы, отсутствие скрытого состояния, строгая работа с геометриями.
Основой расширяемости является унифицированная модель данных GeoJSON
и набор вспомогательных утилит из пакетов @turf/invariant,
@turf/helpers, @turf/meta. Эти инструменты
обеспечивают безопасное извлечение координат, нормализацию геометрий и
итерацию по структурам разного уровня вложенности.
Любая функция, совместимая с экосистемой Turf.js, опирается на несколько обязательных правил:
1. Единый входной формат Все входные данные представлены как GeoJSON:
Feature<Point>Feature<LineString>Feature<Polygon>FeatureCollection2. Чистота функции Отсутствие побочных эффектов. Функция не изменяет входные данные, а возвращает новый объект.
3. Возврат GeoJSON Результат всегда оформляется как
валидный GeoJSON объект через @turf/helpers.
4. Поддержка коллекций Функции должны корректно обрабатывать как одиночные геометрии, так и коллекции.
В Turf.js входные данные приводятся к единому виду с помощью
@turf/invariant.
Ключевые утилиты:
getCoord — извлечение координаты из PointgetCoords — извлечение массива координатgetGeom — получение геометрииgeojsonType — проверка типа GeoJSONcollectionOf — валидация FeatureCollectionПример нормализации:
import { getGeom, geojsonType } from "@turf/invariant";
function example(feature) {
geojsonType(feature, "Feature", "example");
const geom = getGeom(feature);
return geom;
}
Такой подход предотвращает ошибки, связанные с неожиданной структурой входных данных.
Для обхода координат используются функции из
@turf/meta:
coordEachgeomEachfeatureEachsegmentEachimport { coordEach } from "@turf/meta";
function sumCoordinates(feature) {
let sum = 0;
coordEach(feature, (coord) => {
sum += coord[0] + coord[1];
});
return sum;
}
coordEach — работа на уровне координатgeomEach — работа на уровне геометрийfeatureEach — работа на уровне FeaturesegmentEach — работа с сегментами линийТиповая структура функции повторяет единый паттерн:
import { feature } from "@turf/helpers";
import { coordEach } from "@turf/meta";
import { getGeom, geojsonType } from "@turf/invariant";
function customOperation(input) {
geojsonType(input, "Feature", "customOperation");
const geom = getGeom(input);
let resultValue = 0;
coordEach(geom, (coord) => {
resultValue += coord[0] * coord[1];
});
return feature(geom, resultValue);
}
export default customOperation;
Основные элементы шаблона:
featurePoint содержит одну координату, обработка упрощается:
const [x, y] = getCoord(feature);
LineString требует работы с последовательностью точек:
coordEach(line, (coord, index) => {
// обработка сегментов линии
});
Polygon включает внешнее кольцо и внутренние отверстия:
coordEach(polygon, (coord, index, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) => {
// учет колец и дыр
});
FeatureCollection требует отдельной стратегии обработки:
import { featureCollection } from "@turf/helpers";
import { featureEach } from "@turf/meta";
function processCollection(fc) {
let results = [];
featureEach(fc, (feature) => {
results.push(feature);
});
return featureCollection(results);
}
При проектировании функций важно учитывать возможность вложенных структур и MultiGeometry.
Turf.js предоставляет вспомогательные геометрические функции, которые часто используются внутри пользовательских реализаций:
Пример использования расстояния:
import distance from "@turf/distance";
function totalPathLength(line) {
let total = 0;
coordEach(line, (coord, index, coords) => {
if (index > 0) {
total += distance(coords[index - 1], coord);
}
});
return total;
}
При разработке функций критично учитывать корректность GeoJSON.
Основные проверки:
Feature,
FeatureCollection)import { geojsonType } from "@turf/invariant";
function safeFunction(input) {
geojsonType(input, "FeatureCollection", "safeFunction");
// дальнейшая обработка
}
Дополнительно может использоваться ручная проверка координат:
if (!Array.isArray(coord) || coord.length < 2) {
return null;
}
При обработке крупных FeatureCollection критичны следующие аспекты:
1. Минимизация аллокаций Избегается создание промежуточных массивов внутри циклов.
2. Использование meta-итераторов
coordEach и featureEach работают быстрее
ручных рекурсий.
3. Ранний выход При поиске условий допускается прерывание обработки через исключения или флаги.
let found = false;
coordEach(feature, (coord) => {
if (coord[0] > 1000) {
found = true;
}
});
При расширении Turf.js в TypeScript определяется строгая сигнатура входов и выходов:
import { Feature, Geometry } from "geojson";
export default function custom(
input: Feature<Geometry>
): Feature<Geometry | null> {
return input;
}
Типизация помогает зафиксировать:
Каждая пользовательская функция оформляется как самостоятельный модуль:
/custom-function
index.js
index.d.ts
test.js
package.json
Стандартный экспорт:
export default function customFunction(input) {
return input;
}
Такой формат обеспечивает совместимость с экосистемой Turf и позволяет интеграцию через npm-пакеты.
Внутри собственных реализаций часто применяются утилиты:
@turf/helpers — создание Feature и
FeatureCollection@turf/meta — обход структур@turf/invariant — проверка и нормализация@turf/bbox — вычисление границПример с bounding box:
import bbox from "@turf/bbox";
function envelopeArea(feature) {
const [minX, minY, maxX, maxY] = bbox(feature);
return (maxX - minX) * (maxY - minY);
}
Сильной стороной Turf.js является композиция модулей. Пользовательские функции часто строятся как цепочки операций:
function composed(input) {
const step1 = transform(input);
const step2 = filter(step1);
return aggregate(step2);
}
Каждый шаг остается чистым GeoJSON-преобразованием, что сохраняет предсказуемость поведения и упрощает отладку.