一种基于Leaflet.Legend的图例动态更新方法

目录

前言

一、场景再现

1、需求描述

2、核心方法介绍

3、存在的问题

二、问题解决

1、重复解决办法

2、图例不展示解决办法

3、成果展示

三、总结


前言

        在当今数字化时代,地理信息系统(GIS)技术已经广泛应用于各个领域,从城市规划到环境监测,从交通管理到资源勘探等。而地图可视化作为 GIS 的重要组成部分,为用户提供了直观、便捷的方式来展示和分析地理空间数据。Leaflet 作为一种轻量级、开源的地图库,因其简单易用、高度可定制化以及良好的兼容性,受到了众多开发者的青睐,被广泛应用于各种地图应用的开发中。而在地图可视化中,图例的作用不可忽视。它为用户提供了地图上各种符号、颜色和图层所代表的含义,帮助用户更好地理解和解读地图信息。

        关于如何在Leaflet中进行图例生成,原博文介绍:LeafLet加载自定义Legend的设计与实现。在后面的项目当中基本都是一次性生成图例,然后在地图上展示。然而,在最近的实际开发过程中,遇到了一个棘手的问题:Leaflet 的图例无法动态更新。当地图上的数据发生变化,例如添加或移除图层、修改图层样式、更新数据源等时,图例却无法及时反映这些变化,这给用户带来了极大的不便,也影响了地图应用的用户体验和实用性。因此需要程序能根据变化或者事件响应动态更新。在实际实践中我们发现,leaflet.legend的图例动态更新存在一定的局限性。它通常是基于初始加载时的图层和样式信息来生成图例的,而当这些信息发生变化时,图例并不会自动重新生成或更新。这使得开发者在面对动态数据和交互式地图时,难以实现图例与地图的同步更新。

        本篇文章将深入探讨解决 Leaflet.Legend 图例无法动态更新的一种方法。我们将从问题出发,分析现有解决方案的不足之处,然后详细介绍一种基于事件监听和动态渲染机制的方法。通过这种方法,我们可以在地图数据发生变化时,自动检测并动态更新图例,确保图例始终与地图上的数据保持一致。我们将通过实际代码示例和测试结果,展示该方法的有效性和可行性,并探讨其在不同应用场景中的适用性和优化方向。

        通过本文的介绍,希望能够为广大的 Leaflet 开发者提供一种全新的思路和实用的解决方案,帮助他们在地图开发过程中更好地应对图例动态更新的挑战,提升地图应用的质量和用户体验。同时,也期待与更多开发者交流和分享经验,共同推动 Leaflet 技术的发展和创新。

一、场景再现

        本节将从需求场景、核心方法介绍、存在的问题三个方面对开发过程遇到的问题进行讲解。通过本节的阐述,可以让朋友们对leaflet.legend的核心方法有更详细的认识,通过结合核心API方法和存在的问题,为下一步问题的解决奠定方向和基础。

1、需求描述

        在以往的一些WebGIS应用展示中,比如展示地震的震级、风景区的等级等,这些图例信息往往都是固定的,我们可以将地震震级分成不同的震级,比如3级以下,3-5级,5-7级,7级以上等。又比如在风景区的等级中中的5A、4A、3A、2A、1A等,如下图。

        这些图例在地图进行展示时基本上已经是固定的,后续需要动态变化的只是调整数据的输出,而图例基本上是不会改变的。暂且我们将这些图例成为静态图例。与这种需求不一样的是,如果在应用中,我们需要动态切换数据图层,比如从行政区划图层切换到土地利用图层,图例不仅内容也要发生变化,即维度的变化。同时在渲染的样式、具体的图例文字方面都要进行变化,内容上从行政区划名称切换成不同的土地利用类型。还有一些场景是跟随时间维度变化的,随着时间的推移,图例会新增或者移除部分老的图例。比如在在风景区分级中,需要将2A和3A级景区进行合并。从而减少图例的展示个数。这样的场景非常多,不管是基于事件驱动还是时间驱动,都会对关联的图例的有所影响。以上就是本文遇到的几个需求场景,这里只描述了其中的一两种,现实当中肯定有更多的场景,就不注意列举了。

2、核心方法介绍

        与后端的OOP编程思想相类似,前端也是采用类似OOP的思想进行开发。因此对相关的对象的属性和方法进行封装。关于leaflet.legend的属性,这里不再进行赘述,但是对核心的API方法还是需要进行详细叙述。因为在进行图例内容的动态生成中,肯定需要调用leaflet.legend提供的方法来实现图例的动态生成的。这里将详细介绍其相关的方法。

        除了对象的Options配置参数外,以上就是比较重要的几个API方法。 下面将对图例对象的初始化、图例容器构建、图例绘制、事件响应、重绘等几个方法进行介绍。帮助大家对组件有更深入的理解。我们来看一下在原来的代码中是如何将图例添加到地图中的,原始方法代码如下:

function updateLegend(legendData){var legend = L.control.Legend({position: "bottomright",collapsed: false,symbolWidth: 24,opacity: 1,title:"图例",column: 2,legends: legendData});legend.addTo(map);
}

        在Javascript中进行代码断点来看一下将legend对象添加到地图后,会发生什么? 首先将调用的是initialize()方法,可以在参数入口处看到传入的参数。

        在将图例符号进行清空后,将进行图例容器对象的创建,调用的_buildContainer()方法,以此来绑定和展示图例信息。

        请注意,在这里创建用于图例展示的div容器(这个方法很重要,请注意这个方法,在这个方法里,会创建容器,在后面的问题解决过程中会涉及重复对象的创建,因此在调整时需要规避这个问题), 在这个方法中,通过循环配置参数中的不同图例信息,循环构建图例信息。构建图例元素的方法是:_buildLegendItems();

        通过以上对核心方法的介绍,相信大家对于组件的相关API有了进一步的认识。在后面的问题解决阶段还会对这些方法有所涉及。

3、存在的问题

        在最开始开发的时候,往往由于没有深入的研究相关的API,极容易出现一些错误。比如图例越来越多,在地图上的位置都展示不了了。又或者是事件触发后,相应的图例并没有生成,没有任何效果,当前图例没有生成,或者是产生了报错。下面我们对这几种情况分别进行说明,如最开始的代码所示,第一种情况就是图例越来越多。

function updateLegend(legendData){var legend = L.control.Legend({position: "bottomright",collapsed: false,symbolWidth: 24,opacity: 1,title:"图例",column: 2,legends: legendData});legend.addTo(map);
}

        程序运行后,可以在图例的展示栏中看到图例越来越多,虽然新的产生了,但老的没有替换到。如下图所示:

         第二种情况是开发的同学稍微了解组件的方法,在获得legend对象后,重新对图例数据进行赋值,然后调用重绘的方法,代码如下:

function updateLegend(legendData){if(undefined == legend){legend = L.control.Legend({position: "bottomright",collapsed: false,symbolWidth: 24,opacity: 1,title:"图例",column: 2,legends: legendData});}else{//step1、重新设置数据legend.options.legends = legendData;//step2、重新绘制legend.redraw();}legend.addTo(map);
}

        咋一看起来,似乎是非常好的解决办法,但是实际运行后却是以下的情况:

        不仅没有出现新的图例,老的图例都消失了。 在查看浏览器的控制台时,可以发现以下的报错:

        更详细的是以下的代码行中出现问题,在这个重绘的方法中,其调用的是构建单个图例的重绘。在方法调用时需要传入容器对象和当前的图例对象。在redraw方法中,传入了空的值。类似于报了空指针异常。

        以上就是在开发当中极易碰到的问题,这里先讲讲遇到的两个问题场景,如果您开发当中也遇到这种问题,不妨来这里看看。 

二、问题解决

        本节将重点围绕第一节中的遇到的问题,重点对发现或者产生的问题进行解决。主要是围绕图例的重复生成、图例的正确重绘方法进行介绍,在介绍的过程中又会回顾到前面的API核心接口讲解。因此这是一个动手的过程,希望你可以跟着一起来动手实践,纸上得来终觉浅,绝知此事要躬行。只有经过自己的亲自动手,才能彻底得掌握如何应对和解决。

        为了模拟图例的动态生成,在Leaflet页面上,新增了一个“图例更新”的按钮,用这个按钮的模拟事件来进行模拟需要动态切换的场景。模拟的按钮及其相关处理事件如下:

<div class="center-flex"><input type="button" class="opt_button" value="更新图例" onclick="updateLegendEvent()"></input>
</div>

        其处理的回调方法如下,请注意在程序中设置一个标志位,用于切换不同的图例数据对象,在真实情况中,可以通过ajax来请求服务的接口后获得:

function updateLegendEvent(){var updateLegendData;if(sign == 0 ){updateLegendData = [{label: "位置",type: "image",url: "marker/marker-red.png"}, {label: "Marker2",type: "image",url: "marker/purple.png"}];sign = 1;} else {updateLegendData = initLegendData;sign = 0;}updateLegend(updateLegendData);
}

        在有了事件的驱动之后,接下来就是图例对象的定义和展示。下面将深入如何避免在上一节中遇到的问题,针对性的提出解决办法。

1、重复解决办法

        为了解决在图例生成时的重复问题,我们可以在进行图例对象生成时只生成一份,后续则在之前的对象中调用方法来修改相应的参数,以此来达到相应的目的。这个代码比较简单,在前面的方法中提到过,在初始化时增加一个判断,如果为空就创建对象,否则使用原来的对象:

function updateLegend(legendData){if(undefined == legend){legend = L.control.Legend({position: "bottomright",collapsed: false,symbolWidth: 24,opacity: 1,title:"图例",column: 2,legends: legendData});}else{//step1、重新设置数据legend.options.legends = legendData;//step2、重新绘制legend.redraw();}legend.addTo(map);
}

        通过以上的代码就能避免图例对象重复创建的问题。 

2、图例不展示解决办法

        在解决图例的重复问题之后,又迎来一个新的难题,即图例在切换后不展示了。这又是什么问题呢?其实答案在第一节中的第三小节中已经有说明。在上面的代码中,我们调用的是redraw的方法,而这个方法最终调用的是_buildLegendItems: function (legendContainer, legend) {}方法,在这个方法中,需要传入一个图例容器和一个图例对象,而在redraw方法中并没有涉及这两个对象。因此才报的错。那么如何避免这种问题呢?解铃还须系铃人,要想解决图例不展示的问题,还得找到核心的问题,在前面的核心方法中,我们知道一套完备的可视化展示流程。即initialize方法调用_buildContainer方法,同时在_buildContainer方法中又会循环调用_buildLegendItems。通过这种方法,就会传入容器和图例对象,按照这种调用思路,在设置新的数据后,程序需要做的就是重新初始化,这样就会清空当前的图例对象,同时生成最新的图例。代码如下:

function updateLegend(legendData){if(undefined == legend){legend = L.control.Legend({position: "bottomright",collapsed: false,symbolWidth: 24,opacity: 1,title:"图例",column: 2,legends: legendData});}else{//动态加载图例的实现方式//step1、重新设置数据legend.options.legends = legendData;//step2、重新初始化(重新绘制)legend.initialize();}legend.addTo(map);
}

        将代码进行改造后,图例可以正常展示了,但是重复的问题又产生了。如下图:

        难道这种问题没有解决办法了么?仔细再想想,在初始化的方法中,依然还会创建容器对象出来,来看看它的源代码:

        可以看到这个图例容器依然会重新创建,因此还是会产生重复。最终的答案是在每次初始化前将容器移除掉。代码很简单,如下:

function updateLegend(legendData){if(undefined == legend){legend = L.control.Legend({position: "bottomright",collapsed: false,symbolWidth: 24,opacity: 1,title:"图例",column: 2,legends: legendData});}else{//动态加载图例的实现方式//step1、重新设置数据legend.options.legends = legendData;//step2、销毁图例容器,保证不重复legend.getContainer().remove();//step3、重新初始化(重新绘制)legend.initialize();}legend.addTo(map);
}

3、成果展示

        经过上述的改造,就能完美的解决图例重复已经切换后不展示的问题,下面来看一下最终的成果,点击“图例更新”按钮后,图例可以进行不停的切换,基本实现我们的需求,图例不会重复生成,也不会不见,控制台也不会报错,最终效果如下图所示:

三、总结

        以上就是本文的主要内容,本篇文章将深入探讨解决 Leaflet.Legend 图例无法动态更新的一种方法。我们将从问题出发,分析现有解决方案的不足之处,然后详细介绍一种基于事件监听和动态渲染机制的方法。通过这种方法,我们可以在地图数据发生变化时,自动检测并动态更新图例,确保图例始终与地图上的数据保持一致。我们将通过实际代码示例和测试结果,展示该方法的有效性和可行性,并探讨其在不同应用场景中的适用性和优化方向。

        通过本文的介绍,希望能够为广大的 Leaflet 开发者提供一种全新的思路和实用的解决方案,帮助他们在地图开发过程中更好地应对图例动态更新的挑战,提升地图应用的质量和用户体验。同时,也期待与更多开发者交流和分享经验,共同推动 Leaflet 技术的发展和创新。行文仓促,定有许多不足之处,如有不足在此恳请各位专家朋友批评指正,不胜感激。

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

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

相关文章

【AI时代】使用ollama私有化部署deepseek的过程及问题记录

文章目录 说明下载模型通过ollama下载通过modelscope下载 部署open-webui问题记录临时目录空间不足单机多卡部署后台启动 说明 对于DeepSeek的私有化部署&#xff0c;现在网上已经有很全面的资料了&#xff0c;本文主要记录部署以及部署过程中遇到的问题。目前对于这些问题&am…

使用 SDKMAN! 在 Mac(包括 ARM 架构的 M1/M2 芯片)上安装 Java 8

文章目录 1. 安装 SDKMAN!2. 查找可用的 Java 8 版本3. 安装 Java 84. 验证安装5. 切换 Java 版本&#xff08;可选&#xff09;6. 解决 ARM 架构兼容性问题总结 可以使用 SDKMAN! 在 Mac&#xff08;包括 ARM 架构的 M1/M2 芯片&#xff09;上安装 Java 8。SDKMAN! 是一个强大…

存储异常导致的Oracle重大生产故障

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验 Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯…

计算机视觉-拟合

一、拟合 拟合的作用主要是给物体有一个更好的描述 根据任务选择对应的方法&#xff08;最小二乘&#xff0c;全最小二乘&#xff0c;鲁棒最小二乘&#xff0c;RANSAC&#xff09; 边缘提取只能告诉边&#xff0c;但是给不出来数学描述&#xff08;应该告诉这个点线是谁的&a…

【自开发工具介绍】SQLSERVER的ImpDp和ExpDp工具演示05

SQLSERVER的ImpDp和ExpDp工具演示 1、表部分数据导出 (-query) ※「-query」和「-include_table」必须一起使用 「-query」后面字符串是sql文的where语句&#xff0c;但要注意要使用%&#xff0c;需要写%% 验证用&#xff1a;导出的表&#xff0c;导入到新的数据库 db的数…

《qt6+Open3d网格读取》

《qt6+Open3d网格读取》 效果显示一、创建步骤1.1 创建动作及槽函数二、注意效果显示 一、创建步骤 1.1 创建动作及槽函数 按照以下步骤创建动作,并将动作拉入菜单栏文件中,创建槽函数。 在mainwindow.h添加 private:geometry

mapbox进阶,添加绘图扩展插件,绘制圆形

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…

C#控件开发6—指示灯

按钮功能&#xff1a;手自动旋转&#xff0c;标签文本显示、点击二次弹框确认&#xff08;源码在最后边&#xff09;&#xff1b; 【制作方法】 找到控件的中心坐标&#xff0c;画背景外环、内圆&#xff1b;再绘制矩形开关&#xff0c;进行角度旋转即可获得&#xff1b; 【关…

电商平台的设计与实现(代码+数据库+LW)

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统商品交易信息管理难度大&#xff0c;容错率低&#xff0…

【deepseek实战】绿色好用,不断网

前言 最佳deepseek火热网络&#xff0c;我也开发一款windows的电脑端&#xff0c;接入了deepseek&#xff0c;基本是复刻了网页端&#xff0c;还加入一些特色功能。 助力国内AI&#xff0c;发出自己的热量 说一下开发过程和内容的使用吧。 目录 一、介绍 二、具体工作 1.1、引…

【OS】AUTOSAR架构下的Interrupt详解(上篇)

目录 前言 正文 1.中断概念分析 1.1 中断处理API 1.2 中断级别 1.3 中断向量表 1.4 二类中断的嵌套 1.4.1概述 1.4.2激活 1.5一类中断 1.5.1一类中断的实现 1.5.2一类中断的嵌套 1.5.3在StartOS之前的1类ISR 1.5.4使用1类中断时的注意事项 1.6中断源的初始化 1.…

llama.cpp GGUF 模型格式

llama.cpp GGUF 模型格式 1. Specification1.1. GGUF Naming Convention (命名规则)1.1.1. Validating Above Naming Convention 1.2. File Structure 2. Standardized key-value pairs2.1. General2.1.1. Required2.1.2. General metadata2.1.3. Source metadata 2.2. LLM2.2.…

Java/Kotlin双语革命性ORM框架Jimmer(一)——介绍与简单使用

概览 Jimmer是一个Java/Kotlin双语框架 包含一个革命性的ORM 以此ORM为基础打造了一套综合性方案解决方案&#xff0c;包括 DTO语言 更全面更强大的缓存机制&#xff0c;以及高度自动化的缓存一致性 更强大客户端文档和代码生成能力&#xff0c;包括Jimmer独创的远程异常 …

yolov11模型在Android设备上运行【踩坑记录】

0) 参考资料: https://github.com/Tencent/ncnn?tabreadme-ov-file https://github.com/pnnx/pnnx https://github.com/nihui/ncnn-android-yolov5 https://github.com/Tencent/ncnn?tabreadme-ov-file 1) &#xff1a;将xxx.pt模型转化成 xxx.onnx ONNX&#xff08;Ope…

快速上手——.net封装使用DeekSeek-V3 模型

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,用爱发电,去丈量人心,是否能达到人机合一?开工大吉 新的一年就这么水灵灵的开始了,在这里,祝各位读者新春快乐,万事如意! 新年伊…

【WebLogic】Oracle发布WebLogic 14c最新版本-14.1.2.0

根据Oracle官方产品经理的博客&#xff0c;Oracle于2024年12月20日正式对外发布了WebLogic 14c的第二个正式版本&#xff0c;版本号为 14.1.2.0.0 &#xff0c;目前官方已开放客户端下载。该版本除继续支持 Jakarta EE 8 版本外&#xff0c;还增加了对 Java SE 17&#xff08;J…

Spider 数据集上实现nlp2sql训练任务

NLP2SQL&#xff08;自然语言处理到 SQL 查询的转换&#xff09;是一个重要的自然语言处理&#xff08;NLP&#xff09;任务&#xff0c;其目标是将用户的自然语言问题转换为相应的 SQL 查询。这一任务在许多场景下具有广泛的应用&#xff0c;尤其是在与数据库交互的场景中&…

IDEA+DeepSeek让Java开发起飞

1.获取DeepSeek秘钥 登录DeepSeek官网 : https://www.deepseek.com/ 进入API开放平台&#xff0c;第一次需要注册一个账号 进去之后需要创建一个API KEY&#xff0c;然后把APIkey记录保存下来 接着我们获取DeepSeek的API对话接口地址&#xff0c;点击左边的&#xff1a;接口…

intra-mart实现简易登录页面笔记

一、前言 最近在学习intra-mart框架&#xff0c;在此总结下笔记。 intra-mart是一个前后端不分离的框架&#xff0c;开发时主要用的就是xml、html、js这几个文件&#xff1b; xml文件当做配置文件&#xff0c;html当做前端页面文件&#xff0c;js当做后端文件&#xff08;js里…

Linux+Docer 容器化部署之 Shell 语法入门篇 【Shell 替代】

&#x1f380;&#x1f380;Shell语法入门篇 系列篇 &#x1f380;&#x1f380; LinuxDocer 容器化部署之 Shell 语法入门篇 【准备阶段】LinuxDocer 容器化部署之 Shell 语法入门篇 【Shell变量】LinuxDocer 容器化部署之 Shell 语法入门篇 【Shell数组与函数】LinuxDocer 容…