经纬志
首页 / Turf.js / 教程

空间分析基础

先看结论

Turf.js 不画地图,只做计算。输入几何,输出几何或数字, 所以它可以跑在浏览器、Node、甚至一个没有 DOM 的测试环境里。 把数据模型和单位搞清楚,后面的每个函数都不难。

最后验证 2026-11-03 · Turf.js 7.x · 更新 2026-10-27 · 引用本文

它解决的是什么问题

前端做 GIS 经常遇到一类需求:判断一个坐标是否落在某个园区里、把一条路线切成等距的点、 统计两个区的重叠面积。这些逻辑如果用经纬度自己写,很快会撞上球面距离、多边形环方向、 坐标顺序这些细节。Turf 把这些算法封装成一个个纯函数,返回值仍然是标准 GeoJSON, 可以直接塞给 Leaflet、MapLibre 或后端接口。

引入与第一个计算

浏览器里用一个 script 标签就够,全局变量是 turf。

<script src="https://cdn.jsdelivr.net/npm/@turf/turf@7/turf.min.js"></script>
<script>
  var a = turf.point([116.391263, 39.907359]);   // 天安门
  var b = turf.point([121.473701, 31.230416]);   // 上海人民广场

  var km = turf.distance(a, b, { units: 'kilometers' });
  console.log(km);   // 1067 左右,单位为公里
</script>

turf.point 的第一个参数是 [经度, 纬度]。 顺序写反不会报错,只会算出一个位于南极附近的荒谬结果。

GeoJSON 是唯一的数据接口

所有函数都接受 GeoJSON 对象。三种常见形态都能用:

形态示例说明
Geometry { type: 'Point', coordinates: [116.39, 39.90] } 只有几何,没有属性;距离、面积这类函数直接用得上
Feature { type: 'Feature', properties: {}, geometry: {...} } 地理要素的标准形态,绝大多数函数的返回类型
FeatureCollection { type: 'FeatureCollection', features: [...] } 批量统计、网格、聚合函数的常见输入

多数函数对 Geometry 和 Feature 都做了兼容,但少数只接受 Feature。 统一用 turf.feature() 包一层,可以免去在不同版本间试错的时间。

var geom = { type: 'Point', coordinates: [116.391263, 39.907359] };
var feat = turf.feature(geom, { name: '天安门' });

console.log(feat.properties.name);   // 天安门

构造要素的四个常用函数

var p  = turf.point([116.39, 39.90], { name: 'A' });
var l  = turf.lineString([[116.39, 39.90], [116.42, 39.92], [116.46, 39.94]]);
var poly = turf.polygon([[
  [116.35, 39.86], [116.48, 39.86], [116.48, 39.96],
  [116.35, 39.96], [116.35, 39.86]        // 首尾必须相同
]]);
var fc = turf.featureCollection([p, l, poly]);

多边形的每个环都要闭合:第一个坐标和最后一个坐标完全一致。 漏掉闭合点,turf.area 仍会算出一个数,但结果偏小, 而 turf.booleanPointInPolygon 在边界附近的判断会变得不稳定。

单位:默认公里,面积恒为平方米

这是 Turf 里最容易出错的一处约定。带距离概念的函数默认用公里, 通过 options.units 可以改成 meters、 miles、nauticalmiles;而 turf.area 没有 units 参数,返回值永远是平方米。

函数默认输出单位是否可改
distance公里可以,units
length公里可以,units
buffer 的半径公里可以,units
area平方米不行,始终是平方米
bbox度(经纬度数值)不行

把平方米换算成平方公里要除以 1e6,换公顷除以 1e4。 写成 turf.area(poly) / 1000000 比记单位换算表更不容易错。

球面计算,不是平面像素

Turf 的距离基于 WGS84 球面上的大圆距离,面积基于球面多边形, 所以同一块区域的面积不会随地图缩放或投影变化。 这也意味着它和按 Web 墨卡托平面量出来的结果对不上,尤其在高纬度。 用栅格切片统计出来的面积与 Turf 结果有差异时,先确认统计所用的坐标系, 而不是怀疑算法本身。

精度不是无限的。球面公式把地球当正球体,长距离测距与椭球体结果相差千分之几。 要求毫米级时应当用投影后的平面坐标配合专业库,Turf 的定位是前端交互与快速判断。

结果怎么校验

计算完不要直接上屏。两类检查成本最低:

  • 坐标范围:经度应在 -180 到 180,纬度在 -90 到 90,越界基本是顺序写反。
  • 量级:城市级距离是几十公里,省级是几百公里,跨国是几千公里,数量级明显不对就先查单位。
function safeDistance(a, b) {
  var km = turf.distance(a, b, { units: 'kilometers' });
  if (!isFinite(km) || km <= 0) return null;
  return Math.round(km * 1000);   // 统一成米,避免上层再猜单位
}

常见错误

把 [lat, lng] 传给 Turf

Leaflet 的 L.latLng、map.getCenter() 返回的是纬度在前。 直接把 [lat, lng] 交给 Turf,会把北京算到印度洋。 转换用 [lng, lat] 显式重排,不要依赖隐式转换。

在循环里反复构造 Feature

一万个点逐个调用 turf.point 再判断,对象分配的开销会超过计算本身。 先把坐标数组准备好,批量处理时只构造一次 FeatureCollection。

把 undefined 当成 false

函数名拼错时 turf.xxx 是 undefined,调用会抛错; 而拼错的属性用在条件里会静默得到假值,页面看起来「判断永远不成立」。 引入后先确认函数存在,再处理业务逻辑。

引用本文

经纬志(2026)。《空间分析基础》。https://www.jingweizhi.com/turf/tutorial/basics.html(访问日期 2026-11-03)。