Пространственная и атрибутивная выборка в Turf.js опирается на работу с объектами GeoJSON и набором предикативных функций, которые позволяют отбирать геометрии по географическим отношениям и свойствам. В основе лежит идея разделения фильтрации на два независимых слоя: проверку геометрии и проверку атрибутов.
Turf.js работает с типами GeoJSON:
FeatureFeatureCollectionPoint, LineString, Polygon и
их многовариантные формыКаждый объект содержит:
geometry)properties)Выборка объектов почти всегда реализуется как преобразование
FeatureCollection в новый набор объектов, удовлетворяющих
заданным условиям.
const points = turf.featureCollection([
turf.point([30, 50], { id: 1, type: "A" }),
turf.point([31, 51], { id: 2, type: "B" }),
turf.point([32, 52], { id: 3, type: "A" })
]);
Атрибутивная фильтрация не зависит от геометрии и выполняется стандартными средствами JavaScript. Turf.js не предоставляет отдельного API для фильтрации по свойствам, поскольку GeoJSON уже совместим с функциональными подходами языка.
const filtered = turf.featureCollection(
points.features.filter(f => f.properties.type === "A")
);
Такой подход применяется как базовый этап перед пространственными вычислениями, снижая объём данных.
Типовые сценарии:
type, class)const filtered = turf.featureCollection(
points.features.filter(f => f.properties.id > 1)
);
Основная сила Turf.js заключается в геометрических проверках. Они
реализованы через булевы функции, возвращающие true или
false.
Функция booleanPointInPolygon определяет принадлежность
точки области.
const pt = turf.point([30, 50]);
const poly = turf.polygon([[
[29, 49],
[33, 49],
[33, 53],
[29, 53],
[29, 49]
]]);
const result = turf.booleanPointInPolygon(pt, poly);
Этот предикат используется для:
booleanIntersects проверяет наличие любого пересечения
между объектами.
const line = turf.lineString([[30, 50], [35, 55]]);
const polygon = poly;
const intersects = turf.booleanIntersects(line, polygon);
Применяется при:
booleanWithin проверяет, находится ли один объект
полностью внутри другого.
const smallPoly = turf.polygon([[
[30.5, 50.5],
[31, 50.5],
[31, 51],
[30.5, 51],
[30.5, 50.5]
]]);
const isInside = turf.booleanWithin(smallPoly, poly);
Разница между within и pointInPolygon
заключается в поддержке любых геометрий, а не только точек.
На практике пространственная выборка почти всегда комбинируется с атрибутивной.
const selected = points.features.filter(f => {
return f.properties.type === "A" &&
turf.booleanPointInPolygon(f, poly);
});
const result = turf.featureCollection(selected);
Такой подход формирует базовую модель пространственно-атрибутивного запроса.
Для оптимизации вычислений часто используется ограничивающий прямоугольник (bbox). Он позволяет быстро исключить заведомо неподходящие объекты до точных проверок.
const bbox = turf.bbox(poly);
const candidate = points.features.filter(f => {
const [x, y] = f.geometry.coordinates;
return x >= bbox[0] && x <= bbox[2] &&
y >= bbox[1] && y <= bbox[3];
});
После этого выполняется точная проверка:
const final = candidate.filter(f =>
turf.booleanPointInPolygon(f, poly)
);
Такой двухэтапный подход существенно снижает вычислительную нагрузку при больших наборах данных.
Для линейных и полигональных объектов используются те же предикаты, но интерпретация результатов отличается.
const roads = turf.featureCollection([
turf.lineString([[30, 50], [31, 51]]),
turf.lineString([[40, 60], [41, 61]])
]);
const clipped = roads.features.filter(f =>
turf.booleanIntersects(f, poly)
);
Здесь происходит выбор всех линий, которые хотя бы частично попадают в заданную область.
Часто требуется не только включение, но и исключение объектов:
const excluded = points.features.filter(f =>
!turf.booleanPointInPolygon(f, poly)
);
Инверсия используется при:
Сложные запросы строятся через комбинацию нескольких предикатов.
const selected = points.features.filter(f => {
const inPolygon = turf.booleanPointInPolygon(f, poly);
const isTypeA = f.properties.type === "A";
const idRange = f.properties.id >= 10 && f.properties.id <= 100;
return inPolygon && isTypeA && idRange;
});
Такая структура позволяет моделировать SQL-подобные запросы без отдельной базы данных.
При работе с большими коллекциями критично уменьшать количество геометрических операций. Используются следующие подходы:
Разделение FeatureCollection по типам или регионам:
const grouped = points.features.reduce((acc, f) => {
const key = f.properties.type;
if (!acc[key]) acc[key] = [];
acc[key].push(f);
return acc;
}, {});
Как промежуточный слой перед boolean* функциями.
Повторное использование полигонов без пересоздания объектов снижает накладные расходы.
Хотя задача поиска ближайших объектов относится к ранжированию, она часто используется как форма выборки.
const from = turf.point([30, 50]);
const nearest = points.features
.map(f => ({
feature: f,
dist: turf.distance(from, f)
}))
.sort((a, b) => a.dist - b.dist)
.slice(0, 5)
.map(x => x.feature);
Выборка часто организуется как последовательность преобразований:
const result = turf.featureCollection(
points.features
.filter(f => f.properties.type === "A")
.filter(f => {
const [x, y] = f.geometry.coordinates;
return x > 29 && x < 35 && y > 49 && y < 53;
})
.filter(f => turf.booleanPointInPolygon(f, poly))
);
При сопоставлении двух FeatureCollection используется двойной цикл или оптимизированные структуры.
const result = [];
for (const a of collectionA.features) {
for (const b of collectionB.features) {
if (turf.booleanIntersects(a, b)) {
result.push(a);
break;
}
}
}
Такая модель применяется в задачах:
Комбинация booleanPointInPolygon,
booleanIntersects, booleanWithin и
атрибутивных условий формирует универсальный механизм выборки, который
заменяет специализированные запросы баз данных в прикладных сценариях
обработки геоданных в JavaScript.