Arcgis for JS擴展GraphicLayer實現區域對象的聚類統計與展示

功能需求:

分省市統計並展示全國雨量站的數目與位置。

 

常規做法:

分省市雨量站的數目通過統計表的形式在頁面端展示,位置根據XY坐標信息將雨量站標繪在圖上。

優化做法:

去掉統計圖的展示方式,直接將各省市雨量站的數量信息與位置信息展示在圖上,如下圖所示:

雨量站的分省市統計與展示

 

處理思路:

首先,提取各省/市的中心點或者省會城市X與Y坐標信息,在本實例中使用的是省會城市的XY坐標信息,用來顯示各省市雨量站的分佈。

接著,分省/市統計各省市雨量站的個數,並將其根據個數分顏色、大小將其展示在圖上。

最後,點擊單個圓圈在地圖上標繪詳細的雨量站的位置信息,並將其縮放至該省/市。

 

解決問題:

統計信息的清晰展示與數據的請求速度。

 

比較:

優化做法直接將統計信息與位置信息展示在地圖上,在視覺效果上,提高瞭地圖的交互性與美觀程度,簡單明瞭;在數據請求上,優化做法隻需統計個數,不需要詳細的信息,更不需要將所有的站點在地圖上展示,每點擊一次,再去請求數據,大大提高瞭程序的效率與速度。

 

實現代碼:

1、數據

首先,在數據庫中查詢分省市雨量站的統計情況,返回JSON格式的到前臺,數據格式如下:

 

[
	{id:1,name:1,x:1,y:1,count:10},
	{id:2,name:2,x:2,y:2,count:20},
	{id:3,name:3,x:3,y:3,count:30},
	{……}
	{id:n,name:n,x:n,y:n,count:n}
]

接著,點擊每一個點的時候去請求該省/市的詳細雨量站的信息,返回的依然是JSOn格式的,格式如上。

 

2、擴展GraphicLayer

為瞭操作方便,將GraphicLayer進行瞭擴展,擴展的時候主要有以下幾個主要點:a、將統計數按照XY坐標展示在圖上;b、點擊單個點的時候標繪詳細的雨量站的位置分佈信息。

源代碼如下:

 

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
], function (
    declare, arrayUtils, Color, connect,
    SpatialReference, Point, Graphic, SimpleMarkerSymbol, TextSymbol,
    PopupTemplate, GraphicsLayer
    ) {
    return declare([GraphicsLayer], {
        constructor: function(options) {
            // 參數:
            //   data:  Object[]
            //     Array of objects. Required. Object are required to have properties named x, y and attributes. The x and y coordinates have to be numbers that represent a points coordinates.
            //   field:  string?
            //     The field of cluster.
            //   showSingles:  Boolean?
            //     Optional. Whether or graphics should be displayed when a cluster graphic is clicked. Default is true.
            //   labelColor:  String?
            //     Optional. Hex string or array of rgba values used as the color for cluster labels. Default value is #fff (white).
            //   labelOffset:  String?
            //     Optional. Number of pixels to shift a cluster label vertically. Defaults to -5 to align labels with circle symbols. Does not work in IE.
            //   singleSymbol:  MarkerSymbol?
            //     Marker Symbol (picture or simple). Optional. Symbol to use for graphics that represent single points. Default is a small gray SimpleMarkerSymbol.
            //   spatialReference:  SpatialReference?
            //     Optional. Spatial reference for all graphics in the layer. This has to match the spatial reference of the map. Default is 102100. Omit this if the map uses basemaps in web mercator.
            //   singleTemplate:  PopupTemplate?
            //     PopupTemplate. Optional. Popup template used to format attributes for graphics that represent single points. Default shows all attributes as attribute = value (not recommended).

            //聚類數據
            this._clusterData = options.data || [];
            this._clusters = [];
            //標註顏色,默認為白色
            this._clusterLabelColor = options.labelColor || #000;
            //標註偏移,默認為-5
            this._clusterLabelOffset = (options.hasOwnProperty(labelOffset)) ? options.labelOffset : -5;

            this._showSingles = options.hasOwnProperty(showSingles) ? options.showSingles : true;
            //單個對象
            this._singles = []; //點擊時出現
            // 單個的樣式
            var SMS = SimpleMarkerSymbol;
            this._singleSym = options.singleSymbol || new SMS(circle, 6, null, new Color(options.singleColor,0.6));
            //空間參考
            this._sr = options.spatialReference || new SpatialReference({ wkid: 4326 });

            this._singleTemplate = options.singleTemplate || new PopupTemplate({ title: , description: {*} });
        },
        // 重構esri/layers/GraphicsLayer方法
        _setMap: function(map, surface) {
            this._clusterGraphics();
            // GraphicsLayer will add its own listener here
            var p = this.inherited(arguments);
            return p;
        },
        _unsetMap: function() {
            this.inherited(arguments);
        },
        clearSingles: function(singles) {
            // Summary:  Remove graphics that represent inpidual data points.
            var s = singles || this._singles;
            console.log(s);
            arrayUtils.forEach(s, function(g) {
                console.log(g);
                this.remove(g);
            }, this);
            this._singles.length = 0;
        },
        onClick: function(e) {
            // stop the click from bubbling to the map
            e.stopPropagation();
            this.clearSingles(this._singles);
            var g = e.graphic;
            console.log(g);
            var sonData = city;
            for(var i= 0,  sl=sonData.length;i1){
                // show number of points in the cluster
                var font  = new esri.symbol.Font()
                    .setSize(10pt)
                    .setWeight(esri.symbol.Font.WEIGHT_BOLD);
                var label = new TextSymbol(p.pcitycount)
                    .setColor(new Color(this._clusterLabelColor))
                    .setOffset(0, this._clusterLabelOffset)
                    .setFont(font);
                this.add(
                    new Graphic(
                        pt,
                        label,
                        p
                    )
                );
            }
        }
    });
});

 

3、在程序中導入包,並引用

 

        var dojoConfig = {
            paths: {
                extras: location.pathname.replace(//[^/]+$/, ) + /extras
            }
        };

引用的方式為:

 

 

        require([
            ......,
            extras/ZonalClusterLayer,
            dojo/domReady!
        ], function(
            ......,
            ZonalClusterLayer
        ){

 

4、新建ZonalClusterLayer,分類進行渲染,並將之添加到地圖上。

 

                clusterLayer = new ZonalClusterLayer({
                    data: capital,
                    id: clusters,
                    labelColor: #fff,
                    labelOffset: -4,
                    singleColor: #0ff
                });
                var defaultSym = new SimpleMarkerSymbol().setSize(4);
                var renderer = new ClassBreaksRenderer(defaultSym, pcitycount);

                /*var picBaseUrl = images/;
                 var blue = new PictureMarkerSymbol(picBaseUrl + BluePin1LargeB.png, 32, 32).setOffset(0, 15);
                 var green = new PictureMarkerSymbol(picBaseUrl + GreenPin1LargeB.png, 64, 64).setOffset(0, 15);
                 var red = new PictureMarkerSymbol(picBaseUrl + RedPin1LargeB.png, 80, 80).setOffset(0, 15);*/
                var style1 = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 10,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                                new Color([255,200,0]), 1),
                        new Color([255,200,0,0.8]));
                var style2 = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 16,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                                new Color([255,125,3]), 1),
                        new Color([255,125,3,0.8]));
                var style3 = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 18,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                                new Color([255,23,58]), 1),
                        new Color([255,23,58,0.8]));
                var style4 = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 20,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                                new Color([204,0,184]), 1),
                        new Color([204,0,184,0.8]));
                var style5 = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 22,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                                new Color([0,0,255]), 1),
                        new Color([0,0,255,0.8]));
                renderer.addBreak(0, 2, style1);
                renderer.addBreak(2, 5, style2);
                renderer.addBreak(5, 10, style3);
                renderer.addBreak(10, 15, style4);
                renderer.addBreak(15, 20, style5);

                clusterLayer.setRenderer(renderer);
                map.addLayer(clusterLayer);

5、一些無關緊要的東西

 

在地圖上點擊,清楚詳細結果:

 

                // close the info window when the map is clicked
                map.on(click, cleanUp);
                // close the info window when esc is pressed
                map.on(key-down, function(e) {
                    if (e.keyCode === 27) {
                        cleanUp();
                    }
                });

            function cleanUp() {
                map.infoWindow.hide();
                clusterLayer.clearSingles();
            }

 

 

 

發佈留言