原文:Arcgis for JS之Cluster聚类分析的实现(基于区域范围的)咱们书接上文,在上文,实现了基于距离的空间聚类的算法实现,在本文,将继续介绍空间聚类之基于区域范围的实现方式,好了,闲言少叙,先看看具体的效果:

聚类效果

点击显示信息

显示单个聚类点
下面说说具体的实现思路。
1、数据组织
在进行数据组织的时候,因为是要按照区域范围的,所以必须得包含区域范围的信息,在本示例中,我用的数据依然是全国2000多个区县点的数据,并添加了省市代码,数据如下:

2、聚类思路
根据数据中“procode”去判断类别,是同一类别就将该类别添加到该类别的数据中,并将计数增加1,思路很简单,对graphiclayer进行了扩展,源代码如下:
- 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) {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- this._clusterField = options.field || "";
-
- this._clusterData = options.data || [];
- this._clusters = [];
-
- this._clusterLabelColor = options.labelColor || "#000";
-
- 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": 102100 });
-
- this._zoomEnd = null;
-
- this._singleTemplate = options.singleTemplate || new PopupTemplate({ "title": "", "description": "{*}" });
- },
-
-
- _setMap: function(map, surface) {
- this._clusterGraphics();
-
-
-
-
- var div = this.inherited(arguments);
- return div;
- },
-
- _unsetMap: function() {
- this.inherited(arguments);
- connect.disconnect(this._zoomEnd);
- },
-
-
- add: function(p) {
-
-
-
- if ( p.declaredClass ) {
- this.inherited(arguments);
- return;
- }
-
-
-
- this._clusterData.push(this._clusters);
- var clustered = false;
-
- for ( var i = 0; i < this._clusters.length; i++ ) {
- var c = this._clusters[i];
- if ( this._clusterTest(p, c) ) {
-
- this._clusterAddPoint(p, c);
-
- this._updateClusterGeometry(c);
-
- this._updateLabel(c);
- clustered = true;
- break;
- }
- }
-
- if ( ! clustered ) {
- this._clusterCreate(p);
- p.attributes.clusterCount = 1;
- this._showCluster(p);
- }
- },
-
- 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;
- map.graphics.clear();
- },
-
- onClick: function(e) {
-
- this.clearSingles(this._singles);
-
-
-
- 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();
- this._map.infoWindow.show(e.graphic.geometry);
- this._addSingles(singles);
- }
- },
-
-
- _clusterGraphics: function() {
-
- for ( var j = 0, jl = this._clusterData.length; j < jl; j++ ) {
-
- var point = this._clusterData[j];
-
- var clustered = false;
- for ( var i = 0, numClusters = this._clusters.length; i < numClusters; i++ ) {
- var c = this._clusters[i];
- if ( this._clusterTest(point, c) ) {
- var pt = new esri.geometry.Point(point.x,point.y);
- this._clusterAddPoint(point, c);
- clustered = true;
- break;
- }
- }
- if ( ! clustered ) {
- this._clusterCreate(point);
- }
- }
- this._showAllClusters();
- },
-
- _clusterTest: function(p, cluster) {
- if(p.attributes.proCode === cluster.field){
- return true;
- }
- else{
- return false;
- }
- },
-
-
-
-
-
- _clusterAddPoint: function(p, cluster) {
-
- var count, field;
- count = cluster.attributes.clusterCount;
- field = p.attributes.proCode;
- cluster.field = field;
-
- cluster.attributes.clusterCount++;
-
- if ( ! p.hasOwnProperty("attributes") ) {
- p.attributes = {};
- }
-
- p.attributes.clusterId = cluster.attributes.clusterId;
- },
-
-
-
-
- _clusterCreate: function(p) {
- var clusterId = this._clusters.length + 1;
-
-
- if ( ! p.attributes ) {
- p.attributes = {};
- }
- p.attributes.clusterId = clusterId;
-
- var cluster = {
- "x": p.x,
- "y": p.y,
- "field": p.attributes.proCode,
- "attributes" : {
- "clusterCount": 1,
- "clusterId": clusterId
- }
- };
- 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) {
- var point = new Point(c.x, c.y, this._sr);
- this.add(
- new Graphic(
- point,
- null,
- c.attributes
- )
- );
-
- if ( c.attributes.clusterCount == 1 ) {
- return;
- }
-
-
- var font = new esri.symbol.Font()
- .setSize("10pt")
- .setWeight(esri.symbol.Font.WEIGHT_BOLD);
- var label = new TextSymbol(c.attributes.clusterCount)
- .setColor(new Color(this._clusterLabelColor))
- .setOffset(0, this._clusterLabelOffset)
- .setFont(font);
- this.add(
- new Graphic(
- point,
- label,
- c.attributes
- )
- );
- },
-
- _addSingles: function(singles) {
- var mlPoint = new esri.geometry.Multipoint(this._sr);
-
- arrayUtils.forEach(singles, function(p) {
- var pt = new Point(p.x, p.y, this._sr);
- mlPoint.addPoint(pt);
- var g = new Graphic(
- pt,
- this._singleSym,
- p.attributes,
- this._singleTemplate
- );
- this._singles.push(g);
- if ( this._showSingles ) {
- this.add(g);
- }
- }, this);
- map.setExtent(mlPoint.getExtent().expand(2.5));
- var singleCenter = mlPoint.getExtent().getCenter();
- var font = new esri.symbol.Font();
- font.setSize("15pt");
- font.setFamily("微软雅黑");
- font.setWeight("bold");
- var text = new esri.symbol.TextSymbol(singles[0].attributes.proName);
- text.setFont(font);
- text.setColor(new Color([0,0,0]));
- var labelGraphic = new esri.Graphic(singleCenter,text);
- map.graphics.add(labelGraphic);
- 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 ) {
-
- 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
- )
- );
-
- } else {
- console.log("didn‘t find exactly one label: ", label);
- }
- },
-
-
- _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);
- }
- });
- });
接着将之导入,并调用:
- var dojoConfig = {
- paths: {
- extras: location.pathname.replace(/\/[^/]+$/, "") + "/extras"
- }
- };
- require([......
- "extras/ZoneClusterLayer",
- "dojo/domReady!"
- ], function(
- ......,
- ZoneClusterLayer
- ){
新建clusterlayer对象,并将之添加到map:
- function addClusters(items) {
- var countyInfo = {};
- countyInfo.data = arrayUtils.map(items, function(item) {
- var latlng = new Point(parseFloat(item.x), parseFloat(item.y), map.spatialReference);
- var webMercator = webMercatorUtils.geographicToWebMercator(latlng);
- var attributes = {
- "proName": item.attributes.proname,
- "proCode":item.procode,
- "countyName": item.attributes.countyname,
- "lng": item.x,
- "lat": item.y
- };
- return {
- "x": webMercator.x,
- "y": webMercator.y,
- "attributes": attributes
- };
- });
- clusterLayer = new ZoneClusterLayer({
- "data": countyInfo.data,
- "id": "clusters",
- "labelColor": "#fff",
- "labelOffset": -4,
- "singleColor": "#0ff",
- "field":"proCode"
- });
- var defaultSym = new SimpleMarkerSymbol().setSize(4);
- var renderer = new ClassBreaksRenderer(defaultSym, "clusterCount");
-
-
- 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, 20,
- 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, 23,
- 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, 28,
- 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, 33,
- new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
- new Color([0,0,255]), 1),
- new Color([0,0,255,0.8]));
- renderer.addBreak(1, 10, style1);
- renderer.addBreak(10, 50, style2);
- renderer.addBreak(50, 100, style3);
- renderer.addBreak(100, 150, style4);
- renderer.addBreak(150, 200, style5);
-
- clusterLayer.setRenderer(renderer);
- map.addLayer(clusterLayer);
-
- map.on("click", cleanUp);
-
- map.on("key-down", function(e) {
- if (e.keyCode === 27) {
- cleanUp();
- }
- });
- }
- function cleanUp() {
- map.infoWindow.hide();
- clusterLayer.clearSingles();
- }
调用的html的全代码如下:
- <!doctype html>
- <html>
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
- <title>Zone Cluster</title>
- <link rel="stylesheet" href="http://localhost/arcgis_js_api/library/3.9/3.9/js/dojo/dijit/themes/tundra/tundra.css">
- <link rel="stylesheet" href="http://localhost/arcgis_js_api/library/3.9/3.9/js/esri/css/esri.css">
- <style>
- html, body, #map{ height: 100%; width: 100%; margin: 0; padding: 0; }
- #map{ margin: 0; padding: 0; }
- </style>
-
- <script>
- // helpful for understanding dojoConfig.packages vs. dojoConfig.paths:
- // http://www.sitepen.com/blog/2013/06/20/dojo-faq-what-is-the-difference-packages-vs-paths-vs-aliases/
- var dojoConfig = {
- paths: {
- extras: location.pathname.replace(/\/[^/]+$/, "") + "/extras"
- }
- };
- </script>
- <script src="http://localhost/arcgis_js_api/library/3.9/3.9/init.js"></script>
- <script src="data/county.js"></script>
- <script>
- var map;
- var clusterLayer;
- require([
- "dojo/parser",
- "dojo/_base/array",
- "esri/map",
- "esri/layers/ArcGISTiledMapServiceLayer",
- "esri/layers/FeatureLayer",
- "esri/graphic",
- "esri/Color",
- "esri/symbols/SimpleMarkerSymbol",
- "esri/symbols/SimpleLineSymbol",
- "esri/symbols/SimpleFillSymbol",
- "esri/renderers/SimpleRenderer",
- "esri/renderers/ClassBreaksRenderer",
- "esri/SpatialReference",
- "esri/geometry/Point",
- "esri/geometry/webMercatorUtils",
- "extras/ZoneClusterLayer",
- "dojo/domReady!"
- ], function(
- parser,
- arrayUtils,
- Map,
- Tiled,
- FeatureLayer,
- Graphic,
- Color,
- SimpleMarkerSymbol,
- SimpleLineSymbol,
- SimpleFillSymbol,
- SimpleRenderer,
- ClassBreaksRenderer,
- SpatialReference,
- Point,
- webMercatorUtils,
- ZoneClusterLayer
- ){
- map = new Map("map", {logo:false,slider: true});
- var tiled = new Tiled("http://localhost:6080/arcgis/rest/services/image/MapServer");
- map.addLayer(tiled);
- tiled.hide();
- var fch = new FeatureLayer("http://localhost:6080/arcgis/rest/services/china/MapServer/0");
- var symbol = new SimpleFillSymbol(
- SimpleFillSymbol.STYLE_SOLID,
- new SimpleLineSymbol(
- SimpleLineSymbol.STYLE_SOLID,
- new esri.Color([180,180,180,1]), //设置RGB色,0.75设置透明度
- 2
- ),
- new esri.Color([150,150,150,0.2])
- );
- //简单渲染
- var simpleRender=new SimpleRenderer(symbol);
- fch.setRenderer(simpleRender);
- map.addLayer(fch);
- map.centerAndZoom(new Point(103.847, 36.0473, map.spatialReference),4);
-
- map.on("load", function() {
- addClusters(county.items);
- });
-
- function addClusters(items) {
- var countyInfo = {};
- countyInfo.data = arrayUtils.map(items, function(item) {
- var latlng = new Point(parseFloat(item.x), parseFloat(item.y), map.spatialReference);
- var webMercator = webMercatorUtils.geographicToWebMercator(latlng);
- var attributes = {
- "proName": item.attributes.proname,
- "proCode":item.procode,
- "countyName": item.attributes.countyname,
- "lng": item.x,
- "lat": item.y
- };
- return {
- "x": webMercator.x,
- "y": webMercator.y,
- "attributes": attributes
- };
- });
- clusterLayer = new ZoneClusterLayer({
- "data": countyInfo.data,
- "id": "clusters",
- "labelColor": "#fff",
- "labelOffset": -4,
- "singleColor": "#0ff",
- "field":"proCode"
- });
- var defaultSym = new SimpleMarkerSymbol().setSize(4);
- var renderer = new ClassBreaksRenderer(defaultSym, "clusterCount");
-
- /*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, 20,
- 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, 23,
- 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, 28,
- 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, 33,
- new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
- new Color([0,0,255]), 1),
- new Color([0,0,255,0.8]));
- renderer.addBreak(1, 10, style1);
- renderer.addBreak(10, 50, style2);
- renderer.addBreak(50, 100, style3);
- renderer.addBreak(100, 150, style4);
- renderer.addBreak(150, 200, style5);
-
- clusterLayer.setRenderer(renderer);
- map.addLayer(clusterLayer);
- // 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();
- }
- });
- </script>
- </head>
-
- <body>
- <div id="map"></div>
- </div>
- </body>
- </html>
Arcgis for JS之Cluster聚类分析的实现(基于区域范围的)
原文:http://www.cnblogs.com/lonelyxmas/p/5785016.html