还在用老方法计算面积距离?Turf.js文档核心API速查(附实战案例)

编程与开发
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

如果你在 WebGIS 项目里还在用老方法计算面积距离?Turf.js文档核心API速查(附实战案例)这篇文章可以帮你快速切换到更稳定、更适合前端地图的做法。Turf.js 是一个常用于浏览器和 Node.js 环境的 JavaScript 空间分析库,适合处理 GeoJSON 数据的距离、面积、缓冲区、叠加分析、点线面判断等任务。

本文不做泛泛的 API 罗列,而是围绕 GIS 开发中最常见的几个问题:测距、算面积、判断点是否在面内、生成缓冲区、裁剪叠加和统计分析,整理 Turf.js 文档里的核心 API,并给出可直接改造到 Leaflet、OpenLayers 或 Mapbox GL JS 项目中的实战写法。

Turf.js文档核心API速查 Turf.js计算面积距离流程图
Turf.js 在 WebGIS 前端中的典型使用流程:GeoJSON 输入、空间分析计算、地图渲染输出。

引言:为什么 WebGIS 项目需要 Turf.js 文档核心API速查

很多 GIS 初学者或前端开发者在实现地图测距、面积统计时,习惯自己写球面距离公式,或者把数据传回后端 GIS 服务计算。这样并不是不能用,但在交互式 WebGIS 场景下,经常会遇到三个问题:

  • 代码分散,面积、距离、缓冲区、空间判断各写一套逻辑。
  • 坐标单位、投影单位、球面距离混用,导致结果不稳定。
  • 每次交互都请求后端,前端响应慢,用户体验差。

Turf.js 的优势在于:它直接以 GeoJSON 为输入输出格式,和 WebGIS 前端天然兼容。只要你的地图数据可以转成 GeoJSON,就可以用 Turf.js 快速完成轻量级空间分析。

建议把 Turf.js 理解为“前端空间分析工具箱”,而不是完整替代 PostGIS、ArcGIS Server 或 GeoServer 的 GIS 引擎。它适合轻量、实时、交互式分析,不适合超大规模批处理。

背景:Turf.js 适合解决哪些 GIS 问题

Turf.js 最常见的使用场景集中在 WebGIS 前端交互分析。比如用户在地图上画一条线后,需要立即显示长度;圈选一个区域后,需要计算面积;点击一个点后,需要判断它属于哪个行政区;上传一个 GeoJSON 后,需要快速做缓冲区分析。

这些需求有一个共同点:数据量通常不大,但要求即时反馈。此时如果每一步都调用后端空间数据库,开发成本和交互延迟都会增加。Turf.js 正好适合放在前端完成这些中小规模计算。

常见应用场景

  • 地图测距:计算线段长度、两点距离、路径总长度。
  • 面积统计:计算用户绘制面、行政区面、地块面的面积。
  • 空间查询:判断点是否在多边形内,筛选落入范围内的点。
  • 缓冲区分析:围绕点、线、面生成一定距离范围。
  • 叠加分析:计算相交区域、裁剪范围、合并面要素。
  • 数据辅助处理:获取中心点、边界框、随机点、简化线面。

原理:使用 Turf.js 计算面积距离前必须理解的三件事

在看 Turf.js 文档核心 API 之前,先理解三个基本概念,可以避免大部分面积和距离计算错误。

1. Turf.js 主要处理 GeoJSON

GeoJSON 是 WebGIS 中常见的空间数据格式。Turf.js 的函数通常接收 GeoJSON 的 Feature、FeatureCollection、Geometry 作为参数,并返回新的 GeoJSON 对象或数值结果。

const point = turf.point([116.391, 39.907]);
const line = turf.lineString([
  [116.391, 39.907],
  [116.401, 39.917]
]);

这里的坐标顺序是 [经度, 纬度],也就是 [longitude, latitude]。这是很多新手最容易写反的地方。

2. 距离和面积不要直接按经纬度做平面计算

经纬度坐标的单位是度,不是米。如果直接用普通平面几何公式计算面积距离,结果通常不可靠。Turf.js 的 distancelengtharea 等函数会按地理坐标场景进行处理,更适合 WebGIS 常见的 WGS84 经纬度数据。

但要注意:如果你的数据已经是投影坐标,比如 CGCS2000 高斯投影、Web Mercator 米制坐标,使用 Turf.js 前要确认坐标是否需要转换为经纬度 GeoJSON。

3. 前端空间分析要控制数据规模

Turf.js 可以在浏览器里运行,但浏览器不是空间数据库。几百、几千个要素的交互分析通常没问题;如果你要对几十万条道路、上百万个点做叠加分析,应优先考虑 PostGIS、GeoPandas、ArcGIS Pro 或服务端 GIS 引擎。

步骤:Turf.js 文档核心API速查与实战写法

下面按实际开发频率整理 Turf.js 核心 API。示例均以浏览器或现代前端项目中常见的写法为主。

步骤 1:安装或引入 Turf.js

如果你使用 Vite、Vue、React、Webpack 等现代前端工程,推荐通过 npm 安装:

npm install @turf/turf

在代码中引入:

import * as turf from '@turf/turf';

如果是传统 HTML 页面,也可以通过 CDN 引入:

<script src="https://cdn.jsdelivr.net/npm/@turf/turf@7/turf.min.js"></script>

实际项目中建议固定版本号,避免线上依赖因版本变化导致 API 行为不一致。

步骤 2:计算两点距离 distance

turf.distance 用于计算两个点之间的距离。它非常适合点击地图两个位置后显示直线距离。

const from = turf.point([116.391, 39.907]);
const to = turf.point([116.421, 39.932]);

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

console.log('距离(千米):', distanceKm);
console.log('距离(米):', distanceM);

常用单位包括 kilometersmetersmiles。在中文 GIS 项目中,建议统一使用米或千米,并在界面上明确显示单位。

步骤 3:计算线长度 length

turf.length 用于计算 LineString 或 MultiLineString 的长度,适合路线长度、巡检路径长度、河流长度等场景。

const route = turf.lineString([
  [116.391, 39.907],
  [116.401, 39.917],
  [116.421, 39.932]
]);

const length = turf.length(route, { units: 'kilometers' });

console.log('路线长度(千米):', length);

如果你在 Leaflet 或 OpenLayers 中让用户绘制折线,可以把绘制结果转为 GeoJSON 后交给 turf.length 计算。

步骤 4:计算多边形面积 area

turf.area 是 Turf.js 计算面积最常用的 API。它返回的面积单位是平方米。

const polygon = turf.polygon([[
  [116.391, 39.907],
  [116.421, 39.907],
  [116.421, 39.927],
  [116.391, 39.927],
  [116.391, 39.907]
]]);

const areaM2 = turf.area(polygon);
const areaKm2 = areaM2 / 1000000;

console.log('面积(平方米):', areaM2);
console.log('面积(平方千米):', areaKm2);

注意多边形坐标环必须闭合,也就是第一个坐标点和最后一个坐标点相同。很多面积计算失败或结果异常,都是因为面要素坐标环不合法。

步骤 5:判断点是否在面内 booleanPointInPolygon

turf.booleanPointInPolygon 用于判断一个点是否位于多边形内部,常用于行政区归属判断、围栏告警、点位筛选。

const pt = turf.point([116.400, 39.915]);

const district = turf.polygon([[
  [116.391, 39.907],
  [116.421, 39.907],
  [116.421, 39.927],
  [116.391, 39.927],
  [116.391, 39.907]
]]);

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

console.log('点是否在面内:', inside);

如果点正好落在边界上,要结合业务规则判断是否算作“在范围内”。不同系统对边界点的处理可能不同,建议在需求文档中写清楚。

步骤 6:生成缓冲区 buffer

turf.buffer 可以围绕点、线或面生成指定距离的缓冲区。它常用于服务半径、道路影响范围、设施覆盖范围分析。

const school = turf.point([116.391, 39.907]);

const buffer = turf.buffer(school, 500, { units: 'meters' });

console.log(buffer);

如果你要把缓冲区显示到地图上,直接把返回的 GeoJSON 添加到图层即可。需要注意的是,缓冲区结果通常是 Polygon 或 MultiPolygon,点数可能比原始数据多,会增加前端渲染压力。

步骤 7:计算相交区域 intersect

turf.intersect 用于计算两个面要素的相交部分。适合判断两个区域是否重叠,或计算重叠面积。

const areaA = turf.polygon([[
  [116.391, 39.907],
  [116.421, 39.907],
  [116.421, 39.927],
  [116.391, 39.927],
  [116.391, 39.907]
]]);

const areaB = turf.polygon([[
  [116.405, 39.915],
  [116.435, 39.915],
  [116.435, 39.935],
  [116.405, 39.935],
  [116.405, 39.915]
]]);

const fc = turf.featureCollection([areaA, areaB]);
const intersection = turf.intersect(fc);

if (intersection) {
  const overlapArea = turf.area(intersection);
  console.log('相交面积(平方米):', overlapArea);
} else {
  console.log('两个区域不相交');
}

不同 Turf.js 版本中部分叠加分析函数的参数形式可能有变化。实际项目中请以当前安装版本的官方文档为准,并在升级依赖后补充单元测试。

步骤 8:筛选范围内点 pointsWithinPolygon

turf.pointsWithinPolygon 可以从点集合中筛选落入多边形范围内的点。它常用于门店圈选、监测点统计、兴趣点筛选。

const points = turf.featureCollection([
  turf.point([116.400, 39.915], { name: '点A' }),
  turf.point([116.450, 39.950], { name: '点B' })
]);

const polygon = turf.polygon([[
  [116.391, 39.907],
  [116.421, 39.907],
  [116.421, 39.927],
  [116.391, 39.927],
  [116.391, 39.907]
]]);

const selected = turf.pointsWithinPolygon(points, polygon);

console.log('范围内点数量:', selected.features.length);
console.log(selected);

步骤 9:获取中心点 center、centroid、centerOfMass

Turf.js 里有多个“中心点”相关 API,容易混淆:

  • turf.center:根据要素边界框计算中心点。
  • turf.centroid:根据顶点平均位置计算质心。
  • turf.centerOfMass:更接近几何面质量中心的计算方式。
const poly = turf.polygon([[
  [116.391, 39.907],
  [116.421, 39.907],
  [116.421, 39.927],
  [116.391, 39.927],
  [116.391, 39.907]
]]);

const c1 = turf.center(poly);
const c2 = turf.centroid(poly);
const c3 = turf.centerOfMass(poly);

console.log(c1, c2, c3);

如果只是地图定位到区域中心,通常用 center 就够了。如果要给面状地块放置标注,建议实际测试 centroidcenterOfMass 的显示效果。

步骤 10:简化线面 simplify

turf.simplify 用于减少线或面的节点数量,适合 WebGIS 前端性能优化。

const simplified = turf.simplify(polygon, {
  tolerance: 0.001,
  highQuality: false
});

console.log(simplified);

tolerance 越大,简化越明显,但形状失真也越大。对于行政边界、地块边界等严肃业务数据,不建议在未评估误差的情况下直接简化后参与面积统计。

常见坑:Turf.js计算面积距离结果不对的原因

坑 1:经纬度顺序写反

GeoJSON 坐标顺序是 [经度, 纬度],不是很多地图 API 页面上常见的“纬度、经度”描述。如果把北京坐标写成 [39.907, 116.391],点会跑到错误位置,后续面积距离计算全部失真。

坑 2:把投影坐标当经纬度传给 Turf.js

如果你的坐标类似 [12958175, 4852341],很可能是 Web Mercator 或其他米制投影坐标,不是经纬度。此时直接用 Turf.js 的距离、面积函数,结果会很容易异常。

处理建议:

  • 确认数据坐标系,尤其是 EPSG 代码。
  • 前端分析前尽量转换为 WGS84 经纬度 GeoJSON。
  • 如果需要严格投影面积,考虑在后端用 PostGIS 或 GDAL 处理。

坑 3:多边形没有闭合或自相交

GeoJSON Polygon 的每个线性环必须闭合。自相交多边形、重复点、空洞环方向错误等问题,都会让面积和叠加分析结果变得不可靠。

在生产环境中,建议对用户绘制或上传的数据做合法性校验。对于复杂面数据,可以在服务端用 PostGIS 的 ST_IsValidST_MakeValid 或 GIS 桌面软件先清洗。

坑 4:用 Turf.js 处理过大的数据集

Turf.js 运行在浏览器时,会占用用户设备的 CPU 和内存。点面筛选、缓冲区、叠加分析在数据量大时非常消耗性能。如果页面卡顿,不要只怀疑地图框架,也要检查 Turf.js 分析的数据量。

坑 5:忽略单位参数

distancelengthbuffer 等函数都和单位有关。团队开发时建议封装统一函数,避免有人用米,有人用千米,最后导致结果差 1000 倍。

方法比较:Turf.js、PostGIS、ArcGIS Pro 和 GeoPandas 怎么选

方法 适合场景 优势 限制
Turf.js WebGIS 前端轻量分析、交互测量、范围筛选 直接处理 GeoJSON,前端响应快,集成简单 不适合超大数据量和高精度复杂空间分析
PostGIS 服务端空间查询、海量数据筛选、空间索引分析 性能强,可建空间索引,适合生产数据库 需要数据库和后端接口支持
ArcGIS Pro 桌面 GIS 制图、专业空间分析、批处理建模 工具完整,适合规范化 GIS 作业 不适合直接承担前端实时交互计算
GeoPandas Python 数据分析、批量矢量处理、科研统计 适合脚本化处理和数据分析流程 需要 Python 环境,对前端交互不直接友好

简单判断:如果是浏览器里即时反馈的小规模空间分析,优先用 Turf.js;如果是海量数据查询和严肃业务统计,优先用 PostGIS 或后端 GIS 服务;如果是离线制图和批处理,ArcGIS Pro、QGIS、GeoPandas 更合适。

检查清单:上线前如何检查 Turf.js 面积距离功能

  • 坐标顺序:确认所有 GeoJSON 坐标都是 [经度, 纬度]
  • 坐标系:确认输入数据是否为 WGS84 经纬度,避免投影坐标误用。
  • 单位:统一距离和缓冲区单位,界面显示与计算单位一致。
  • 几何合法性:检查多边形是否闭合,是否存在自相交或空几何。
  • 数据规模:避免在浏览器中一次性叠加分析超大数据集。
  • 边界规则:明确点落在面边界时是否算作在范围内。
  • 版本锁定:固定 @turf/turf 版本,升级前回归测试核心 API。
  • 结果校验:用 QGIS、ArcGIS Pro 或 PostGIS 抽样对比关键计算结果。

FAQ:Turf.js文档核心API常见问题

Turf.js 计算面积准吗?

对于常见 WebGIS 经纬度 GeoJSON 的轻量面积计算,turf.area 可以满足很多前端展示和交互统计需求。但如果涉及法定面积、工程测量、地籍权属等高精度业务,应使用合适的投影坐标系,并在专业 GIS 软件或后端空间分析环境中计算和复核。

Turf.js 计算距离应该用 distance 还是 length?

两点之间的直线距离用 turf.distance;一条折线或路径的总长度用 turf.length。如果用户在地图上画了一条多段线,应使用 length,而不是只计算起点到终点的距离。

Turf.js 能不能直接处理 Shapefile?

Turf.js 主要处理 GeoJSON,不能直接把 Shapefile 当作输入。你可以先在后端或前端使用相关工具把 Shapefile 转为 GeoJSON,再交给 Turf.js 分析。生产项目中更推荐在服务端完成格式转换和数据清洗。

Turf.js 和 Leaflet、OpenLayers 是什么关系?

Leaflet 和 OpenLayers 主要负责地图显示、图层管理和交互操作;Turf.js 负责空间分析计算。实际项目中常见做法是:用户在 Leaflet 或 OpenLayers 上绘制几何,转换成 GeoJSON 后交给 Turf.js 计算,再把结果渲染回地图。

为什么 Turf.js buffer 生成的缓冲区看起来不够圆?

缓冲区本质上是用多边形近似表达圆形或曲线区域。显示效果和分段数量、地图缩放级别、数据坐标有关。如果对视觉效果要求较高,可以检查 buffer 参数和地图渲染样式;如果对精度要求较高,应在专业 GIS 环境中验证。

Turf.js 能替代 PostGIS 吗?

不能简单替代。Turf.js 更适合前端轻量空间分析,PostGIS 更适合服务端空间数据库、空间索引、复杂查询和海量数据处理。两者在 WebGIS 架构中通常是互补关系。

结论:把 Turf.js 用在合适的位置,面积距离计算会更稳

Turf.js 文档核心API速查的重点,不是记住所有函数名,而是知道在什么场景用哪个 API。两点距离用 distance,线长度用 length,面面积用 area,点面判断用 booleanPointInPolygon,缓冲区用 buffer,范围筛选用 pointsWithinPolygon

在 WebGIS 项目中,Turf.js 非常适合承担前端轻量级空间分析任务。只要你控制好坐标系、单位、几何合法性和数据规模,就可以用更少的代码实现可靠的面积距离计算和交互分析。

最后建议把常用 Turf.js API 封装成项目内部工具函数,并配合 QGIS、PostGIS 或 ArcGIS Pro 做抽样校验。这样既能保持前端交互流畅,也能让 GIS 计算结果更可信。