美文网首页web前端
arcgis 3x 聚类实现 点击弹出infowindow 附带

arcgis 3x 聚类实现 点击弹出infowindow 附带

作者: channel_puls | 来源:发表于2019-12-11 17:47 被阅读0次
    • 首先官方也给出了例子 但是这不能满足我们的需求 image.png

      改造后 当然设置了他的 renderer 达到效果


      ss.png
    define([
        "dojo/_base/declare",
        "dojo/_base/array",
        "esri/Color",
        "dojo/_base/connect",
        "esri/SpatialReference",
        "esri/geometry/Point",
        "esri/graphic",
        "esri/symbols/SimpleMarkerSymbol",
        "esri/symbols/TextSymbol",
        "esri/dijit/PopupTemplate",
        "esri/layers/GraphicsLayer",
        "esri/InfoTemplate",
        "esri/geometry/Extent",
        "dojo/dom-construct",
        "esri/symbols/PictureMarkerSymbol",
        "esri/dijit/InfoWindow"
    ], function(
        declare, arrayUtils, Color, connect,
        SpatialReference, Point, Graphic, SimpleMarkerSymbol, TextSymbol,
        PopupTemplate, GraphicsLayer,
        InfoTemplate,
        Extent,
        domConstruct,PictureMarkerSymbol,
        InfoWindow
    ) {
        return declare([GraphicsLayer], {
            constructor: function(options) {
                this._clusterTolerance = options.distance || 50;
                // 页面初始数据
                this._clusterData = options.data || [];
                // 
                this._clusters = [];
                this._clusterLabelColor = options.labelColor || "#000";
                // 标签偏移可以是零,所以处理方式不同
                this._clusterLabelOffset = (options.hasOwnProperty("labelOffset")) ? options.labelOffset : -5;
                this._singles = []; // 在单击图形时填充
                this._showSingles = options.hasOwnProperty("showSingles") ? options.showSingles : true;
                // 表示单个点的图形
                var SMS = SimpleMarkerSymbol;
                this._singleSym = options.singleSymbol || new SMS("circle", 3, null, new Color("#097"));
                this._singleTemplate = options.singleTemplate || new InfoTemplate("Attributes", "{*}");
                this._maxSingles = options.maxSingles || 1000;
                this._webmap = options.hasOwnProperty("webmap") ? options.webmap : false;
                this._sr = options.spatialReference || new SpatialReference({
                    "wkid": 4326
                });
                this._zoomEnd = null;
                this._mapclick = null;
            },
    
            // override esri/layers/GraphicsLayer methods 
            _setMap: function(map, surface) {
                // 计算并设置初始分辨率
                this._clusterResolution = map.extent.getWidth() / map.width; // probably a bad default...
                if(this._zoomEnd==null){this._clusterGraphics();}
                //       连接到onZoomEnd,以便在缩放级别更改时重新聚集数据
                this._zoomEnd = connect.connect(map, "onZoomEnd", this, function() {
                    // 更新分辨率
                    this._clusterResolution = this._map.extent.getWidth() / this._map.width;
                    this.clear();
                    this._clusterGraphics();
                });
                // GraphicsLayer将在这里添加自己的侦听器
                var div = this.inherited(arguments);
                return div;
            },
    
            _unsetMap: function() {
                this.inherited(arguments);
                connect.disconnect(this._zoomEnd);
            },
            // 公共ClusterLayer方法
            add: function(p) {
                //参数是要添加到现有集群中的数据点。如果数据点落在现有集群内,
                // 则将其添加到该集群,并更新集群的标签。如果新点不在现有集群中,则创建一个新集群
                // 如果传递了一个图形,使用GraphicsLayer的add方法
                if (p.declaredClass) {
                    this.inherited(arguments);
                    return;
                }
                // 将新数据添加到_clusterData中,以便将其包含在集群中
    
                this._clusterData.push(p);
    
                var clustered = false;
                //  当地图级别改变时
                // 在现有集群中查找新点
                for (var i = 0; i < this._clusters.length; i++) {
                    var c = this._clusters[i];
                    // 将该点添加到现有集群
                    this._clusterAddPoint(p, c);
                    // 更新集群的几何形状
                    this._updateClusterGeometry(c);
                    // 更新标签
                    this._updateLabel(c);
                    clustered = true;
                }
    
                if (!clustered) {
                    p.attributes.clusterCount = 1;
                    this._clusterCreate(p);
                    this._showCluster(p);
                }
            },
            showSingles: function() {
                var singles = [];
                for (var i = 0, il = this._clusterData.length; i < il; i++) {
                    singles.push(this._clusterData[i]);
                }
                this._addSingles(singles);
            },
            clear: function() {
                // 摘要:删除所有集群和数据点
                this.inherited(arguments);
                this._clusters.length = 0;
            },
            clearSingles: function(singles) {
                // 摘要:删除表示单个数据点的图形。
                var s = singles || this._singles;
                arrayUtils.forEach(s, function(g) {
                    this.remove(g);
                }, this);
                this._singles.length = 0;
            },
    
            onClick: function(e) {
                // 删除任何以前显示的单一功能
                this._map.infoWindow.resize(440, 350)
                this.clearSingles(this._singles);
                // 查找组成被单击的集群的单个图形
                // would be nice to use filter but performance tanks with large arrays in IE
                var singles = [];
                for (var i = 0, il = this._clusterData.length; i < il; i++) {
                    if (e.graphic.attributes.clusterId == this._clusterData[i].attributes.clusterId) {
                        singles.push(this._clusterData[i]);
                    }
                }
                if (singles.length > this._maxSingles) {
                    alert("Sorry, that cluster contains more than " + this._maxSingles + " points. Zoom in for more detail.");
                    return;
                } else {
                    e.stopPropagation();
                    // 停止从弹出到地图的单击
                    if (singles.length == 1) {
                        // 单一的时候
                        // this._map.infoWindow.show(e.graphic.geometry);
                        // this._graphicOnClick(e.graphic.attributes);
                        this._graphicOnClick(e);
                    } else if(this._map.getMaxZoom()-this._map.getZoom()>2 && singles.length > 1){
    //点击singles时得到符号的extent 然后设置为当前可见范围 放大地图 达到放大地图等级 触发重新渲染点 从而分开点
                        var xmax, ymax, xmin, ymin;
                        xmax = this._find(singles, "x", "max");
                        ymax = this._find(singles, "y", "max");
                        xmin = this._find(singles, "x", "min");
                        ymin = this._find(singles, "y", "min");
                        var extent = new Extent(xmin, ymin, xmax, ymax, this._sr)
                        this._map.setExtent(extent);
                        this._clusterResolution = this._map.extent.getWidth() / this._map.width;
                        this.clear();
                        this._clusterGraphics();
                        this._addSingles(singles);
                    }
                }
            },
    //如果点前是一个点 则触发此事件
            _graphicOnClick: function(e) {
                var _this = this;
                var id;
                if (e.graphic.attributes.id.id) {
                    id = e.graphic.attributes.id.id;
                } else {
                    id = e.graphic.attributes.id;
                }
                this.addInfo(id, function(res) {
                    // var node = domConstruct.create("div", {
                    //  innerHTML: "<div class='content_doms'>" +
                    //      "<div class='content_doms_header'>" +
                    //      "<table class='table table-bordered table-condensed'><thead><tr class='info'><th>户主姓名</th><th>所在自然村</th><th>本户人数</th><th>联系电话</th></tr></thead>" +
                    //      "<tbody><tr><td>" + res.nhFarmerInfo.name + "</td><td>" + res.nhFarmerInfo.naturalvillagename +
                    //      "</td><td>" + res.nhFarmerInfo.peoples + "</td><td>" + res.nhFarmerInfo.telephone +
                    //      "</td></tr></tbody></table>" +
                    //      "</div>" +
                    //      "<div class='content_doms_footer'>" + _this.createList(res.nhOutletList) + "<div>" +
                    //      "</div>"
                    // });
                    // 表格生成代码
                    var node = domConstruct.create("div", {
                        innerHTML: "<div class='content_doms'>" +
                            "<div class='content_doms_header'>" +
                            // <table class='table table-bordered table-condensed'>" + createTableList(res.nhFarmerInfo) +"</table>
                            generateTable(res.nhFarmerInfo,2)+
                            "</div>" +
                            "<div class='content_doms_footer'>" +createList(res.nhOutletList) + "<div>" +
                            "</div>"
                    });
                    // var infoTemplate = new InfoTemplate("农户信息", node);
                    // 排口信息
                    res.id = id;
                    // e.graphic.setAttributes(res);
                    // e.graphic.setInfoTemplate(infoTemplate);
                    _this._map.infoWindow.setTitle("农户信息");
                    _this._map.infoWindow.setContent(node);
                    _this._map.infoWindow.show(e.graphic.geometry);
                });
            },
            // 查找数组中最大值 或者 最小值 
            _find: function(arr, pro, single) {
                return Math[single].apply(Math, arr.map(function(o) {
                    return o[pro]
                }))
            },
            addInfo: function(id, cb) {
                var url ='/hbnhcj/farmer/nhFarmerInfo/getFarmerWithOutlet';
                $ajax(url,"GET",{id:id},function(data){
                    cb(data.result)
                });
            },
            // 内部方法 ***************************起点*********************************
            _clusterGraphics: function() {
                // ,遍历这些点
                for (var j = 0, jl = this._clusterData.length; j < jl; j++) {
                    // 查看当前特性是否应该添加到集群中
                    var point = this._clusterData[j];
                    var clustered = false;
                    var numClusters = this._clusters.length;
                    for (var i = 0; i < this._clusters.length; i++) {
    
                        // 当前集群
                        var c = this._clusters[i];
                        // 查看是否满足距离公式
                        if (this._clusterTest(point, c)) {
                            // 如果满足 就将当前点添加到
                            this._clusterAddPoint(point, c);
                            clustered = true;
                            break;
                        }
                    }
    
                    if (!clustered) {
                        this._clusterCreate(point);
                    }
                }
                this._showAllClusters();
            },
    
            _clusterTest: function(p, cluster) {
                var distance = (
                    Math.sqrt(
                        Math.pow((cluster.x - p.x), 2) + Math.pow((cluster.y - p.y), 2)
                    ) / this._clusterResolution
                );
                return (distance <= this._clusterTolerance);
            },
    
            // 应该包括传递给clusterAddPoint的点
            //在现有集群中
            //还为该点提供一个名为clusterId的属性
            //这与它的星系团相对应
            _clusterAddPoint: function(p, cluster) {
                //平均在新的点集群几何
                var count, x, y;
                count = cluster.attributes.clusterCount;
                x = (p.x + (cluster.x * count)) / (count + 1);
                y = (p.y + (cluster.y * count)) / (count + 1);
                cluster.x = x;
                cluster.y = y;
    
                //构建一个包括集群中所有点的范围
                //扩展只用于调试/测试…该层不使用
                if (p.x < cluster.attributes.extent[0]) {
                    cluster.attributes.extent[0] = p.x;
                } else if (p.x > cluster.attributes.extent[2]) {
                    cluster.attributes.extent[2] = p.x;
                }
                if (p.y < cluster.attributes.extent[1]) {
                    cluster.attributes.extent[1] = p.y;
                } else if (p.y > cluster.attributes.extent[3]) {
                    cluster.attributes.extent[3] = p.y;
                }
    
                // 增加数
                cluster.attributes.clusterCount++;
                // 属性可能不存在
                if (!p.hasOwnProperty("attributes")) {
                    p.attributes = {};
                }
                // 给图形一个集群id
                p.attributes.clusterId = cluster.attributes.clusterId;
            },
    
            //传递给clusterCreate的点不在
            //为层指定的聚类距离
            //为它创建一个新的集群
            _clusterCreate: function(p) {
                var clusterId = this._clusters.length + 1;
                // console.log("cluster create, id is: ", clusterId);
                // p.attributes might be undefined
                //控制台。日志(“集群创建,id是:”,clusterId);
                // p。属性可能未定义
                if (!p.attributes) {
                    p.attributes = {};
                }
                p.attributes.clusterId = clusterId;
                // 创建集群
                var cluster = {
                    "x": p.x,
                    "y": p.y,
                    "attributes": {
                        "clusterCount": 1,
                        "clusterId": clusterId,
                        "id": p.attributes,
                        "extent": [p.x, p.y, p.x, p.y]
                    }
                };
                this._clusters.push(cluster);
            },
            // 展示所有聚类
            _showAllClusters: function() {
                for (var i = 0, il = this._clusters.length; i < il; i++) {
                    var c = this._clusters[i];
                    this._showCluster(c);
                }
            },
            // 展示单一聚类
            _showCluster: function(c) {
                // 单一集群  
                console.log(c);
    
                var point = new Point(c.x, c.y, this._sr);
                this.add(
                    new Graphic(
                        point,
                        null,
                        c.attributes
                    )
                );
                // 下面的代码用于不使用单点标记集群
                if (c.attributes.clusterCount == 1) {
                    return;
                }
    
                // show number of points in the cluster
                // 显示集群中的点的数量
                var label = new TextSymbol(c.attributes.clusterCount.toString())
                    .setColor(new Color(this._clusterLabelColor))
                    .setOffset(0, this._clusterLabelOffset);
                this.add(
                    new Graphic(
                        point,
                        label,
                        c.attributes
                    )
                );
            },
    
            _addSingles: function(singles) {
                // 向地图添加单个图形
                arrayUtils.forEach(singles, function(p) {
                    var g = new Graphic(
                        new Point(p.x, p.y, this._sr),
                        new PictureMarkerSymbol("https://static.arcgis.com/images/Symbols/Shapes/BluePin1LargeB.png", 32, 32)
                            .setOffset(0, 15),
                        p.attributes,
                        this._singleTemplate
                    );
                    this._singles.push(g);
                    if (this._showSingles) {
                        this.add(g);
                    }
                }, this);
                // this._map.infoWindow.show
                // this._map.infoWindow.setFeatures(this._singles);
            },
    
            _updateClusterGeometry: function(c) {
                // 查找集群图
                var cg = arrayUtils.filter(this.graphics, function(g) {
                    return !g.symbol &&
                        g.attributes.clusterId == c.attributes.clusterId;
                });
                if (cg.length == 1) {
                    cg[0].geometry.update(c.x, c.y);
                } else {
                    console.log("didn't find exactly one cluster geometry to update: ", cg);
                }
            },
    
            _updateLabel: function(c) {
                // 查找现有的标签
                var label = arrayUtils.filter(this.graphics, function(g) {
                    return g.symbol &&
                        g.symbol.declaredClass == "esri.symbol.TextSymbol" &&
                        g.attributes.clusterId == c.attributes.clusterId;
                });
                if (label.length == 1) {
                    // console.log("update label...found: ", label);
                    this.remove(label[0]);
                    var newLabel = new TextSymbol(c.attributes.clusterCount)
                        .setColor(new Color(this._clusterLabelColor))
                        .setOffset(0, this._clusterLabelOffset);
                    this.add(
                        new Graphic(
                            new Point(c.x, c.y, this._sr),
                            newLabel,
                            c.attributes
                        )
                    );
                    // console.log("updated the label");
                } else {
                    console.log("didn't find exactly one label: ", label);
                }
            },
    
            // debug only...never called by the layer 调试只有……从未被层调用
            _clusterMeta: function() {
                // 打印总功能数
                console.log("Total:  ", this._clusterData.length);
    
                // 加起来并打印出来
                var count = 0;
                arrayUtils.forEach(this._clusters, function(c) {
                    count += c.attributes.clusterCount;
                });
                console.log("In clusters:  ", count);
            }
    
        });
    });
    
    
    • 外部使用
                loadClusterLayer: function(data,map) {
                    var photoInfo = {},
                        clusterLayer;
                    var wgs = new SpatialReference({
                        "wkid": 4326
                    });
                    photoInfo.data = array.map(data, function(p) {
                        var latlng = new Point(parseFloat(p.lon), parseFloat(p.lat), wgs);
                        // 转成webMercator坐标系
                        // var webMercator = webMercatorUtils.geographicToWebMercator(latlng);
                        var attributes = {
                            "id": p.id
                        };
                        return {
                            "x": latlng.x,
                            "y": latlng.y,
                            "attributes": attributes
                        };
                    });
                    var one = new PictureMarkerSymbol("https://static.arcgis.com/images/Symbols/Shapes/BluePin1LargeB.png", 32, 32)
                        .setOffset(0, 15);
                    // cluster layer that uses OpenLayers style clustering
                    clusterLayer = new ClusterLayer({
                        "data": photoInfo.data,
                        "distance": 1,
                        "id": "clusters",
                        "labelColor": "#000",
                        "labelOffset": -5,
                        "resolution":  map.extent.getWidth() / map.width,
                        "singleColor": "#888",
                        "singleTemplate": '',
                        "spatialReference": wgs,
                    });
                    var defaultSym = new SimpleMarkerSymbol().setSize(4);
                    var renderer = new ClassBreaksRenderer(defaultSym, "clusterCount");
                    var first = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 50,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([255, 125, 3, 0.2]), 10),
                        new Color([241, 128, 23, 0.9]));
    
                    var second = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 35,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([241, 211, 87, 0.6]), 10),
                        new Color([240, 194, 13, 0.9]));
    
                    var third = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 25,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([181, 226, 140, 0.6]), 10),
                        new Color([110, 204, 57, 0.9]));
                    //渲染等级
                    renderer.addBreak(0, 1, one);
                    renderer.addBreak(2, 3, third);
                    renderer.addBreak(4, 20, second);
                    renderer.addBreak(21, 100, first);
                    clusterLayer.setRenderer(renderer);
                    return clusterLayer
                }
    

    添加到地图

    //调取api 获取要渲染的点
        this._loadData("460000", 1, 100000, function(data) {
                // 采集信息
                layer = this.loadClusterLayer(data,map);
                layer.setVisibility(layerConfig.visible);
                map.addLayer(layer);
        })
    
    • 要点
      通过设置distance大小改变两个点的聚合和距离
      在引入这个写好的图层类的时候将其放入与根目录同级 代码引入
    "extras/ClusterLayer",
    

    若你是gis 完整的项目 需要在init.js 设置dojoConfig

       dojoConfig = {
                parseOnLoad: false,
                async: true,
                tlmSiblingOfDojo: false,
                has: {
                    'extend-esri': 1
                },
                paths: {
                //我放到了我的项目的根目录下了 若放在服务器根目录下就改为/extras
                  extras:"../extras"
                }
            };
    
    sss (2).png

    相关文章

      网友评论

        本文标题:arcgis 3x 聚类实现 点击弹出infowindow 附带

        本文链接:https://www.haomeiwen.com/subject/fghagctx.html