leaflet地图制作尾篇— — 图标聚合,测距测面,标绘功能使用
1.利用L.markerClusterGroup插件实现数据点聚合
作用:在不同地图缩放层级下,是一定范围内的marker点实现聚合或展示,达到地图页面不会因数据点过多造成视觉杂乱问题。
官方插件地址:https://github.com/Leaflet/Leaflet.markercluster
实现效果图:
官方使用示例:
var markers = L.markerClusterGroup();
markers.addLayer(L.marker(getRandomLatLng(map)));
... Add more layers ...
map.addLayer(markers);
要注意的是,官方示例中,聚合默认的样式是已范围内聚合数据点个数的不同,改变聚合之后marker的背景颜色,来达到区分作用,但是在实际项目中,我们需要再地图上加载多个类型的数据,例如景点,公园,学校,然后聚合需要不同的icon来表示,这时候就需要对源码进行适当的修改,来实现分类聚合效果,具体效果图如下:人代表公园,文代表景点
使用方法:
首先我们先引入必要的css与js文件
<link href="leaflet/leaflet.markercluster/MarkerCluster.Default.css" rel="stylesheet" />
<script src="leaflet/leaflet.markercluster/MarkerCluster.js"></script>
<script src="leaflet/leaflet.markercluster/MarkerCluster.QuickHull.js"></script>
<script src="leaflet/leaflet.markercluster/DistanceGrid.js"></script>
<script src="leaflet/leaflet.markercluster/leaflet.markercluster-src.js"></script>
然后创建图层并添加数据
//虚拟数据demo.json
{
"total":6,
"rows":[
{"name":"人民大会堂","lat":"39.903244","lng":"116.387400","type":"viewSpot"},
{"name":"天安门","lat":"39.907064","lng":"116.391305","type":"viewSpot"},
{"name":"故宫","lat":"39.916462","lng":"116.390790","type":"viewSpot"},
{"name":"国家博物馆","lat":"39.903717","lng":"116.395339","type":"viewSpot"},
{"name":"北海公园","lat":"39.923973","lng":"116.383323","type":"park"},
{"name":"景山公园","lat":"39.924144","lng":"116.390533","type":"park"}
]
}
//创建图层并加载
var _viewSpotLayer=L.markerClusterGroup();
_map.addLayer(_viewSpotLayer);
$.ajax({
url:"js/demo.json",
type:"POST",
success:function(data){
for(var i=0;i<data.rows.length;i++){
(function (index){
var row=data.rows[index];
var pointFeature = new L.marker([row.lat,row.lng],{ icon:
viewIcon,title:row.name}).bindLabel(row.name,{noHide:true});
pointFeature.options.sm_sid = row.type;
pointFeature.on("click",function(){
alert(row.name)
});
pointFeature.addTo(_viewSpotLayer)
})(i)
}
}
})
注意 pointFeature.options.sm_sid = row.type 这句话。这句代码给不同的marker数据点绑定了
一个属性sm_sid用来区分该marker的数据类型。然后在 leaflet.markercluster-src.js 添加修改部
分js代码,即可实现根据类别聚合数据,具体操作如下
在该js开头出设置一个新变量 var markerSid;然后再84行处,找到addLayer方法
addLayer: function (layer) {
if (layer instanceof L.LayerGroup) {
return this.addLayers([layer]);
}
......
return this;
}
修改为:
addLayer: function (layer) {
markerSid=layer.options.sm_sid;
if (layer instanceof L.LayerGroup) {
return this.addLayers([layer]);
}
......
return this;
}
然后在820行处,找到_defaultIconCreateFunction 方法
_defaultIconCreateFunction: function (cluster) {
var childCount = cluster.getChildCount();
var c = ' marker-cluster-';
......
}
修改为:
_defaultIconCreateFunction: function (cluster) {
var x=" sclass-"+markerSid;
return new L.DivIcon({ html: '<div><span>' + childCount + '</span></div>', className:
'marker-cluster'+ x, iconSize: new L.Point(40, 52) });
}
注意 new L.Point(40, 52) 请根据你自己的聚合图标大小修改该宽高;
然后打开 MarkerCluster.Default.css 在css文件中添加class样式表
例如 :
.sclass-viewSpot{
background:url(jh-bxxx.png) no-repeat center;
}
经过以上代码修改,即可实现不同类型数据的分类聚合效果
完成上述操作后还有一个问题,就是地图缩放时,聚合图标会错乱变化,如下图
经过缩放后,不同类型的合并成一个点,并使用了公园类型的聚合图标,这不是我们想要的效果,此时我们需要创建两个图层,并根据数据类型添加到不同的图层中
var _viewSpotLayer=L.markerClusterGroup();
_map.addLayer(_viewSpotLayer);
var _parkLayer=L.markerClusterGroup();
_map.addLayer(_parkLayer);
$.ajax({
url:"js/demo.json",
type:"POST",
success:function(data){
for(var i=0;i<data.rows.length;i++){
(function (index){
......
if(row.type=="park"){
pointFeature.addTo(_parkLayer)
}else{
pointFeature.addTo(_viewSpotLayer)
}
})(i)
}
}
})
经过上面的修改后,就完成了不同类型数据分层展示的效果,但是缩放后还是会出现如下图的问题
大家可以看到,缩放后,原先代表景点的聚合图标变为了公园的图标,解决这个问题的方法很简单,就是在地图缩放时重新进行数据加载
加载map时,给map绑定缩放事件,刷新数据
_map.on("zoomend", function () {
_parkLayer.clearLayers();
_viewSpotLayer.clearLayers();
loadPointData()
});
ps:注意每次加载数据时清空图层上的数据点,否则会造成地图上有多个重复数据点的情况发生,另外情况图层操作一般放在ajax加载数据成功内执行,我放在此处是为了省事。
经过上面所有的操作,就完成了L.markerClusterGroup插件的使用。
2.测距,测面功能实现
在地图上点击标点进行距离与面积的测量,效果图如下
首先引入必要的文件
<link href="css/leaflet.draw.css" rel="stylesheet" />
<script src="leaflet/L.Control.MousePosition.js"></script>
<script src="leaflet/leaflet.polylineDecorator.js"></script>
<script src="leaflet/leaflet.draw.js"></script>
<script src="leaflet/measure.js"></script>
<div class="meauser">
<span onclick="measure()">测距</span>
<span onclick="measureArea()">测面</span>
<span onclick="clearMap()">清除</span>
</div>
然后再添加相应的变量并创建地图即可
var DRAWING = false; //是否正在绘制
var DRAWLAYERS = [];
var BarDRAWLAYERS = [];
var ISMEASURE = false; //是否是量距
var MEASURETOOLTIP; //量距提示
var MEASUREAREATOOLTIP; //量面提示
var MEASURERESULT = 0;
var DRAWPOLYLINE; //绘制的折线
var DRAWMOVEPOLYLINE; //绘制过程中的折线
var DRAWPOLYLINEPOINTS = []; //绘制的折线的节点集
var DRAWPOLYGON; //绘制的面
var DRAWMOVEPOLYGON; //绘制过程中的面
var DRAWPOLYGONPOINTS = []; //绘制的面的节点集
ps:因为插件中,结束绘制时调用的是双击事件,而L.map默认地图双击放大,所以需要再地图加载完成后取消地图的默认点击事件,如下:
_map.doubleClickZoom.disable();
所有步骤完成后,点击按钮即可执行相应测距测面方法,无需多余操作。
3.标绘功能
此功能就不详细讲解了,因为测距测面功能双击地图后会在地图展示数据,所以只需要在 measure.js 内找到相应的双击事件,然后再双击后,拿到此条线段/面的坐标点数据加以保存就好,如果还需要额外的命名,备注,修改颜色,宽度,透明度等功能,大家可以再 measure.js 内尝试自行添加,在此就不给大家添加此功能了。
到此为止 lealfet 在项目中的基本应用差不多已经全部完成,所有demo我会打包上传,如果大家有需要可自行下载,如果需要别的功能,请大家去lefleft官网自行查找学习。
转载自:https://blog.csdn.net/lonly_maple/article/details/83658608