Leaflet.js与Turf.js平滑曲线生成展示实战教程

2026-06-06阅读 0热度 0
其他

在GIS路线相关的开发场景中,轨迹可视化是一个高频需求。通常我们会在地图上采集若干个关键经纬度点,再将其串联成一条路线。但一个常见痛点随之而来:如果仅采集少数关键点,最终呈现的折线会非常生硬,尤其在拐点部位显得格外突兀。直观效果就像下面这张图所示:

那么,有没有什么手段能让这些拐点连成的曲线看起来更加自然平滑?有开发者可能会说:“多采集一些点不就行了?”理论上确实如此,点越密曲线越平滑。但现实是,野外数据采集工作强度大,点位越多耗费的人力时间成本越高。那么,能否在不增加外业工作量的前提下,直接基于现有数据进行曲线平滑处理呢?

这里分享一套基于Turf.js的WebGIS解决方案。它能在不增加采集负担的情况下,动态生成平滑曲线并渲染到地图上。对于希望在WebGIS中实现类似功能的开发者来说,这是一个相当实用的技术路径。

一、问题的由来

线由点构成。将相邻点两两连接,一条折线便形成了。为了便于演示,我们模拟了一条虚拟的自驾路线。然后借助Turf.js生成不同平滑程度的曲线,直观对比效果。

先从最基础的实现开始:以Leaflet作为地图渲染引擎,配合Turf.js进行曲线计算。

1、创建网页框架

首先创建一个HTML页面。页面中需要引入Leaflet的CSS和JS文件,以及Turf.js的库。核心代码如下:




    基于Leaflet和Turf生成平滑曲线实践
    
    
    
    
    <script src="/2d/leaflet/leaflet.js?v=1.0.0"></script>
    
    <script src="https://unpkg.com/@turf/turf/turf.min.js"></script>
    


    
<script></script>

2、创建map对象

基础框架搭建完成后,实例化地图对象,将容器绑定到DOM上:

var mymap = L.map('map').setView([29.052934, 104.0625], 6);
var tileLayer = L.tileLayer('http://localhost:8086/data/xxgc/q0403/{z}/{x}/{y}.png', {
    maxZoom: 7,
    minZoom:0
});
tileLayer.addTo(mymap); 

3、构建点位,生成路线

为了演示,我们准备一组虚拟坐标数据。模拟一条自驾路线:从云南保山出发,依次经过攀枝花、昆明、成都、重庆、贵阳、长沙、赣州,最终抵达福建福州。各城市经纬度如下:

var cityPoint = new Array();
cityPoint.push([99.116482, 25.078402]);//保山
cityPoint.push([101.708392, 26.50289]);//攀枝花
cityPoint.push([102.780718, 24.915559]);//昆明
cityPoint.push([104.098757, 30.594412]);//成都
cityPoint.push([106.559098, 29.452047]);//重庆
cityPoint.push([106.515163, 26.461228]);//贵阳
cityPoint.push([112.929622, 28.141659]);//长沙
cityPoint.push([114.956049, 25.713705]);//赣州
cityPoint.push([119.344081, 26.027307]);//福州

然后将这些点位连成线,显示在地图上:

var linestring = turf.lineString(cityPoint, {name: 'line 1'});
L.geoJSON(linestring,{
    style:{color:"blue",wight:2,fill:false}
}).addTo(mymap);

查看原始效果。注意各个拐点——转折确实不够平滑。

二、Turf.js平滑曲线改造

现在进入核心环节。先简要了解Turf.js中用于曲线平滑的API。

1、官网方法介绍

Turf.js提供了bezierSpline()方法,用于对多线段进行平滑处理。其原理基于贝塞尔样条算法,将原始折线转换为弯曲路径。关于贝塞尔曲线的数学原理,感兴趣的话可以自行查阅相关资料,里面涉及不少数值计算细节。

方法参数如下:

参数 类型 描述
line Feature input LineString
options Object 可选参数:见下文

options选项:

属性 类型 默认值 描述
resolution number 10000 点之间的时间(毫秒)
sharpness number 0.85 衡量样条路径应该有多弯曲的一个度量

返回值是Feature ,即弯曲后的线。

2、0.4弯曲度曲线

在实际测试中,我们将sharpness设置为0.4,观察效果:

var curved = turf.bezierSpline(linestring,{sharpness:0.4,resolution:10000});
L.geoJSON(curved,{
    style:{color:"red",wight:2,fill:false}
}).addTo(mymap);

将生成的红色曲线与原始蓝色折线叠加显示。可以明显看到,整条路线的过渡变得平滑许多。

3、0.85弯曲度曲线

接着将弯曲度调高至0.85:

L.geoJSON(turf.bezierSpline(linestring,{sharpness:0.85,resolution:10000}),{
    style:{color:"green",wight:2,fill:false}
}).addTo(mymap);

从效果来看,0.85的曲线弯曲程度显著增大,与实际路线的形态偏差也更为明显。

4、0.1弯曲度曲线

再尝试将弯曲度降至0.1:

L.geoJSON(turf.bezierSpline(linestring,{sharpness:0.1,resolution:10000}),{
    style:{color:"yellow",wight:2,fill:false}
}).addTo(mymap);

5、综合对比

将三条不同弯曲度的曲线叠加在同一张地图上,对比效果更加直观:

从对比中可以看出:弯曲度系数越大,曲线越“弯”。黄色对应0.1弯曲度,红色对应0.4,绿色对应0.85。

序号 弯曲度 实际效果
1 0.1 与原始拟合
2 0.4 有一定弯曲
3 0.85 弯曲较大

最后附上完整的示例代码。运行时请将图源地址替换为自己服务器上的瓦片服务地址。




    基于Leaflet和Turf生成平滑曲线实践
    
    
    
    
    <script src="/2d/leaflet/leaflet.js?v=1.0.0"></script>
    <script src="https://unpkg.com/@turf/turf/turf.min.js"></script>
    


    
<script> var mymap = L.map('map').setView([29.052934, 104.0625], 6); var tileLayer = L.tileLayer('http://localhost:8086/data/xxgc/q0403/{z}/{x}/{y}.png', { maxZoom: 7, minZoom:0 }); tileLayer.addTo(mymap); var cityPoint = new Array(); cityPoint.push([99.116482, 25.078402]); cityPoint.push([101.708392, 26.50289]); cityPoint.push([102.780718, 24.915559]); cityPoint.push([104.098757, 30.594412]); cityPoint.push([106.559098, 29.452047]); cityPoint.push([106.515163, 26.461228]); cityPoint.push([112.929622, 28.141659]); cityPoint.push([114.956049, 25.713705]); cityPoint.push([119.344081, 26.027307]); var linestring = turf.lineString(cityPoint, {name: 'line 1'}); L.geoJSON(linestring,{ style:{color:"blue",wight:2,fill:false} }).addTo(mymap); var curved = turf.bezierSpline(linestring,{sharpness:0.4,resolution:10000}); L.geoJSON(curved,{ style:{color:"red",wight:2,fill:false} }).addTo(mymap); L.geoJSON(turf.bezierSpline(linestring,{sharpness:0.85,resolution:10000}),{ style:{color:"green",wight:2,fill:false} }).addTo(mymap); L.geoJSON(turf.bezierSpline(linestring,{sharpness:0.1,resolution:10000}),{ style:{color:"yellow",wight:2,fill:false} }).addTo(mymap); </script>

总结

总体而言,利用Turf.js的bezierSpline方法配合sharpness参数,能够高效地在已有数据基础上对手绘路线做平滑优化。既不需要增加野外采集的点数,也不会扭曲原始路径的走向意图。在拐点修饰这类GIS可视化场景中,这是一条相当优雅的技术路线。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策