使用Leaflet-canvas-label进行个性化标注实践详解

news2024/11/15 15:34:48

目录

前言

一、leaflet-canvas-label属性

1、地图展示属性

2、Canvas文本标注属性

3、事件列表

二、属性设置实战

1、标注放大比例

2、字体颜色和方向偏移

3、标注文字透明色设置

4、标注显示层级

三、事件绑定

1、颜色改变

2、事件绑定解析

3、标记初始化的一个小问题

 四、总结


前言

        今天是端午节,首先祝大家端午安康,节日快乐,记得要吃粽子。

        众所周知,在地理信息工作过程中,标注就是在地图中的地图要素上或者地图要素旁边加上描述性文字的过程。在WebGIS中,标注主要是特指自动生成并放置地图要素的描述性文字的过程。一个标注是地图上的一段文本,它由一个或多个要素属性产生。

        标注这一操作有助于为地图上的许多要素添加描述性的文本。标注是向地图上添加文本的一种较为快捷的方式,它避免了手动地为每个要素逐个添加文本。另外,WebGIS能够自动地进行标注,自动地生成并放置文本。如果用户的数据可能发生变化,或者用户要在不同的空间尺度上制作地图的时候,这种标注的方法就会非常地实用。

        在之前的博客中,我们对leaflet-canvas-label进行了简单的介绍,也讲解了如何使用leaflet-canvas-label来进行数据免切片数据标注。但是对于这款组件常见的属性如何使用,没有进行详细的说明,有一些属性还是要进一步的使用才能熟练掌握。本文将重点介绍leaflet-canvas-label这款组件的基本属性的使用,通过实例来详细展示不同的效果,同时基于leaflet-canvas-label介绍它的事件机制,掌握通过事件来重新设置属性。

        本文详细介绍leaflet-canvas-label的属性以及事件,首先介绍它的参数列表,然后根据不同的属性进行实例的讲解,最后给出一个完整的演示示例。如果您当前也有这种标注需求,不妨来这里看看。

一、leaflet-canvas-label属性

        为了详细介绍leaflet-canvas-label的属性,知道这款组件有什么属性可以独立设置。我们首先详细的介绍其属性。虽然在前面的博客中,曾经介绍过相关属性,但是没有进行详细的案例讲解。因此在这里再一次回顾一下这些属性,如果是第一次看博客的朋友刚好可以掌握,如果是第二次以上的朋友,则可以熟悉一下相关参数。

        leaflet-canvas-label这款组件的参数主要分为两个部分,第一部分是地图展示的属性,第二部分是Canvas的标注属性。下面将详细介绍这两个部分的每个属性。

1、地图展示属性

        首先介绍一下地图展示部分的属性:

序号参数说明默认值
1offsetX横坐标偏移(像素)0
2offsetY纵坐标偏移(像素)0
3scale放大比例1
4rotation旋转角度(弧度),可能会导致碰撞检测不准确0
5text标注文本内容null
6minZoom最小显示级别null
7maxZoom最大显示级别null
8collisionFlg碰撞检测true
9center标注位置,默认为null,会自动计算几何中心null
10zIndex排序0
11defaultHeight文本高度,无法自动计算,所以直接传参手动调整20

        上面的参数是用于在地图中展示标注的属性设置时跟地图相关的。下面来介绍文本的设置。

2、Canvas文本标注属性

        然后介绍一下地图文本部分的属性,这些属性其实与地图无关,仅用于使用Canvas来进行实际的文本标注,因此更多的是Canvas的属性,这里列几个常见的属性(如果增加属性,需要在源码中进行修改),更多的属性可以参考Canvas的相关教学网站:

序号参数说明默认值
1font设置或返回文本内容的当前字体属性。"10px sans-serif",
2fillStyle设置或返回用于填充绘画的颜色、渐变或模式。"rgba(0,0,0,1)"
3lineCap设置或返回线条的结束端点样式。round
4strokeStyle设置或返回用于笔触的颜色、渐变或模式。"rgba(0,0,0,1)"
5textAlign设置或返回文本内容的当前对齐方式。textAlign的值必须是start,end,left,center,right中的一个!center
6textBaseline设置或返回在绘制文本时使用的当前文本基线。textBaseline的值必须是middle,top,hanging,bottom,alphabetic中的一个!middle
7lineWidth设置或返回当前的线条宽度1

3、事件列表

        在组件中允许进行事件绑定,绑定事件后可以实现一些自定义的业务逻辑,比如在点击后修改相应的属性。这里来看下组件允许绑定什么事件。

序号事件说明
1click点击事件
2mousemove鼠标悬浮事件
3mousedown鼠标按下事件
4mouseup鼠标抬起事件

二、属性设置实战

        在了解了上述的属性和事件配置信息之后,本节将重点讲述实战,将重点演示每个属性的设置,通过截图对比区别。

1、标注放大比例

        标注文本比例主要是通过scale这个属性来实现,默认是1,也就是1:1保持一致。这里我们可以不同的场景,比如需要重点警示的需要加大标记或者根据不同的类型设置不同的标注字体大小。文中的示例中是随机创建1000个随机点,前300个随机点是默认大小,300到600个是1.1,最后的是1.3。

        首先需要指定一个经纬度范围,在指定范围内生成1000个随机点。关键代码如下:

var count = 1000;
for (let i = 0; i < count; i++) {
   let latlng = L.latLng(23.95 + Math.random() * 10, 112.40034 + Math.random() * 15);
   var content = "<strong>名称:</strong>城市"+i + "<br/><strong>级别:</strong>"+ i;
	   content += "<br/><strong>所属行政区划:</strong>"+ i + "/" ;
	   content += "<br/><strong>评定时间:</strong>"+ i ;
	  var title = "重要城市" + Math.random();
	  var scaleSize = 1;
	  if(i > 300 && i <= 600){
		scaleSize = 1.1;
        title = "1.1倍" + title;
	  }
	  if(i > 600){
		scaleSize = 1.3;
        title = "1.3倍" + title;
	  }
	  
      let c = L.circleMarker(latlng, {
        radius: 5,
        labelStyle: {
          text: title,
          rotation: 0,
		  scale: scaleSize,
          zIndex: 1,
		  font: "14px Microsoft YaHei",
		  fillStyle:"white",
		  textBaseline: "top" ,
		  minZoom: 5
        }
      }).addTo(showGroup);
	  c.bindPopup(content);
}
map.addLayer(showGroup);

        我们来看一下文本缩放的实际效果:

        需要注意的是,这里的放大比例是在原始设置的font之上的,比如

font: "14px Microsoft YaHei",

         字体的放大也是在14px的基础上进行放大或者缩小的。

2、字体颜色和方向偏移

        在canvasLabel中不仅可以设置字体的大小,还可以设置字体的颜色,还可以设置标注的偏移方向,比如顺时针旋转,逆时针旋转。演示依然是上述例子的数据,按照1/3进行分割,进行颜色和方向的设置。

var color = "white";
var diyRota = 0;
var scaleSize = 1;
if(i > 300 && i <= 600){
	color = "yellow";
	diyRota =  -0.30;
	scaleSize = 1.1;
	title = "1.1倍" + title;
}
if(i > 600){
	color = "red";
	diyRota =  -0.45;
	scaleSize = 1.3;
	title = "1.3倍" + title;
}
	  
let c = L.circleMarker(latlng, {
    radius: 5,
    labelStyle: {
          text: title,
          rotation: diyRota,
		  scale: scaleSize,
          zIndex: 1,
		  font: "14px Microsoft YaHei",
		  fillStyle: color,
		  textBaseline: "top" ,
		  minZoom: 5
        }
}).addTo(showGroup);

        再来看一下上面代码运行的效果:

3、标注文字透明色设置

        组件支持文字的背景颜色为透明色设置,strokeStyle: "#ffffff00", //透明色通过设个属性来设置即可。

//矢量文本标签渲染器
var canvasLabel = new L.CanvasLabel({
      defaultLabelStyle: {
        collisionFlg: true,//碰撞检测,默认true
        scale: 1,
		strokeStyle: "#ffffff00", //透明色
        fillStyle: "#fff",
        lineWidth:3
      }
});

4、标注显示层级

        有时候,我们需要控制标注在某一些级别才能展示,比如根据实际的范围,在至少5级以上的地图才展示出来。在低于5级下,标注不会在界面上展示。

let c = L.circleMarker(latlng, {
        radius: 5,
        labelStyle: {
          text: title,
          rotation: diyRota,
		  scale: scaleSize,
          zIndex: 1,
		  font: "14px Microsoft YaHei",
		  fillStyle: color,
		  textBaseline: "top" ,
		  minZoom: 5
        }
}).addTo(showGroup);

三、事件绑定

         事件绑定机制允许我们对页面显示的空间进行交互和控制,然后通过属性API来操作属性信息,让标注按照我们的预想进行展示。这里举一个例子,抛砖引玉,大家可以琢磨出更有意思的场景出来。本例子以标注被点击为例,我们来设置标注的颜色。

1、颜色改变

        要想实现上述需求,首先要绑定点击事件,然后获取点击的标注信息,再通过API修改相应的属性。下面结合代码来讲解:

//定义事件
canvasLabel.addOnClickListener(function (e, data) {
	//console.log("click", data);
	console.log(data[0].layer.options.labelStyle.fillStyle);
	data[0].layer.options.labelStyle.fillStyle = "#fe57a1";
	canvasLabel._draw();
});

        来看一下实际的效果:

2、事件绑定解析

        为了熟悉事件操作机制,我们来看一下源码中事件的绑定和处理逻辑的,下面是事件注册器,源代码如下,在31行:

getEvents: function () {
        var events = {
            viewreset: this._reset,
            zoom: this._onZoom,
            moveend: this._update,
            zoomend: this._onZoomEnd,
            click: this._executeListeners,
            mousemove: this._executeListeners,
            mousedown: this._executeListeners,
            mouseup: this._executeListeners,
        };
        if (this._zoomAnimated) {
            events.zoomanim = this._onAnimZoom;
        }
        return events;
    },

        我们主要来看click及下面的几个事件,

 /**
  * 执行侦听器
  */
  _executeListeners: function (event) {
        if (!this._textBounds) return;
        var me = this;
        var ret = this.getTextByEvent(event);
        if (ret && ret.length > 0) {
            me._map._container.style.cursor = "pointer";
            if (event.type === "click") {
                me._onClickListeners.forEach(function (listener) {
                    listener(event, ret);
                });
            }
            if (event.type === "mousemove") {
                me._onHoverListeners.forEach(function (listener) {
                    listener(event, ret);
                });
            }
            if (event.type === "mousedown") {
                me._onMouseDownListeners.forEach(function (listener) {
                    listener(event, ret);
                });
            }

            if (event.type === "mouseup") {
                me._onMouseUpListeners.forEach(function (listener) {
                    listener(event, ret);
                });
            }
        } else {
            me._map._container.style.cursor = "";
        }
    },

        最后需要将时间的监听器注册到上下文中,

/**
     * 添加click侦听器
     */
    addOnClickListener: function (listener) {
        this._onClickListeners.push(listener);
    },

    /**
     * 添加hover侦听器
     */
    addOnHoverListener: function (listener) {
        this._onHoverListeners.push(listener);
    },

    /**
     * 添加mousedown侦听器
     */
    addOnMouseDownListener: function (listener) {
        this._onMouseDownListeners.push(listener);
    },

    /**
     * 添加mouseup侦听器
     */
    addOnMouseUpListener: function (listener) {
        this._onMouseUpListeners.push(listener);
    },

3、标记初始化的一个小问题

        大家在进行页面开发的时候,第一次加载页面时一定会发现,由于我们加上了碰撞检测,因此界面的文字效果比较难看,有的标注被截断了尤其在边界的位置处,如下图所示:

         那么这种问题应该怎么解决呢?首先我们发现在碰撞检测中有以下代码:

 // 碰撞检测
var textWidth =ctx.measureText(labelStyle.text).width * labelStyle.scale;
var textHeight = labelStyle.defaultHeight * labelStyle.scale;

let textBounds = { minX, minY, maxX, maxY, layer };
if (
     !(
         labelStyle.collisionFlg == true &&
         this._textBounds.collides(textBounds)
      )
) {
     //绘制标注
     ctx.strokeText(labelStyle.text, 0, 0);
     ctx.fillText(labelStyle.text, 0, 0);
     this._textBounds.insert(textBounds);
}

        也就是说碰撞检测时依赖了组件的宽度,同时我们发现到了界面上进行地图拖动和放大缩小也触发了组件重绘,可以解决这个问题。因此我们模拟进行地图缩放,

map.setZoom(map.getZoom());//调用层级,防止初始展示时都挨在一起

        再来看以下的效果(请注意边界的位置标注):

        可以发现在边界处,标注不再被截断,而是正常展示。

 四、总结

        以上就是本文的主要内容,本文详细介绍leaflet-canvas-label的属性以及事件,首先介绍它的参数列表,然后根据不同的属性进行实例的讲解,最后给出一个完整的演示示例。通过本文您可以掌握leaflet-canvas-label的个性化标注如何实现,包括自定义颜色、字体大小、标注方向、事件的绑定,如何解决标注边界被截断的问题。行文仓促,定有不足之处,欢迎各位专家朋友在评论区批评指正,不甚感激。

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

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

相关文章

html5实现个人网站源码

文章目录 1.设计来源1.1 网站首页页面1.2 个人工具页面1.3 个人日志页面1.4 个人相册页面1.5 给我留言页面 2.效果和源码2.1 动态效果2.2 目录结构 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/139564407 ht…

427. 建立四叉树

427. 建立四叉树 题目难度-中等1. dfs分治 题目难度-中等 给你一个 n * n 矩阵 grid &#xff0c;矩阵由若干 0 和 1 组成。请你用四叉树表示该矩阵 grid 。 你需要返回能表示矩阵 grid 的 四叉树 的根结点。 四叉树数据结构中&#xff0c;每个内部节点只有四个子节点。此外…

音程与和弦 音程协和度

2个音符之间的音程计算 1234567&#xff0c;1到7的音程是7度&#xff0c;音程是计算总长度&#xff0c;看音级的个数。 Cubase中的音程计算 下面一个是4度&#xff0c;一个是3度&#xff0c;格子中深色的行就是黑键行。 根据半音数量来确定对应音程的专业术语叫法 旋律音程、…

国产嵌入式仪器模块:电子负载模块及自动化测试软件

• 输入电流在 0–5 A 范围内线性可调 • 最大功率达 150 W&#xff0c;满足多种定制化应用场景 • 支持 CC/CR/CV 多种工作模式 • 支持多种辅助模块&#xff08;如 PD 控制、信号调制、二维码扫描&#xff09; 应用场景 • 负载能力测试&#xff08;电源或信号&#xff0…

opencv--使用opencv实现旋转角度的模板匹配

下面的例子是简单的使用opencv 实现的模板匹配流程&#xff0c;其中时间性能和精确度还需要调整&#xff0c;如果直接使用会出问题&#xff0c;所以这个只是例子&#xff0c;根据代码原理可以实现尺度变化的模板匹配和旋转尺度变化同时&#xff0c;具体根据实现的旋转代码进一步…

【Unity学习笔记】反射

文章目录 前言反射通过反射获取类型 Unity中的反射用反射在Unity中动态加载 前言 在我平时做项目的时候&#xff0c;由于我们做的项目都是很简单的&#xff0c;所以不怎么接触反射机制。最早了解反射机制是关于Invoke的时候&#xff0c;知道可以通过方法名来直接进行Invoke调用…

【会议征稿,IEEE出版】第三届能源与电力系统国际学术会议 (ICEEPS 2024,7月14-16)

如今&#xff0c;全球能源行业正面临着前所未有的挑战。一方面&#xff0c;加快向清洁、可再生能源转型是遏制能源环境污染问题的最佳途径之一&#xff1b;另一方面&#xff0c;电力系统中新能源发电、人工智能技术、电力电子装备等被广泛应用和期待&#xff0c;以提高能源可持…

汇编:结构体

在32位汇编中&#xff0c;结构体&#xff08;structures&#xff09;用于组织和管理复杂的数据类型&#xff0c;结构体可以包含多个不同类型的数据项&#xff08;成员&#xff09;&#xff1b;在MASM&#xff08;Microsoft Macro Assembler&#xff09;中&#xff0c;使用结构体…

Qt——升级系列(Level Four):控件概述、QWidget 核心属性、按钮类控件

目录 控件概述 QWidget 核心属性 核心属性概览 enabled geometry windowTitle windowIcon windowOpacity cursor font toolTip focusPolicy styleSheet 按钮类控件 Push Button Radio Buttion Check Box Tool Button 控件概述 Widget 是 Qt 中的核⼼概念. 英⽂原义是 "…

10.结构体、共用体、枚举

头文件&#xff1a;#include<string.h> //struct&#xff1a;结构体关键字 //stu&#xff1a;结构体类型名&#xff0c;指定了一个结构体类型&#xff0c;它相当于一个模型&#xff0c;但其中并无具体数据&#xff0c;系统对之也不分配实际内存单元//使用结构体类型必须是…

CDR2024软件破解Keygen激活工具2024最新版

CorelDRAW Graphics Suite2024最新版&#xff0c;这是一款让我爱不释手的图形设计神器&#xff01;作为一个软件评测专家&#xff0c;我一直在寻找一款能够提升我的设计效率和创造力的工具。而这款软件&#xff0c;简直就是为我量身定制的&#xff01;&#x1f389; 「CorelDR…

北航第五次数据结构与程序设计编程题复习

北航第五次数据结构与程序设计编程题复习 树叶节点遍历&#xff08;树-基础题&#xff09;计算器&#xff08;表达式计算-表达式树实现&#xff09;服务优化词频统计&#xff08;树实现&#xff09; 树叶节点遍历&#xff08;树-基础题&#xff09; 【问题描述】 从标准输入中…

OpenCV学习(4.9) OpenCV中的轮廓

1.目标 了解轮廓是什么。学习寻找轮廓&#xff0c;绘制轮廓等您将看到以下功能&#xff1a;**cv.findContours()** &#xff0c;**cv.drawContours()* 2.什么是轮廓 轮廓可以简单地解释为连接具有相同颜色或强度的所有连续点(沿边界)的曲线。轮廓是用于形状分析以及对象检测…

嵌入式学习——Linux高级编程复习(互斥锁、信号量、管道、信号)——day41

1. 同步和异步 1.1 同步 多个任务在某一时刻,先后执行顺序可以被确定 同步操作要求一系列操作严格按照顺序执行&#xff0c;一个操作只有在前一个操作完成之后才能开始。在计算机编程中&#xff0c;这意味着当一个程序或线程发出一个请求或调用后&#xff0c;它会暂停执行&…

java自动化之java基础03-09java基础之数组

数组 1、定义 数组是一种用于存储固定大小的同类型数据的数据结构 1&#xff09;固定大小 2&#xff09;同类型数据的存储 2、声明数组 1&#xff09;数据类型[] 变量名称&#xff1b; 例如&#xff1a;int[] numsArry; 2&#xff09;数据类型 变量名称[]; 例如&#xf…

27.机会成本

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/677 题目描述 明天有 𝑛n 门考试,今晚只…

【C++修行之道】类和对象(五)日期类的实现、const成员、取地址及const和取地址操作符重载

目录 一、 日期类的实现 Date.h 1.1 GetMonthDay函数&#xff08;获取某年某月的天数&#xff09; 问&#xff1a;这个函数为什么不和其他的函数一样放在Date.cpp文件中实现呢&#xff1f; 1.2 CheckDate函数&#xff08;检查日期有效性&#xff09;、Print函数&#xff08;…

计算机毕业设计 | SpringBoot宠物医院管理 宠物商城购物系统(附源码)

写在前面 Le Dao宠物医院管理系统是一个超大型的&#xff0c;完成度很高的&#xff0c;集宠物医疗、宠物美容、宠物交易、宠物周边等各种功能于一身的&#xff0c;权限涵盖普通用户、医生、化验师、美容师、仓库主管、采购员等多种角色于一体的大型宠物医疗&#xff0c;购物系…

Java 数据类型 -- Java 语言的 8 种基本数据类型、字符串与数组

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 004 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

1035 插入与归并(测试点6)

solution 类型判断&#xff1a;插入排序中已排序的部分有序&#xff0c;未排序的和原数组元素相同&#xff1b;否则为归并排序测试点6&#xff1a;对于归并排序的子序列长度&#xff0c;不能简单视为前k个有序则子序列长度就是k 例如该测试用例的归并排序的子序列长度应该为2&…