leaflet学习笔记-贝塞尔曲线绘制(八)

前言

两点之间的连线是很常见的,但是都是直直的一条线段,为了使连线更加平滑,我们可以使用曲线进行连线,本功能考虑使用贝塞尔曲线进行连线绘制,最后将线段的两端节点连接,返回一个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 = false
        let { lat, lng } = e.latlng
        drawPath = [...drawPath, [lng, lat]]

        //如果才开始点击第一次,就创建一个polyline,后面需要动态需改它的path
        if (drawPath?.length === 1) {
          status.value = 'start'
          //添加绘制line
          drawLine = L.polyline(drawPath, { color: 'red' }).addTo(mainMap)
        }
      })

      //松开鼠标开始拖动绘制(开始绘制)
      mainMap.on('mouseup', (e) => {
        isDragging = true
      })

      //鼠标移动绘制(绘制中)
      mainMap.on('mousemove', (e) => {
        if (isDragging) {
          let { lat, lng } = e.latlng
          movePoint = [lng, lat]
          //动态生成贝塞尔曲线的feature
          let 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)) {
          //打开方向的popup
          mouseEventPopup?.openOn(mainMap)
        }
      })

      //右键结束(结束绘制)
      mainMap.on('contextmenu', (e) => {
        let coords = turf.getCoords(turf.flip(drawLine.toGeoJSON()))
        //生成polygon
        polygon_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()
    }

    //添加要素到drawLayer
    let 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()

      //移除popup
      mainMap?.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 = temp

  onMounted(() => {
    //需要这种处理,不然会有异常
    nextTick(() => {
      startDraw()
    })
  })
}

效果

贝塞尔曲线


本文为学习笔记,仅供参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/310726.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

示例说明 Makefile 中的 $(@F),及其用法示例$$dir $@ $< $^ %.c

备忘一个不错的开源编辑器CudaText 下载网址: CudaText - Browse /release at SourceForge.net CudaText 主页: CudaText - Home 1,含义及验证 在 Makefile 中,$(F) 表示当前规则的目标文件名(不包括路径部分&…

RabbitMQ入门到实战——基础篇

初识RabbitMQ:高性能异步通讯组件 同步调用 异步调用 场景:1.对结果不关心时异步。订单状态-异步,查询-同步 2.影响性能。调用链超长,可改成异步 MQ技术对比 kafka日志收集 RabbitMQ整体架构 快速入门 交换机只负责路由消息&am…

Linux学习之网络编程(纯理论)

写在前面 刚刚更新完Linux系统编程,特别推荐大家去看的Linux系统编程,总共44个小时,老师讲的非常好,我是十天肝完的,每天大概看20集,每天还要以写blog的形式来写笔记来总结一下,虽然这十天有点…

回顾2023,立2024flag

文章目录 回顾2023与CSDN相识专栏整理数据回顾 立2024flag 回顾2023 在过去的一年里,前端技术不断演进和创新。新技术、新框架层出不穷,给前端工程师提供了更多选择和挑战。2023年已经成为过去,回首这一年,我们也经历了许多挑战和…

C# Linq+ValueTuple(元祖),成为Linq高手!

文章目录 前言简单使用:能被2整除ValueTuple使用:两数相加等于4不使用元祖使用元祖排序 基于类的LinqGroupByJoinDistinct去重普通去重选择去重 集合去重ExceptIntersectUnion 总结 前言 Linq是C# 最强语法之一,和委托,get set并列(在我的心中)。我很早就听说了Lin…

rust异步实现(偏应用少理论不头疼版)

文章目录 1 添加依赖2 示例3 tokio异步实现机制概要 参考资料:( 想要进步理解可以看这个 ↓ ) https://www.bilibili.com/video/BV16r4y187P4/?spm_id_from333.788.recommend_more_video.1&vd_source20edf767ec72b97832bba2fc3aca50b8 R…

原型对象与对象原型,理解Function与Array和Object,在instanceof下的关联

面向过程与面向对象 面向过程时一步一步去做一件事,面向对象是多个功能组合在一起,去完成这件事。 面向对象的特性:继承性,封装性,多态性 通过概述应该知道面向过程和面向对象的优缺点 封装性 大家要玩游戏&#x…

如何使用手机公网远程访问本地群辉Video Station中视频文件【内网穿透】

最近,我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念,而且内容风趣幽默。我觉得它对大家可能会有所帮助,所以我在此分享。点击这里跳转到网站。 文章目录 1.使用环境要求:2.下载群晖videostation&am…

三段低THD线性恒流控制芯片SM2256E:适用于印度球泡灯9W@230Vac

三段低THD线性恒流控制芯片SM2256E是一款专为印度球泡灯、GU10 LED 球泡灯、射灯、LED 蜡烛灯等设计的电子元件。它采用了先进的控制技术,实现了对电流的精准控制,从而有效地降低了总谐波失真(THD)。 SM2256E参数 该芯片的主要特…

蓝桥杯省赛无忧 STL 课件12 vector

01 vector的定义和特性 02 vector的常用函数 03 vector排序去重 示例&#xff1a; #include<bits/stdc.h> using namespace std; int main(){vector<int> vec {5,2,8,1,9};sort(vec.begin(),vec.end());for(const auto& num : vec){cout<<num<<&q…

Spring Boot自动装配

前言 自动装配是 Spring Boot 最核心的功能之一&#xff0c;第三方可以基于这个特性非常方便的和 Spring 做整合&#xff0c;实现自己的 Starter&#xff0c;做到开箱即用。 Java 早期并不支持注解&#xff0c;所以那会儿 Spring 只能通过 xml 的形式来配置。早期项目里要引入…

[Vulnhub靶机] DriftingBlues: 6

[Vulnhub靶机] DriftingBlues: 6靶机渗透思路及方法&#xff08;个人分享&#xff09; 靶机下载地址&#xff1a; https://download.vulnhub.com/driftingblues/driftingblues6_vh.ova 靶机地址&#xff1a;192.168.67.25 攻击机地址&#xff1a;192.168.67.3 一、信息收集 …

分布式限流和本地限流那些事?

分布式限流和本地限流的目的是一样的&#xff0c;当然我建议技术人在自己的服务中优先考虑本地限流&#xff0c;那样对于自己的API的影响会小一点。 限流这种技术&#xff0c;在没有触发限流的阈值的时候&#xff0c;是不会有什么大的问题的&#xff0c;当时一旦触发阈值&…

在树莓派OS Bookworm中如何安装Python包

树莓派OS "Bookworm"版本&#xff0c;用于树莓派5上&#xff0c;更改了安装Python模块的方法。 关键要点&#xff1a; 1&#xff09;树莓派OS Bookworm需要在一个虚拟环境中安装Python包来防止与Python的系统版本发生冲突。 2&#xff09;你可以使用apt包管理器来搜…

如何在群辉NAS使用Docker搭建容器魔方并实现无公网ip远程访问

文章目录 1. 拉取容器魔方镜像2. 运行容器魔方3. 本地访问容器魔方4. 群辉安装Cpolar5. 配置容器魔方远程地址6. 远程访问测试7. 固定公网地址 本文主要介绍如何在群辉7.2版本中使用Docker安装容器魔方&#xff0c;并结合Cpolar内网穿透工具实现远程访问本地网心云容器魔方界面…

商品源数据如何采集,您知道吗?

如今&#xff0c;电子商务已经渗透到了人们生活的方方面面。2020年新冠肺炎突如其来&#xff0c;打乱了人们正常的生产生活秩序&#xff0c;给经济发展带来了极大的影响。抗击疫情过程中&#xff0c;为避免人员接触和聚集&#xff0c;以“无接触配送”为营销卖点的电子商务迅速…

【数据结构】7大排序最详细

0.前言 接下来进入排序&#xff0c;我们知道在c语言阶段可能就学习过了像冒泡排序&#xff0c;选择排序这种比较简单的排序&#xff0c;那么接下来我们就会学习到更加高级的排序算法。但高级代表着难度的提升&#xff0c;但不用担心&#xff0c;博主会细细来谈&#xff0c;慢慢…

使用Rider C# Dll工程和Unity工程互相调用、断点方法

总体流程 创建C# Dll工程&#xff0c;生成C#工程Dll 创建Unity工程 Unity调用C#工程的代码 C#工程调用Unity工程的代码 断点方法 创建C# Dll工程&#xff0c;生成C#工程Dll 创建工程 选这个&#xff0c;注意UnityEngineDll这个选项&#xff0c;要选你目标unity版本的Dll…

【【深入浅出了解静态时钟分析和时钟约束】】

深入浅出了解静态时钟分析和时钟约束 时序分析是什么&#xff1f; 我们提出一些特定的时序要求&#xff08;或者说是添加特定的时序约束&#xff09;&#xff0c;使用特定的时序模型&#xff0c;针对特定的电路进行分析。分析的最终结果是要求系统时序满足我们提出的要求。 这…

MySQL的三种存储引擎 InnoDB、MyISAM、Memory

InnoDB 1). 介绍 InnoDB是一种兼顾高可靠性和高性能的通用存储引擎&#xff0c;在 MySQL 5.5 之后&#xff0c;InnoDB是默认的MySQL 存储引擎。 2). 特点 DML操作遵循ACID模型&#xff0c;支持事务&#xff1b; 行级锁&#xff0c;提高并发访问性能&#xff1b; 支持外键F…