前言
两点之间的连线是很常见的,但是都是直直的一条线段,为了使连线更加平滑,我们可以使用曲线进行连线,本功能考虑使用贝塞尔曲线进行连线绘制,最后将线段的两端节点连接,返回一个polygon。
贝塞尔简介
给定不同的点 P0 和 P1,线性贝塞尔曲线只是这两点之间的一条线。
相当于线性插值。
Turf.bezierSpline()简介
接受一条线,通过应用贝塞尔样条算法返回一个弯曲的版本
官方例子
var 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]
]);var curved = turf.bezierSpline(line);
参数说明
line:input LineString
options:{
resolution:点之间的时间(毫秒)
sharpness:衡量样条路径应该有多弯曲的一个度量
}
具体可以查看官方的bezierSpline函数
UseBezierSpline.js完整代码
import { onBeforeUnmount, reactive, ref } from 'vue'
import * as turf from '@turf/turf'/*** @Description 接受一条线,通过应用贝塞尔样条算法返回一个弯曲的版本(贝塞尔曲线)* @param mainMap 地图对象* @param drawComplete 完成绘制的回调函数* @Param bezierOptions* @Param bezierOptions.resolution 点之间的时间(毫秒)* @Param bezierOptions.sharpness 衡量样条路径应该有多弯曲的一个度量* @param drawLayer 绘制图形的layer* @Author ZhangJun* @Date 2024-01-11 09:55:12* @return void**/
export default function useBezierSpline(mainMap, drawComplete = null, bezierOptions = {}, drawLayer = undefined) {//默认的贝塞尔配置参数合并let bezierOptions_config = reactive({resolution: 1000,sharpness: 0.85,...bezierOptions,})//绘制事件状态let status = ref('start')// 记录当前状态是否可以拖动绘制let isDragging = true//拖动绘制的坐标let drawPath = []//拖动绘制的线let drawLine = reactive(null)//鼠标正在移动的点let movePoint//最终绘制的polygon,最终返回的就是它的轮廓坐标let polygon_draw = reactive(null)//鼠标提示let mouseEventPopup = new L.popup({ className: 'customPopup', closeButton: false })if (mainMap) {//关闭的时候一定要销毁onBeforeUnmount(() => {closeDraw()mainMap?.removeLayer(drawLayer)})if (!drawLayer) {drawLayer = L.featureGroup([])drawLayer.addTo(mainMap)}//初始化事件let initEvents = () => {isDragging = false//按下鼠标确定需要添加的节点(暂停中)mainMap.on('mousedown', (e) => {isDragging = falselet { lat, lng } = e.latlngdrawPath = [...drawPath, [lng, lat]]//如果才开始点击第一次,就创建一个polyline,后面需要动态需改它的pathif (drawPath?.length === 1) {status.value = 'start'//添加绘制linedrawLine = L.polyline(drawPath, { color: 'red' }).addTo(mainMap)}})//松开鼠标开始拖动绘制(开始绘制)mainMap.on('mouseup', (e) => {isDragging = true})//鼠标移动绘制(绘制中)mainMap.on('mousemove', (e) => {if (isDragging) {let { lat, lng } = e.latlngmovePoint = [lng, lat]//动态生成贝塞尔曲线的featurelet splineFeature = generationBezierSpline(drawPath, movePoint)if (splineFeature) {let tempCoords = turf.getCoords(turf.flip(splineFeature))//将生成的贝塞尔曲线的坐标传给polyline,在地图上刷新渲染drawLine?.setLatLngs(tempCoords)}}mouseEventPopup?.setLatLng(e.latlng)?.setContent('右键结束绘制')//如果还没有添加就直接先添加一下if (!mainMap.hasLayer(mouseEventPopup)) {//打开方向的popupmouseEventPopup?.openOn(mainMap)}})//右键结束(结束绘制)mainMap.on('contextmenu', (e) => {let coords = turf.getCoords(turf.flip(drawLine.toGeoJSON()))//生成polygonpolygon_draw = L.polygon(coords, { color: 'green' })clearDrawLayer()addLayersToDrawLayer([polygon_draw])//移除曲线mainMap?.removeLayer(drawLine)status.value = 'end'//绘制完成的回调if (typeof drawComplete === 'function') {let result = getResult(polygon_draw)drawComplete(result)}})}//移除事件let removeEvents = () => {//按下鼠标mainMap?.off('mousedown')//抬起鼠标mainMap?.off('mouseup')//拖拽事件mainMap?.off('mousemove')//右键事件mainMap?.off('contextmenu')}//开始绘制let startDraw = () => {//禁止拖动地图mainMap?.dragging?.disable()//初始化事件initEvents()}//清除原来绘制的内容let clearDrawLayer = () => {drawPath = []drawLayer?.clearLayers()}//添加要素到drawLayerlet addLayersToDrawLayer = (features = []) => {features?.forEach(feature => {drawLayer.addLayer(feature)})}/*** @Description 生成曲线* @Param originalPath 已经确定的点坐标集合* @Param lastPoint 最后一个坐标点,一般为移动的点坐标* @Author ZhangJun* @Date 2024-01-11 10:36:11* @return void**/let generationBezierSpline = (originalPath = drawPath, lastPoint = movePoint) => {if (originalPath?.length > 0) {//加入最后一个点let line = turf.lineString([...originalPath, lastPoint], bezierOptions_config)return turf.bezierSpline(line)}return null}//关闭绘制功能let closeDraw = () => {//清空绘制的几何clearDrawLayer()//一定要移除事件,否则事件之间会有干扰removeEvents()//移除popupmainMap?.closePopup(mouseEventPopup)//激活拖拽功能mainMap?.dragging?.enable()}//获取最终的polygon的轮廓坐标let getResult = (feature = polygon_draw) => {if (feature) {//获取输入 feature 并将它们的所有坐标从 [x, y] 翻转为 [y, x]。let featureCollection = turf.flip(feature.toGeoJSON())return turf.getCoords(featureCollection)}return []}return { status, getResult, closeDraw, drawLayer, bezierOptions_config, startDraw }}return {}
}
UseBezierSpline.js使用
if (wizMap?.map) {let { startDraw, closeDraw, status: temp, getResult } = useBezierSpline(wizMap?.map)getCoords = getResult//当前绘制状态(是否完成绘制)status.value = temponMounted(() => {//需要这种处理,不然会有异常nextTick(() => {startDraw()})})
}
效果
贝塞尔曲线
本文为学习笔记,仅供参考