156.Vue3 + OpenLayers + Turf 实现多线段绘制与贝塞尔曲线平滑展示

🖼️ 效果演示


📚 实现背景

在地图可视化项目中,我们经常需要对轨迹或路径进行“平滑处理”,使其更自然、柔和。传统折线虽然精准,但视觉上较为生硬;而贝塞尔曲线可对线段进行插值优化,生成更符合用户感官的平滑路径。

本文基于:

  • Vue 3 + Composition API

  • OpenLayers 地图框架

  • Turf.js 空间算法库(用于处理几何图形)

实现了从 多线段绘制贝塞尔曲线平滑处理 的完整流程。


🧩 技术栈与依赖

npm install ol @turf/turf

📦 主要功能

  • ✏️ 一键绘制多段折线(LineString);

  • 🧮 使用 turf.bezierSpline 将折线平滑为贝塞尔曲线;

  • 🗺️ 使用 OpenLayers 显示原始线与平滑后的线;

  • 🧹 支持图层清除操作。


🧱 完整代码

<!--
 * @Author: 彭麒
 * @Date: 2025/7/16
 * @Email: 1062470959@qq.com
 * @Description: 此源码版权归吉檀迦俐所有,可供学习和借鉴或商用。
 -->
<template>
  <div class="container">
    <div class="w-full flex justify-center flex-wrap">
      <div class="font-bold text-[24px]">
        Vue3 + OpenLayers + Turf 绘制线段并生成贝塞尔曲线
      </div>
    </div>
    <h3></h3>
    <h4>
      <el-button type="primary" size="small" @click="showLine">绘制多线段</el-button>
      <el-button type="warning" size="small" @click="showBezier">绘制贝塞尔曲线</el-button>
      <el-button type="danger" size="small" @click="clearSource">清除图层</el-button>
    </h4>
    <div id="vue-openlayers"></div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import 'ol/ol.css'
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import VectorSource from 'ol/source/Vector'
import VectorLayer from 'ol/layer/Vector'
import XYZ from 'ol/source/XYZ'
import GeoJSON from 'ol/format/GeoJSON'
import { Fill, Stroke, Style, Circle } from 'ol/style'
import { fromLonLat } from 'ol/proj'
import * as turf from '@turf/turf'

// 地图和图层相关
const map = ref(null)
const turfSource = new VectorSource({ wrapX: false })
let line = null // 储存原始多线段 LineString

// 渲染 GeoJSON 数据到矢量图层
function show(geojsonData) {
  const features = new GeoJSON().readFeatures(geojsonData, {
    dataProjection: 'EPSG:4326',
    featureProjection: 'EPSG:3857'
  })
  turfSource.addFeatures(features)
}

// 清除图层
function clearSource() {
  turfSource.clear()
  line = null
}

// 绘制原始多线段
function showLine() {
  line = turf.lineString([
    [-76.091308, 18.427501],
    [-76.695556, 18.729501],
    [-76.552734, 19.40443],
    [-74.61914, 19.134789],
    [-73.652343, 20.07657],
    [-73.157958, 20.210656]
  ])
  show(line)
}

// 绘制贝塞尔曲线
function showBezier() {
  if (line) {
    const curved = turf.bezierSpline(line)
    show(curved)
  }
}

// 初始化地图
function initMap() {
  const baseLayer = new TileLayer({
    source: new XYZ({
      url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=en&size=1&scl=1&style=7'
    })
  })

  const vectorLayer = new VectorLayer({
    source: turfSource,
    style: new Style({
      fill: new Fill({
        color: 'rgba(255,0,0,0.2)'
      }),
      stroke: new Stroke({
        color: '#f0f',
        width: 2
      }),
      image: new Circle({
        radius: 5,
        fill: new Fill({
          color: '#ff0000'
        })
      })
    })
  })

  map.value = new Map({
    target: 'vue-openlayers',
    layers: [baseLayer, vectorLayer],
    view: new View({
      projection: 'EPSG:3857',
      center: fromLonLat([-74.61914, 19.134789]),
      zoom: 8
    })
  })
}

onMounted(() => {
  initMap()
})
</script>

<style scoped>
.container {
  width: 840px;
  height: 570px;
  margin: 50px auto;
  border: 1px solid #42B983;
}

#vue-openlayers {
  width: 800px;
  height: 400px;
  margin: 0 auto;
  border: 1px solid #42B983;
  position: relative;
}
</style>

📈 Turf 中的 bezierSpline 原理简述

turf.bezierSpline(line, options) 方法将折线插值成一条平滑曲线,本质是对线段进行贝塞尔插值,支持设置分辨率、曲线张力等参数。

其优点包括:

  • 平滑自然;

  • 适用于轨迹回放、导航路径可视化;

  • 插值后的线段依旧符合 GeoJSON 标准,便于进一步处理。


🧰 衍生拓展方向

你可以在此基础上做更多扩展:

方向建议
轨迹动画将贝塞尔线段动画渲染轨迹播放
用户绘制让用户在地图上点击生成 LineString
曲率控制自定义 turf.bezierSpline(line, { sharpness: 0.5 }) 控制曲率


🔚 总结

本篇内容演示了如何用 Vue3 + OpenLayers + Turf 绘制线段并生成贝塞尔曲线,适用于路径平滑、地图轨迹、可视化展示等场景。通过简单按钮交互,你可以方便地控制原始线段与平滑曲线的展示。

如需源码或完整工程,可私信我或评论获取。欢迎点赞、收藏与转发!🌟


🔗 参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉檀迦俐

你的鼓励奖是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值