目录

前言

一、关于Leaflet.Legend组件

1、Legend组件的主要参数

2、相关参数

二、Legend图例可视化控制

1、违规教培信息的管理

2、违规培训信息时空可视化及图例渲染控制 

 3、成果展示

三、总结


前言

        在很多的地理时空分析系统中,我们经常会遇到一些需求。比如在地图中,我们会结合内容的分类来进行图例的展示,而图例不仅承担着区分的作用,同时还可能承担着展示不同数据的重要作用。比如在Echarts这类的图形报表效果展示中,我们在图表上要展示相应的数据,在图形的左边还展示了一些图例,通过这些图例,我们可以选择进行数据的展示与隐藏。通过使用鼠标的点击来进行不同状态的切换。当然,在Echarts当中,已经有现成的解决方案,我们可以直接使用组件提供的功能即可。

基于Leaflet Legend的图例数据筛选实践-以某市教培时空分布为例_Legend图例控制

        与这种图表的应用很相似,在地理信息系统建设过程当中,也会有许多的图表和图例生成。以我们常见的Leaflet渲染框架为例,它的图例控件需要自己去定义。 我们在之前的博文中,也介绍了一款基于Leaflet的Leaflet Legend的图例组件。但是没有讲解如何在这款图例生成软件中来进行图例的切换和数据的隐藏与控制。

基于Leaflet Legend的图例数据筛选实践-以某市教培时空分布为例_Legend图例控制_02

        本文即在这样的背景下诞生。本文以Leaflet Legend为例,结合之前采集的某市校外违规培训的时空数据,首先讲解如何进行数据的空间可视化,然后讲解Leaflet.Legend这款组件的具体应用,最后将数据和组件进行融合,讲解如何实现在图例上进行切换实现空间数据的切换与隐藏。如果您对基于图例的时空可视化渲染有兴趣,不妨来本文看看。

一、关于Leaflet.Legend组件

        在正式介绍本文的主要内容之前,请允许在这里花一点时间将Leaflet.Legend这个组件来简单进行介绍,对这个组件熟悉的朋友就当做加深了解。如果对Legend图例组件不是很熟悉的朋友刚好可以利用这个机会来深入认识一下。本节从两个方面来进行介绍,第一个方面是关于Legend这个组件的主要参数;另一个方面则简要介绍Legend的主要方法和实现。

1、Legend组件的主要参数

        Leaflet.Legend 是一个 Leaflet 插件, 用于显示图例符号和切换相应的叠加层的显示。对Legend的源码感兴趣的同学可以在Github或者Git上找到它的源代码, Leaflet.Legend

基于Leaflet Legend的图例数据筛选实践-以某市教培时空分布为例_数据_03

        大家可以把源代码clone下来,插件比较小,很简单。里面的代码相信大家都能很轻松的看懂。 同时这款插件采用的开源协议是MIT的,因此您可以免费的放心使用。

2、相关参数

        为了更详细的介绍和展示这款组件的功能,下面对Legend组件的相关参数来进行简单介绍,方便大家在使用时对它的属性有一个比较全面的了解。

选项

类型

默认值

描述

position

String

'topleft'

图例控件位置。

title

String

'Legend'

图例控件的标题。

opacity

Number

1.0

图例面板的透明度。

legends

LegendSymbol[]

[]

 LegendSymbol 图例符号数组。

symbolWidth

Number

24

图例符号的宽度,以像素为单位。

symbolHeight

Number

24

图例符号的高度,以像素为单位。

column

Number

1

图例符号排列的列数。

collapsed

Boolean

false

图例面板是否默认展开。

        关于上面的属性定义,大家也可以在clone下来的原始代码中找到,在src/leaflet.legend.js这个文件当中的第199行,代码如下所示:

L.Control.Legend = L.Control.extend({
        options: {
            position: "topleft",
            title: "Legend",
            legends: [],
            symbolWidth: 24,
            symbolHeight: 24,
            opacity: 1.0,
            column: 1,
            collapsed: false,
        },
        xxx
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

        既然是图例,肯定最重要还得是图例组件的属性介绍,也就是上面的表格中的LegendSymbol,我们来看下LegendSymbol的具体属性:

选项

类型

默认值

描述

label

String

undefined

图例符号的文本标签。

type

String

undefined

图例符号的类型. 可以是 'image','circle','rectangle','polygon' 或 'polyline'。

url

String

undefined

图里图片的 URL,仅用于 type 为 'image' 时。

radius

Number

undefined

圆形图例的半径,以像素为单位,仅用于 type 为 'circle' 时。

sides

Number

undefined

正多边形的边数,仅用于 type 为 'polygon' 时。

layers

Layer|Layer[]

undefined

图例符号关联的叠加层. 关联叠加层后可通过点击图例来切换相应叠加层的可见性。

inactive

Boolean

undefined

图例符号是否为非激活的, 非激活的图例会减淡显示。

stroke

Boolean

true

是否绘制边框。

color

String

'#3388ff'

边框颜色。

weight

Number

3

边框宽度。

opacity

Number

1.0

边框透明度。

lineCap

String

'round'

指定如何绘制每一条线段末端的属性。有 3 个可能的值,分别是:'butt','round' 或 ’square‘。

lineJoin

String

'round'

用来设置2个长度不为0的相连部分(线段,圆弧,曲线)如何连接在一起的属性(长度为0的变形部分,其指定的末端和控制点在同一位置,会被忽略)。

dashArray

String

null

控制用来描边的点划线的图案范式。

dashOffset

String

null

dash模式到路径开始的距离。

fill

Boolean

depends

是否用颜色填充。

fillColor

String

*

填充色,默认与边框颜色相同

fillOpacity

Number

0.2

填充透明度。

fillRule

String

'evenodd'

填充规则。

是Layers这个参数,这个参数就是实现我们今天核心主题的钥匙。要想实现图例的切换,就是依靠上面的Layers这个图层参数。同时注意查看这个Layers这个属性,它的值可以是一个对象也可以是一个数组,比如多个点对象集合。通过Leaflet.Legend.js源码可以看到一些它的初始化状态和属性信息:

_style() {
            var ctx = (this._ctx = this._canvas.getContext("2d"));
            if (this._legend.fill || this._legend.fillColor) {
                ctx.globalAlpha = this._legend.fillOpacity || 1;
                ctx.fillStyle = this._legend.fillColor || this._legend.color;
                ctx.fill(this._legend.fillRule || "evenodd");
            }

            if (this._legend.stroke || this._legend.color) {
                if (this._legend.dashArray) {
                    ctx.setLineDash(this._legend.dashArray || []);
                }
                ctx.globalAlpha = this._legend.opacity || 1.0;
                ctx.lineWidth = this._legend.weight || 2;
                ctx.strokeStyle = this._legend.color || "#3388ff";
                ctx.lineCap = this._legend.lineCap || "round";
                ctx.lineJoin = this._legend.lineJoin || "round";
                ctx.stroke();
            }
        }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

        在介绍了上面的API信息之后,我们来看一下具体如何实现基于Legend的图例可视化开关。

二、Legend图例可视化控制

        本节将重点介绍在Legend中如何进行图例的切换与数据绑定,在图例生成和绑定过程中可能会遇到一些问题,也会介绍如何介绍这些问题,最终实现可以点击图例来进行相应数据的显示与隐藏。由于会涉及之前的违规教培信息的可视化展示,因此如果对违规教培的数据和采集不熟悉的,可以翻阅博主早些时候的一些博客。里面有相关信息的叙述,闲言少语,我们直接加进入正题。

1、违规教培信息的管理

        作为数据可视化的核心,违规教培信息的管理尤其重要。违规教培信息在这里包含两个方面的信息,第一个方面是基本信息,比如机构的信息、机构的地址、违规培训的类型、发布的日期、信息的来源等,另一方面就是空间信息,比如这个机构信息是在长沙而不是上海。这属于空间坐标位置信息。同样是重要的,因此我们可以进行统一的登记管理。这里仅展示管理的功能界面,大多数的功能界面都是增删改查,因此没有过多的叙述。

基于Leaflet Legend的图例数据筛选实践-以某市教培时空分布为例_图例_04

        上图仅展示了违规教培信息的列表信息,系统支持新增单条信息,也支持编辑单条培训信息,可以进行新处罚机构的信息录入,也可以进行信息的调整。 

基于Leaflet Legend的图例数据筛选实践-以某市教培时空分布为例_Leaflet 图例控制切换_05

2、违规培训信息时空可视化及图例渲染控制 

        在上面的违规培训信息管理中,我们已经实现了基本信息的管理,本小节中将进行赋予了经纬度信息的违规培训机构信息时空可视化展示。同时基于Legend的图例控制器来进行不同违规类型的切换与隐藏展示。当然,如果不想在图例上进行数据的安全过滤,也可以考虑做到全局的数据过滤中,直接在sql中加入where条件即可。

        要想实现基于Legend的图例数据切换,结合在最前面介绍的API接口,我们来梳理一下如何进行实现(至于其他的比如底图的加载与初始化,由于在之前的博客中已经讲解了很多,这里不再进行赘述)。第一步、根据之前的基本数据,违规培训的类型可以分为:隐形变异学科培训、无证非学科类培训、有证机构违规办学这三种,因此我们需要在地图上初始化这三类图例。同时,为了能将图例和数据进行一一对应,我们定义三个数组,在请求后台的数据时,根据不同的数据类型来进行赋值,最后将图例添加到地图组件中,就圆满的完成了图例的可视化。

        首先我们定义三个空的数组,用来接收三类违规培训的类型,代码如下:

var training1 = new Array();//隐形变异学科培训
var training2 = new Array();//无证非学科类培训
var training3 = new Array();//有证机构违规办学
  • 1.
  • 2.
  • 3.

        然后,获取所有的违规培训信息,根据三类违规培训类型,对上面的三个数组进行赋值。

function showViolationTraining(){
     $.ajax({  
		  type:"get",  
		  url:prefix + "/globallist",  
		  dataType:"json",  
		  cache:false,
		  processData:false,
		  success:function(result){
		       if(result.code == web_status.SUCCESS){
		        	var strokeStyleSet = "#c50808";
		        	var lat,lng,cityInfo;
		        	for(var i=0;i < result.data.length;i++){
		        		var dataInfo = result.data[i];
		        		if(dataInfo.geomJson != null){
		        			var geomObj = JSON.parse(dataInfo.geomJson);
			        		var radiusSize = 6;
			        		switch(dataInfo.type) {
				        		case '无证非学科类培训':  
				        		    strokeStyleSet = "#168d40";
				        		    break;
				        		case '有证机构违规办学':  
				        		    strokeStyleSet = "#2196f3";
				        		    break;
				        		default:
				        		    strokeStyleSet = "#c50808";
				        	}
		    				var content = "<strong>机构名称:</strong>"+dataInfo.name + "<br/><strong>地址:</strong>"+dataInfo.address;
		    				content += "<br/><strong>发布时间:</strong>"+dataInfo.publishDate + "<br/><strong>类型:</strong>"+dataInfo.type;
			    			var latlng = new L.latLng(geomObj.coordinates[1], geomObj.coordinates[0]);
			    			let marker = L.circleMarker(latlng, {
			        		     radius: radiusSize,
			        		    color: strokeStyleSet,//这里设置的是circleMarker的颜色属性
			        		    labelStyle: {
			        		       offsetX: 0, //横坐标偏移(像素)
			        		       offsetY: 30, //纵坐标偏移(像素)
			        		       text: dataInfo.name,
			        		       rotation: 0,
			        		       zIndex: radiusSize,
			        			   minZoom : 2,
			        		      fillStyle: strokeStyleSet
			        		     }
		        		     }).addTo(showLayerGroup);
		        		     switch(dataInfo.type) {
				        		    case '无证非学科类培训':  
				        		    	training2.push(marker);
				        		        break;
				        		    case '有证机构违规办学':  
				        		    	training3.push(marker);
				        		        break;
				        		    default:
		        		      			training1.push(marker);
				        		}
			    				marker.bindPopup(content); 
		        			}
		        		}
		        		mymap.addLayer(showLayerGroup);
		        	}
		        },
		        error:function(){
		        	$.modal.alertWarning("获取信息失败");
		        }
		    });
        }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.

        最后,将图例和数据进行绑定,关键代码如下:

function initLegend(){
	 const legend = L.control.Legend({
	      position: "bottomright",
	      collapsed: false,
	      symbolWidth: 35,
	      opacity: 1,
		  title:"图例",
	      column: 1,
	      legends: [ {
	          label: "\xa0\xa0 隐形变异学科培训",//一定要注意这里的转义字符
	          type: "rectangle",
	          color: "#c50808",
	          fillColor: "#c50808",
	          weight: 2,
	          layers: training1,
	          inactive: false
	       }, {
	          label: "\xa0\xa0 无证非学科类培训",
	          type: "rectangle",
	          color: "#168d40",
	          fillColor: "#168d40",
	          weight: 2,
	          layers: training2,
	          inactive: false
	        }, {
	          label: "\xa0\xa0 有证机构违规办学",
	          type: "rectangle",
	          color: "#2196f3",
	          fillColor: "#2196f3",
	          weight: 2,
	          layers: training3,
	          inactive: false
	          }]
	     }).addTo(mymap);
	}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.

        在上面的代码中,在设置图例的时候,legends对象数组中的每个一个layers将不同的违规培训类型进行绑定,从而实现点击图例,切换不同的违规培训数据。在本例中,请求后台的所有违规培训信息列表接口返回的数据如下:

基于Leaflet Legend的图例数据筛选实践-以某市教培时空分布为例_LeafletLegend图例_06

        单个培训单位信息内容如下:

address: "湘江新区奥克斯中央公馆9栋308房"
geom: "0101000020E6100000A2B437F8C23C5C40FB3A70CE883A3C40"
geomJson: "{\"type\":\"Point\",\"coordinates\":[112.9494,28.22865]}"
id: "1827241962588106753"
lat: "28.22865"
lon: "112.9494"
name: "唐*"
params: {}
publishDate: "2024-08-07"
remark: ""
source: "长沙晚报"
type: "隐形变异学科培训"
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

 3、成果展示

        下面将重点对图例切换的时空可视化结果进行展示。主题功能分左边和右边两块,左边展示违规培训信息列表,右边展示地图信息。左边的违规培训机构信息展示,支持按照机构名称进行模糊搜索,而右边的地图默认显示整个长沙市的违规教育培训信息。

基于Leaflet Legend的图例数据筛选实践-以某市教培时空分布为例_Leaflet 图例控制切换_07

        图例窗口默认展示在界面右下角,在地图主界面默认将所有类型的培训机构信息展示齐全。

点击图例中的隐形变异学科培训”,将隐藏所有的隐形变异学科培训培训机构。效果如下所示:

基于Leaflet Legend的图例数据筛选实践-以某市教培时空分布为例_数据_08

        同样的操作,可以一次进行剩下的“无证非学科类培训”和“有证机构违规办学”这两种培训的切换和隐藏。

基于Leaflet Legend的图例数据筛选实践-以某市教培时空分布为例_LeafletLegend图例_09

         当某一类型的违规培训机构被取消选中后,其颜色会变灰。跟Echarts的效果几乎是一模一样的。这样就满足了我们的实际需求。

三、总结

        以上就是本文的主要内容,本文以Leaflet Legend为例,结合之前采集的某市校外违规培训的时空数据,首先讲解如何进行数据的空间可视化,然后讲解Leaflet.Legend这款组件的具体应用,最后将数据和组件进行融合,讲解如何实现在图例上进行切换实现空间数据的切换与隐藏。如果您对基于图例的时空可视化渲染有兴趣,不妨来本文看看。行文仓促,定有许多不足之处,在此恳请各位专家博主和读者不吝赐教,在评论区留下宝贵的意见,不胜感激。