基于Leaflet和天地图的直箭头标绘实战-源码分析

news2024/11/14 14:11:39

目录

前言

一、Leaflet的特种标绘库

1、特种标绘对象的定义

2、Plot基类定义

3、直线箭头的设计与实现

二、在天地图中进行对象绘制

1、引入天地图资源

2、标绘对象的调用时序

3、实际调用过程

三、总结


前言

        在博客中介绍过geoman标绘的具体实现,使用Leaflet GeoMan结合天地图进行自由标绘实战,基于GeoMan的标绘只能包含了常见的点、线、面、矩形的空间对象的标绘。在一些面向特种行业的应用中,我们会遇到特种标绘。比如用来表示敌我双方态势的战斗标绘,比如在一场战斗中的敌我接敌,各方的支援力量的介入,战斗的结果等等过程需要进行集中的标绘。如下图所示:

        以上对象的绘制比之前的基于Geoman的点、线、面等信息的生成稍微要复杂一些。当然您使用一些开源库进行系统的构建,这样能加快开发的速度。但是如果我们想实现自由业务的封装,就需要进行相应的改造才可以,比如我们需要定义箭头的偏转角,控制斜率,生成集结地等曲面时更加的平滑等等,这些功能的实现都是需要进行自己的定制和改造的。因此我们有必要在Leaflet中实现上述的功能,同时掌握如何来进行自定义的绘制。

        一般的态势标绘的类型可以包含以下几种:直箭头、细直箭头、突击方向、进攻方向、进攻方向(尾)、分队战斗行动、分队战斗行动(尾)、钳击、聚集地等。不同的图形绘制过程不一样,根据绘制算法的不同,计算过程也不尽相同。后续会依据不同的标绘对来进行绘制过程解析。本文主要以直线箭头的绘制重点讲解在Leaflet中对上述对象的封装,相关类的功能介绍等,首先介绍一个基于Leaflet的标绘基础库,其次介绍这个库的基本结构,相关类属性和方法的定义,然后基于时序图来介绍相关API的调用,最后生成一个直线箭头的实例。如果对标绘感兴趣的朋友,可以不妨看过来。

一、Leaflet的特种标绘库

        目前基于Leaflet的特种标绘库开源的不多,但是有一个基础的开源库可以提供标绘对象的生成服务,leaflet_plot,大家可以下载相关的源代码进行学习。它的开源代码主要包含两个文件,一个是Plots.js和PlotUtil.js,其中PlotUtil.js主要用于相关坐标点的绘制,Plots.js主要用于绘制和展示不同的对象。

1、特种标绘对象的定义

        首先,我们来看一下Plots.js,在这个类中,定义了所有的标绘对象,由于对象种类较多,这里仅以直线箭头为例,重点讲解标绘类的设计与实现,其它的对象绘制过程比较复杂,后续再慢慢进行讲解。Plots.js主要包含类型定义、对象工厂的创建、具体对象实现的创建。下面将详细介绍。

        在这里,通过javascript代码定义出所有的对象类型,具体有下列几种:

序号类型说明
1STRAIGHT_ARROW"straightarrow",//直箭头
2ASSAULT_DIRECTION"assaultdirection",//突击方向
3ATTACK_ARROW"attackarrow",//进攻方向
4TAILED_ATTACK_ARROW"tailedattackarrow",//进攻方向(尾)
5SQUAD_COMBAT"squadcombat",//分队战斗行动
6TAILED_SQUAD_COMBAT"tailedsquadcombat",//分队战斗行动(尾)
7FINE_ARROW"finearrow",//细直箭头
8DOUBLE_ARROW"doublearrow", //钳击 
9 GATHERING_PLACE"gatheringplace",//聚集地  

2、Plot基类定义

        按照后端面向对象的方式将对象的公共父类抽象出来,形成公共的基类。用于基础属性的设置与渲染。其它对象可以在此基础之上进行扩展即可。

L.Plot = {
    isPlot: function () {
        return true;
    },
    getBaseType: function () {
        let geojson = this.toGeoJSON()
        let type = geojson.geometry.type
        if (type == 'MultiLineString' || type == 'LineString') {
            type = 'Polyline'
        }
        return type
    },
    //设置绘制图形需要的点
    setPoints: function (latlngs) {
        this._bounds = new L.LatLngBounds();
        this._setLatLngs([])
        this._points = this._convertLatLngs(latlngs) || [];
        this._proPoints = L.PlotUtils.proPoints(this._points);
        if (this.getPointCount() >= 1)
            this.generate();
    },
    //设置投影点并更新对应的坐标点
    setProPoints: function (proPts) {
        var latlngs = L.PlotUtils.unProPoints(proPts);
        this.setPoints(latlngs);
    },
    //获取控制点坐标
    getCtrlPoints: function() {
        let ctrlPts = []
        switch (this.type) {
            case L.PlotTypes.SECTOR:
            case L.PlotTypes.ARC:
                ctrlPts = this.getPoints();
                if (ctrlPts.length < 3) {
                    ctrlPts = this._ctrlPnts;
                }
                break;
            case L.PlotTypes.CIRCLE:
                ctrlPts = this.getPoints();
                if (ctrlPts.length < 2) {
                    ctrlPts = this._ctrlPnts;
                }
                break;
            default:
                ctrlPts = this.getPoints();
        }
        return ctrlPts;
    },
    //获取输入点
    getPoints: function () {
        return this._points;
    },
    //获取输入点对应的投影点
    getProPoints: function () {
        return this._proPoints;
    },
    //获取输入的点个数
    getPointCount: function () {
        return this._proPoints.length || 0;
    },
    toPlotJSON: function () {
        let setting = {
            type: this.type,
            points: this.getPoints(),
            options: this.options,
        }
        return setting
    },
    //结束绘制
    finishDrawing: function () {

    }
}

        Plos类的方法列表如下:

序号方法说明
1isPlot是否特殊标绘,默认true
2getBaseType获取基础类型,如:Polyline
3setPoints设置绘制图形需要的点
4setProPoints 设置投影点并更新对应的坐标点
5getCtrlPoints获取控制点坐标
6getPoints获取输入点
7getProPoints获取输入点对应的投影点
8getPointCount获取输入的点个数
9toPlotJSON转成标绘json
10finishDrawing标绘结束事件

3、直线箭头的设计与实现

        在特种标绘的工厂方法中,有生成直线箭头的方法,为简单起见,将其它的方法进行隐藏说明,关键代码如下所示:。

L.PlotFactory = {};
L.PlotFactory.createPlot = function (type, points, options) {
    switch (type) {
        case L.PlotTypes.STRAIGHT_ARROW:
            return new L.Plot.StraightArrow(points, options);
        case L.PlotTypes.ASSAULT_DIRECTION:
            return new L.Plot.AssaultDirection(points, options);
    }
    return null;
}

        其次我们来看下具体的直线箭头的具体实现:

/**
 * 直箭头
 */
L.Plot.StraightArrow = L.Polyline.extend({
    includes: L.Plot,
    options: {
        fixPointCount: 2,
        maxArrowLength: 3000000,
		arrowLengthScale: 8
    },
    initialize: function (latlngs, options) {
        L.setOptions(this, options);
        this.type = L.PlotTypes.STRAIGHT_ARROW;
        this.setPoints(latlngs)
    },
    //生成图形
    generate: function () {
        if (this.getPointCount() < 2) {
            return;
        }
        var pnts = this._proPoints;
        var pnt1 = pnts[0];
        var pnt2 = pnts[1];
        var distance = L.PlotUtils.distance(pnt1, pnt2);
        var len = distance / this.options.arrowLengthScale;
        len = len > this.options.maxArrowLength ? this.options.maxArrowLength : len;
		var leftPnt = L.PlotUtils.getThirdPoint(pnt1, pnt2, Math.PI / 8, len, false);
        var rightPnt = L.PlotUtils.getThirdPoint(pnt1, pnt2, Math.PI / 8, len, true);
        let proPts = [pnt1, pnt2, leftPnt, pnt2, rightPnt]
        this._setLatLngs(L.PlotUtils.unProPoints(proPts));
        this.redraw();
    }
});
L.Plot.straightArrow = function (latlngs, options) {
    return new L.Plot.StraightArrow(latlngs, options);
};

        通过代码大家可以看到,在StraightArrow这个类中,其是通过继承Polyline来实现对象的扩展的,在extends扩展实现中,扩展了两个属性和两个方法。

序号参数说明
1includes: L.Plot,表示基类包含Plot对象
2options当前对象扩展属性,包含对象独有的箭头倾角等
3initialize初始化方法
4generate最主要的图形绘制,包括各种角度的计算

        以上就是特种标绘对象的方法和属性的具体介绍。下面将结合天地来重点讲解如何进行标绘对象的静态标绘,即根据指定坐标来动态绘制。

二、在天地图中进行对象绘制

        这里将重点讲解如何在天地图中进行特种对象的标绘。通过具体代码的实现和调用过程的重现,让大家对如何进行标绘有更详细的讲解。

1、引入天地图资源

        在地图的展示界面中,引入天地图的在线图源非常重要,在加载影像注记的时候,需要请大家注意替换相应的参数。关键代码如下:

<!DOCTYPE >
<html lang="zh">
  <head>
	<meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Leaflet plot绘制</title>
    <link rel="stylesheet" href="./lib/leaflet.css"/>
	<style>
		.hello {
		  position: relative;
		}
		#mapContainer {
		  width: 100%;
		  height: 600px;
		  background-color: #eee;
		  z-index: 0;
		}
		#toolbar {
		  position: absolute;
		  left: 10px;
		  bottom: 10px;
		  list-style: none;
		  margin: 0;
		  padding: 10px;
		  box-shadow: 2px 2px 5px;
		  background-color: rgb(34 34 34 / 50%);
		  border-radius: 0 5px 5px 0;
		}
		#toolbar li {
		  line-height: 28px;
		}
	</style>
  </head>
  <body>
     <div class="hello">
    <h1>Leaflet的plot标绘</h1>
    <div id="mapContainer"></div>
    <ul id="toolbar">
      <li><button onclick="addStraightArrow();">直箭头</button></li>
      <hr>
      <li><button onclick="clearPlots();">清空</button></li>
    </ul>
  </div>
    <script src="./lib/leaflet.js"></script>
	<!-- // 计算工具 -->
    <script src="./lib/PlotUtil.js"></script>
	<!-- // 绘制工具 -->
	<script src="./lib/Plots.js"></script>
	<script>
		var tdt_client_key = "xxx";//天地图客户端的key
		//影像底图
		const tiles = L.tileLayer('http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + tdt_client_key, {
		  maxZoom: 18,
		  attribution:
			'&copy; <a href="https://www.tianditu.gov.cn/">在线图源使用国家天地图</a> contributors',
		});
		
		var plotLayer;
		var map = L.map('mapContainer').setView([28.170086, 112.957993], 13).addLayer(tiles);
		//影像注记
		const label_tiles = L.tileLayer('http://t0.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + tdt_client_key, {
		  maxZoom: 18
		});
		map.addLayer(label_tiles);
		plotLayer = L.featureGroup().addTo(map);
		function clearPlots() {
		  this.plotLayer && this.plotLayer.clearLayers()
		}
		// 直箭头
		function addStraightArrow() {
		  L.Plot.straightArrow([[28.17629, 112.923746],[28.188471, 112.948208]])
		  .addTo(this.plotLayer);
		}
	</script>
  </body>
</html>

        这里需要注意的是,在引入影像注记的时候,需要根据天地图的规范进行相应图层的替换,这里需要注意的点就是:

http://t0.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=

        需要注意上述字符串中的cia_w和后面的cia,cia表示图层的名字,这里一定注意,否则地图不能正确加载。

2、标绘对象的调用时序

        这里我们使用时序图来进行调用时序的讲解,让大家对标绘对象的绘制和加载过程有更深入的讲解,以下是简单的时序调用视图。

3、实际调用过程

        这里以静态标绘为例,未来需要根据绘制事件来进行绘制坐标的获取来进行对象的生成。

         绘制对象的关键点生成,这个距离在后面的倾角的计算有很大的作用。

        第三点(即倾角坐标点的计算)

         最终得到的空间对象如下所示:

        最后在在上面的结果中对标注关键参数进行说明。

         通过以上四点的计算即完成直线箭头的绘制,将绘制的对象添加到地图即可。

三、总结

        以上就是本文的主要内容,本文主要以直线箭头的绘制重点讲解在Leaflet中对上述对象的封装,相关类的功能介绍等,首先介绍一个基于Leaflet的标绘基础库,其次介绍这个库的基本结构,相关类属性和方法的定义,然后基于时序图来介绍相关API的调用,最后生成一个直线箭头的实例。行文仓促,定有不足之处,还请各位专家博友不吝指教,不胜感激。

        参考资料:

        1、基于Leaflet实现标绘——直箭头。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux驱动开发 ——架构体系

只读存储器&#xff08;ROM&#xff09; 1.作用 这是一种非易失性存储器&#xff0c;用于永久存储数据和程序。与随机存取存储器&#xff08;RAM&#xff09;不同&#xff0c;ROM中的数据在断电后不会丢失&#xff0c;通常用于存储固件和系统启动程序。它的内容在制造时或通过…

教师薪酬管理系统的设计与实现

摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;老师信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足广…

【专题】2024中国生物医药出海现状与趋势蓝皮书报告合集PDF分享(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p37719 出海已成为中国医药产业实现提速扩容的重要途径。目前&#xff0c;中国医药产业发展态势良好&#xff0c;创新能力不断增强&#xff0c;然而也面临着医保政策改革和带量集采带来的压力。政府积极出台多项政策支持医药企业出海…

人工智能 | 基于ChatGPT开发人工智能服务平台

简介 ChatGPT 在刚问世的时候&#xff0c;其产品形态就是一个问答机器人。而基于ChatGPT的能力还可以对其做一些二次开发和拓展。比如模拟面试功能、或者智能机器人功能。 模拟面试功能包括个性化问题生成、实时反馈、多轮面试模拟、面试报告。 智能机器人功能提供24/7客服支…

字节跳动冯佳时:大语言模型在计算机视觉领域的应用、问题和我们的解法

演讲嘉宾&#xff5c;冯佳时 编辑 &#xff5c;蔡芳芳 近年来&#xff0c;大语言模型 (LLMs) 在文本理解与生成领域取得了显著进展。然而&#xff0c;LLMs 在理解和生成自然信号&#xff08;例如图像&#xff0c;视频&#xff09;等&#xff0c;还处在比较早期的探索阶段。为…

muduo - 概要简述

作者&#xff1a;陈硕 编程语言&#xff1a;C 架构模式&#xff1a;Reactor 代码链接&#xff1a;GitHub - chenshuo/muduo: Event-driven network library for multi-threaded Linux server in C11 设计自述&#xff1a;https://www.cnblogs.com/Solstice/archive/2010/08…

MybatisPlus:多条件 or()的使用

default List<ErpProductDO> selectByOE(String oe1, String oe2){return selectList(new LambdaUpdateWrapper<ErpProductDO>().eq(ErpProductDO::getOe,oe1).or().eq(ErpProductDO::getOe,oe2)); } 对应SQL为&#xff1a;

《探索云原生与相关技术》

在当今的科技领域中&#xff0c;云原生&#xff08;Cloud Native&#xff09;已经成为了一个热门的话题。它代表着一种构建和运行应用程序的全新方式。 云原生的概念 云原生是一套技术体系和方法论&#xff0c;旨在充分利用云计算的优势来构建更具弹性、可扩展性和高效性的应…

LeetCode 2332.坐上公交的最晚时间 (双指针 + 贪心)

给你一个下标从 0 开始长度为 n 的整数数组 buses &#xff0c;其中 buses[i] 表示第 i 辆公交车的出发时间。同时给你一个下标从 0 开始长度为 m 的整数数组 passengers &#xff0c;其中 passengers[j] 表示第 j 位乘客的到达时间。所有公交车出发的时间互不相同&#xff0c;…

python 识别省市、区县并组建三级信息数据库

一、网址&#xff1a; 全国行政区划信息查询平台 二、分析并搭建框架 检查网页源码&#xff1a; 检查网页源码可以发现&#xff1a; 所有省级信息全部在javaScript下的json中&#xff0c;会在页面加载时加载json数据&#xff0c;填充到页面的option中。 1、第一步&#xff1a…

1、2、3、4四个数字能组成多少个互不相同且无重复数字的三位数

要求 请编写函数fun&#xff0c;其功能是:找出用1、2、3、4四个数字&#xff0c;能组成多少个互不相同且无重复数字的三位数&#xff0c;然后把这些三位数按从小到大的顺序依次存入相应的数组xxx中&#xff0c;符合条件的个数由函数值返回 解题思路 本题要求求出一个三位数&…

c++基础入门三

文章目录 C基础入门(三)auto关键字auto简介使用细则一、可以和指针联合使用二、在一行定义多个变量 不能使用场景一、不能作为函数的参数二、不能用来声明数组 基于for的循环使用条件 指针空值nullptr C基础入门(三) 回顾上集&#xff0c;我们介绍了C的函数重载&#xff0c;引…

初识ZYNQ——FPGA学习笔记15

一、ZYNQ简介 ZYNQ&#xff1a;Zynq-7000 All Programmable SoC&#xff08;APSoC&#xff09;&#xff0c;赛灵思公司&#xff08;AMD Xilinx&#xff09;推出的新一代全可编程片上系统 PS&#xff1a;Processing System&#xff0c;处理系统 PL&#xff1a;Program Logic&…

C++ 类的默认成员函数- 拷贝构造函数

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 概念概述 默认成员函数就是用户没有显式实现&#xff0c;编译器会自动生成的成员函数称…

十四,在Spring Boot当中对应“ Tomcat 服务器的相关配置”和“服务器的切换”的详细说明

十四&#xff0c;在Spring Boot当中对应“ Tomcat 服务器的相关配置”和“服务器的切换”的详细说明 文章目录 十四&#xff0c;在Spring Boot当中对应“ Tomcat 服务器的相关配置”和“服务器的切换”的详细说明1. 基本介绍2. 准备工作&#xff1a;3. 内置 Tomcat 的配置3.1 第…

C++速通LeetCode中等第3题-盛最多水的容器

双指针法&#xff1a;两个指针分别指向左右边界&#xff0c;记录最大面积&#xff0c;由于面积由短板决定&#xff0c;两个指针中较短的短指针向内移动一格&#xff0c;再次记录最大面积&#xff0c; 直到两指针相遇&#xff0c;得出答案。 class Solution { public:int maxAr…

其他图嵌入方法(6)

前面写了图神经网络可以把节点或图映射到一个低维空间&#xff0c;我们将其称为图嵌入。然而&#xff0c;除了图神经网络还有许多的图嵌入方法。本节将介绍其他浅层图嵌入方法。早在图神经网络发明之前&#xff0c;图嵌入的概念就经常出现在流形学习和网络分析的研究中。相对于…

科技引领未来生活——“光影漫游者”展览馆应用—轻空间

随着科技的快速发展&#xff0c;展览馆作为展示文化、科技和艺术的场所&#xff0c;正逐渐从传统的静态展示向高科技互动体验转变。由轻空间打造的“光影漫游者”展览馆&#xff0c;凭借其前沿的气承式结构和智能化系统&#xff0c;将参观者带入了一个未来感十足、充满科技魅力…

海外服务器哪个速度最快且性能稳定

海外服务器的速度与性能稳定性受多种因素影响&#xff0c;包括地理位置、网络架构、基础设施质量以及用户网络路径等。在众多选择中&#xff0c;几个特定地区的服务器因其卓越表现而备受推崇。 首先&#xff0c;美国硅谷(加利福尼亚州)与纽约的服务器以其技术领先、网络连接稳定…

OceanBase 中 schema 的定义与应用

背景 经常在OceanBase 的问答社区 里看到一些关于 “schema 是什么” 的提问。 先纠正一些同学的误解&#xff0c; OceanBase 中的 Schema 并不简单的等同于 Database&#xff0c;本次分享将探讨 OceanBase 中的Schema是什么&#xff0c;及一些大家经常遇到的问题。 具体而…