功能需求:
分省市统计并展示全国雨量站的数目与位置。
常规做法:
分省市雨量站的数目通过统计表的形式在页面端展示,位置根据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</a>. 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 div = this.inherited(arguments); return div; }, _unsetMap: function() { this.inherited(arguments); }, clearSingles: function(singles) { // Summary: Remove graphics that represent individual 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;i<sl;i++){ if(sonData[i].propy===g.attributes.propy){ var pt = new Point(sonData[i].x,sonData[i].y, this._sr); var sg = new Graphic(pt, this._singleSym, sonData[i], this._singleTemplate); clusterLayer.add(sg); this._singles.push(sg); } } map.infoWindow.setFeatures(this._singles); map.infoWindow.show(g.geometry); }, //添加聚类图形 _clusterGraphics: function(){ for(var i= 0, jl=this._clusterData.length;i<jl;i++){ var point = this._clusterData[i]; this._addPoint(point); } }, //添加点 _addPoint: function(p){ var pt = new Point(p.x, p.y,this._sr); this.add( new Graphic( pt, null, p ) ); if(p.pcitycount>1){ // 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(); }
源码下载