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

You may also like...