当前位置: 首页 > news >正文

地图可视化实践录:空间分析库Turf.js的学习

本文介绍空间分析库Turf.js的接口,并给出实例。

知识点

Turf .js是空间分析的 JavaScript 库。它包含传统的空间操作、用于创建 GeoJSON 数据的辅助函数以及数据分类和统计工具。其涵盖空间几何图形的测量、关系判断、坐标变换和偏移、辅助方法等具体场景,功能强大。

因为Turf.js使用GeoJSON格式处理所有地理数,因此其坐标顺序为经度,纬度,与leaflet刚好相反。

Turf.js 不仅能在后端的Node.js环境中使用,也可在浏览器环境中使用,比如与 Leaflet、MapBox GL JS 等地图库配合。本文基于原来的综合示例,学习一些入门级的接口,由于是在html中调用接口,所以给出实例和对应展示效果。详细接口说明建议参考官网。

实践

下载和使用

参考https://turf.nodejs.cn/docs/getting-started文档下载,编写本文时(2025年11月),最新版本为7.2.0,具体地址:https://unpkg.com/@turf/turf@7.2.0/turf.min.js。

在html文件引入:

<script src="mymap/maptool/turf-7.2.0.min.js"></script>

点、线、面

turf.js的点、线、面,与leaflet有较多相似之处。

点:turf.point([坐标], {可选属性});

线:turf.lineString([坐标], {可选属性})

面:turf.polygon([坐标], {可选属性})

核心代码:

    const points = [[108.397293,22.738823],[108.481064,22.724890]];// 点// 注:turf.point 返回点,第二个参数可指定properties参数,drawOneLayer 函数会自动判断name,故加之const point1 = turf.point(points[0], {name: "五象湖公园"});var pointLayer1 = drawOneLayer(point1);addToLayers(pointLayer1);const point2 = turf.point(points[1], {name: "南宁园博园"});var pointLayer2 = drawOneLayer(point2);addToLayers(pointLayer2);// 线const linePoints = [[108.316269, 22.838212],[108.326569, 22.807200],[108.347168, 22.779347],[108.352661, 22.759720],[108.379440, 22.738190]];var line = turf.lineString(// [//     [108.316269, 22.838212],//     [108.326569, 22.807200],//     [108.347168, 22.779347],//     [108.352661, 22.759720],//     [108.379440, 22.738190]// ],linePoints,{color: "#FF00FF", name: "折线"});// 可指定为miles或kilometers,默认后者,可不写var totalDistance = turf.length(line, { units: "kilometers"});var lineLayer = drawOneLayer(line);addToLayers(lineLayer);// 面const polygon = turf.polygon([[[108.3, 22.86], [108.4, 22.86], [108.4, 22.9], [108.3, 22.9], [108.3, 22.86]]], {color: "#0000FF"});var polygonLayer = drawOneLayer(polygon);addToLayers(polygonLayer);

注意,drawOneLayeraddToLayers是为了显示绘制效果而调用的。效果如下图所示。
在这里插入图片描述

里程、面积计算

计算长度:turf.length(line),默认返回长度单位为千米。

计算里程:turf.distance(point1, point2),默认返回长度单位为千米。

计算面积:turf.area(polygon),返回面积单位为平方米。

核心代码:

    // 计算两点间距离const disTurf = turf.distance(point1, point2, { units: 'kilometers' });info +=`2点间距离(turfs): ${disTurf.toFixed(3)} 公里\r\n`;const disLeaflet = calcDistance(points, "km")info +=`2点间距离(leaflet): ${disLeaflet.toFixed(3)} 公里\r\n`;// 可指定为miles或kilometers,默认后者,可不写var totalDistance = turf.length(line, { units: "kilometers"});info += `线段长度: ${totalDistance.toFixed(3)} 公里\r\n`const disLeaflet2 = calcDistance(linePoints, "km")info +=`线段长度(leaflet): ${disLeaflet2.toFixed(3)} 公里\r\n`;// 计算面积const area = turf.area(polygon); // 平方米info += `面积: ${area.toFixed(3)} 平方米`;

turf使用distance计算2个经纬度的里程,用length即可计算经纬度数组的里程。leaflet也有类似的接口,其使用distanceTo计算2个经纬度里程,但没有length功能接口,下面实现之:

// 计算经纬度数组points的总里程
function calcDistance(points, units = 'km') {let totalDistance = 0;for (let i = 0; i < points.length - 1; i++) {const [lng1, lat1] = points[i];const [lng2, lat2] = points[i + 1];const distance = L.latLng(lat1, lng1).distanceTo(L.latLng(lat2, lng2));totalDistance += distance;}// 单位转换const unitConvert = {'m': (d) => d,'km': (d) => d / 1000,'mile': (d) => d / 1609.34};const convert = unitConvert[units] || unitConvert['km'];return convert(totalDistance);
}

效果图如下:

可以看到,使用turfs和leaflet计算相同经纬度里程的结果是相同的。
在这里插入图片描述

外接矩形、中心点

计算最小外接矩形:turf.bbox

计算中心点:turf.center

核心代码:

function turf_demo2() {var info = ""// 最小外接矩形var bbox = turf.bbox(gxGeoJson); // gxGeoJson 在 450000-广西壮族自治区.js 中定义var polygon = turf.bboxPolygon(bbox, {}, {color: "#0000FF"});var polygonLayer = drawOneLayer(polygon);addToLayers(polygonLayer);info += `广西最小外接矩形为 ${bbox}\r\n`// 计算中心点const center = turf.center(gxGeoJson);const latlng = center.geometry.coordinates;const point = turf.point(latlng, {name: "中心点"});var pointLayer = drawOneLayer(point);addToLayers(pointLayer);info += `中心点为 ${latlng}\r\n`// 计算总面积var totalArea = turf.area(gxGeoJson);totalArea = totalArea / 10000000000;info += `广西总面积 ${totalArea.toFixed(3)} 万平方千米`return info
}

效果图:

在这里插入图片描述

根据GeoJSON使用turf.area计算总面积,为23.81万平方千米,与官方部门提供的数据(23.76万平方千米)非常接近。

贝塞尔曲线Bezier

调用turf.bezierSpline可以将一条线段变成平滑的塞尔曲线。

核心代码:

    // 坐标点var points = [[108.390427,22.922982],[108.476257,22.929306],[108.524323,22.895786],[108.500290,22.841376]];// 原始线var line = turf.lineString(points,{color: "#0000FF", name: "折线"});addToLayers(drawOneLayer(line));var line1 = turf.lineString(points,);var curved = turf.bezierSpline(line1, {properties: {color: "#FF0000", name: "折线"}});addToLayers(drawOneLayer(curved));

效果图如下,其中蓝色为原始线段,红色为贝塞尔曲线。

在这里插入图片描述

根据官方手册,可带resolutionsharpness参数。值越高,效果越好,下面代码将参数调低数值。

    var curved = turf.bezierSpline(line1, {resolution: 1000, sharpness: 0.5,properties: {color: "#FF0000", name: "折线"}});addToLayers(drawOneLayer(curved));

效果比默认的差一些,如图:

在这里插入图片描述

空间关系判断

点与线关系的判断:turf.booleanPointOnLine,点在线上,返回true。

点与面关系的判断:booleanPointInPolygon,点在面内,返回true。

面与面关系的判断:booleanOverlap,如有重叠,返回true。

为减少篇幅,只列出核心代码,完整代码参考文后工程仓库代码。

点线关系判断代码片段:

    const points = [[108.481064,22.724890],[108.397293,22.738823]];const point1 = turf.point(points[0], {name: "南宁园博园"});addToLayers(drawOneLayer(point1));const point2 = turf.point(points[1], {name: "五象湖公园"});addToLayers(drawOneLayer(point2));var line1 = turf.lineString([[108.481064,22.724890],[108.397293,22.738823],[108.369827,22.774599]], {color: "#0000FF"});addToLayers(drawOneLayer(line1));// 判断点与线的关系const isPointOnLine1 = turf.booleanPointOnLine(point1, line1);// 不在线上的点const outPoint = turf.point([108.45,22.77], {name: "其它点"});addToLayers(drawOneLayer(outPoint));const isPointOnLine2 = turf.booleanPointOnLine(outPoint, line1);info += `点1与线1关系:${isPointOnLine1}, 其它与线1关系: ${isPointOnLine2}`;

效果:

在这里插入图片描述

点面关系判断代码:

    polygon1 = turf.polygon([[[108.3, 22.86], [108.4, 22.86], [108.4, 22.9], [108.3, 22.9], [108.3, 22.86]]], {color: "#0000FF"});polygon2 = turf.polygon([[[108.349228,22.918555],[108.378067,22.963451],[108.476257,22.950806],[108.479004,22.893888],[108.440552,22.855929],//[108.417892,22.909701], // 删除此坐标,两多边形相交[108.349228,22.918555]]], {color: "#0000FF"});addToLayers(drawOneLayer(polygon1));addToLayers(drawOneLayer(polygon2));inPoint = turf.point([108.304596,22.895786], {name: "内点"})addToLayers(drawOneLayer(inPoint));const isPointInPoly = turf.booleanPointInPolygon(inPoint, polygon1);const isOverlap = turf.booleanOverlap(polygon1, polygon2);info += `点与面关系:${isPointInPoly}, 面与面的关系: ${isOverlap}\r\n`;

效果:

在这里插入图片描述

几何运算

交集:turf.intersect

并集:turf.union

差集:turf.difference

上述几个函数均返回GeoJson格式,可直接用之显示在地图上。

核心代码:

    polygon1 = turf.polygon([[[108.3, 22.86], [108.4, 22.86], [108.4, 22.9], [108.3, 22.9], [108.3, 22.86]]], {color: "#0000FF"});polygon2 = turf.polygon([[[108.325195,22.887562],[108.327942,22.872379],[108.422012,22.864155],[108.446732,22.879971],[108.417892,22.891990],[108.325195,22.887562]]], {color: "#0000FF"});// 交集const intersection = turf.intersect(turf.featureCollection([polygon1, polygon2]), {properties: {color: "#FF0000"}});// 并集const union = turf.union(turf.featureCollection([polygon1, polygon2]), {properties: {color: "#008000"}});// 差集const difference = turf.difference(turf.featureCollection([polygon1, polygon2]), {properties: {color: "#FF0000"}});

效果如下所示,从上而下依次是原始2个多边形,交集、并集、差集。

在这里插入图片描述

需要说明的是,笔者之前使用的是turf6版本,当前使用turf7版本,两版本之间部分接口参数是不同的。以下交集接口的对比:

v6版本:
const intersection = turf.intersect(polygon1, polygon2);
v7版本:
const intersection = turf.intersect(turf.featureCollection([polygon1, polygon2]));

发现这些变化,也是经历了一些曲折的过程。由于笔者旧的工程有使用计算2个多边形交集的接口,更新turf版本后抛出异常,查了很久才发现是接口参数变化了。

小结

turf还有很多其它高阶功能,但GIS于笔者而言,只是工作的一小部分而已,目前使用到的函数,只限于其中一小部分,比如,计算外接矩形、多边形交集,等。其它接口,留待后续有需要时再研究了。

代码

文中列出了主要的代码片段,另有相关的工程demo,已上传到github仓库。因不定时更新,代码不一定与文中严格对应,以代码仓库为准。如使用,请自行根据实际情况修改。

仓库地址:https://github.com/latelee/mapdemo 。

本文涉及文件:100.综合示例.html,函数为turf_demo1turf_demo2

  • turf官方API说明(英文版):https://turfjs.org/docs/api/along
  • turf官方文档:http://turfjs.org/docs/getting-started
  • turfAPI说明(中文版但较旧):https://turf.nodejs.cn/docs/api/along
http://www.dtcms.com/a/600782.html

相关文章:

  • 长沙制作网站公司哪家好广州seo推广营销
  • 11、prometheus-PromQL-5-聚合计算函数
  • (114页PPT)上海x友集团管理咨询及IT规划项目第一期报告管理诊断分析咨询报告(附下载方式)
  • C语言编译器 Visual Studio:实现高效编程与调试环境优化
  • 王树森深度强化学习 DRL(六)连续控制 DDPG + 随机策略
  • 【SatWetCH4 第一期】全球湿地甲烷排放通量估算过程模型 SatWetCH4 介绍
  • Opencv(十一) : 图像缩放
  • 开源 Objective-C IOS 应用开发(四)Xcode工程文件结构
  • 儿童网站 源码html5网站开发教学
  • 编译类语言的特点与应用
  • Python 数组使用方法总结
  • 网站风格变化免费logo在线制作头像
  • 第三章深度解析:智能体“大脑”的底层逻辑——大语言模型技术基石全拆解
  • 100个云计算基础知识
  • 对比 DeepSeek(MLA)、Qwen 和 Llama 系列大模型在 Attention 架构/算法层面的核心设计及理解它们的本质区别。
  • 【C++】List容器模拟实现(超详细)
  • 湖南火电建设有限公司网站龙采哈尔滨建站公司
  • 【PHP反序列化】css夺旗赛
  • ServletLess架构简介
  • 安卓C语言编译器的选择与使用技巧 | 优化C语言编程体验,提升开发效率
  • (三)自然语言处理笔记——Transformer
  • iOS性能分析工具,有UI卡顿、app启动、内存、webview等性能优化解析
  • 电商网站建设 数商云招商码头无忧查询系统
  • 开源 Objective-C IOS 应用开发(三)第一个iPhone的APP
  • (11)(2.2.2) BLHeli32,AM32, and BLHeli_S ESCs(二)
  • Google Chrome v142.0.7444.135 便携增强版
  • [Windows] PDF文件浏览OCR工具1.0
  • 2025人形机器人产业链全景分析报告:核心技术与市场趋势|附130+份报告PDF、数据、可视化模板汇总下载
  • 长春教做网站带维护的培训机构淮安网站建设
  • 图文详述:MySQL的下载、安装、配置、使用