首页 > 编程语言 >基于Leaflet和天地图的直箭头标绘实战-源码分析

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

时间:2024-09-24 16:55:03浏览次数:3  
标签:function 对象 标绘 Leaflet 箭头 源码 绘制 options


目录

前言

一、Leaflet的特种标绘库

1、特种标绘对象的定义

2、Plot基类定义

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

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

1、引入天地图资源

2、标绘对象的调用时序

3、实际调用过程

三、总结


前言

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

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

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

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

一、Leaflet的特种标绘库

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

1、特种标绘对象的定义

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

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

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

序号

类型

说明

1

STRAIGHT_ARROW

"straightarrow",//直箭头

2

ASSAULT_DIRECTION

"assaultdirection",//突击方向

3

ATTACK_ARROW

"attackarrow",//进攻方向

4

TAILED_ATTACK_ARROW

"tailedattackarrow",//进攻方向(尾)

5

SQUAD_COMBAT

"squadcombat",//分队战斗行动

6

TAILED_SQUAD_COMBAT

"tailedsquadcombat",//分队战斗行动(尾)

7

FINE_ARROW

"finearrow",//细直箭头

8

DOUBLE_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类的方法列表如下:

序号

方法

说明

1

isPlot

是否特殊标绘,默认true

2

getBaseType

获取基础类型,如:Polyline

3

setPoints

设置绘制图形需要的点

4

setProPoints

 设置投影点并更新对应的坐标点

5

getCtrlPoints

获取控制点坐标

6

getPoints

获取输入点

7

getProPoints

获取输入点对应的投影点

8

getPointCount

获取输入的点个数

9

toPlotJSON

转成标绘json

10

finishDrawing

标绘结束事件

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扩展实现中,扩展了两个属性和两个方法。

序号

参数

说明

1

includes: L.Plot,

表示基类包含Plot对象

2

options

当前对象扩展属性,包含对象独有的箭头倾角等

3

initialize

初始化方法

4

generate

最主要的图形绘制,包括各种角度的计算

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

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

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

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:
			'© <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、标绘对象的调用时序

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

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

3、实际调用过程

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

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

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

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

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

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

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

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

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

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

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

三、总结

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

        参考资料:

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

标签:function,对象,标绘,Leaflet,箭头,源码,绘制,options
From: https://blog.51cto.com/yelangking/12100907

相关文章

  • 基于JDK1.8和Maven的GeoTools 28.X源码自主构建实践
    目录前言一、GeoTools与Jdk的版本关系1、GeoTools与Jdk版本2、编译环境简介二、使用Maven编译GeoTools28.X1、GeoTools28.x2、Maven的完整编译3、构建时的问题三、总结前言        想要学习和掌握一个开源软件或者项目,源码是我们主要学习的内容。学习开源项目的源代码可以......
  • 基于SSM的旅游综合网站【附源码+文档】
    ......
  • 基于SSM的旅游服务综合平台【附源码+文档】
    ......
  • 高校高校教师教学质量评价系统 毕业设计-附源码88214
    摘要本研究旨在探讨基于SSM框架的高校教师教学质量评价系统的设计与实现。教师教学质量评价是高校教育质量保障的重要组成部分,而借助SSM框架的优势,可以快速构建一个全面、高效的评价系统,有助于提升教学质量管理水平。本系统将涵盖教师评价指标设定、评价数据管理、评价结......
  • 基于Python+Vue开发的蛋糕商城管理系统源码+开发文档
    项目简介该项目是基于Python+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力......
  • 基于Java+Springboot+Vue开发的体育用品商城管理系统源码+开发文档
    项目简介该项目是基于Java+Springboot+Vue开发的体育用品商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的体育用品商城管理系统项目,大学生可以在实践中学习和......
  • 基于Java+Springboot+Vue开发的体育场馆预约管理系统源码+开发文档
    项目简介该项目是基于Java+Springboot+Vue开发的体育场馆预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的体育场馆管理系统项目,大学生可以在实践中学习和提升......
  • 基于Java+Springboot+Vue开发的旅游景区管理系统源码+参考文章1.3万字
    项目简介该项目是基于Java+Springboot+Vue开发的旅游景区管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的旅游景区管理系统项目,大学生可以在实践中学习和提升自己......
  • 基于Python+Vue开发的旅游景区管理系统源码+开发文档1.3万字
    项目简介该项目是基于Python+Vue开发的旅游景区管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的旅游景区管理系统项目,大学生可以在实践中学习和提升自己的能力......
  • 基于Java+Springboot+Vue开发的鲜花商城管理系统源码+参考文章1.3万字
    项目简介该项目是基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己......