1. 程式人生 > >Arcgis api for JavaScript 4.6 點聚合分析

Arcgis api for JavaScript 4.6 點聚合分析

建立物件:

var clusterLayer = new ClusterLayer({  
						"view":mapManager.view,
						"map":mapManager.map,
						"data": photoInfo.data,  
						"id": clusterAnalysis.layerId,
						"labelColor": "#000",  
						"labelOffset": 0,
						"symbolArray":[symbolManager.clusterGreen,symbolManager.clusterBlue,symbolManager.clusterRed],
						"graphicSym":symbolManager.clusterBlue
					});  

執行點聚合:

//執行聚合
clusterLayer.excuseClusterEvent();

設定地圖縮放事件:

view.watch("zoom",function(){
						showProgressbar("點聚合","正在努力中,請耐心等待...");
						clusterAnalysis.clusterLayer.changeExtentEvent();
						$('#progressBarWin').window('close');
					});

設定地圖點選事件:

on(mapManager.view, 'click', lang.hitch(this, function(evt) {
 var screenPoint = {x: event.x,y: event.y};
 view.hitTest(screenPoint).then(function (response) {
	if (response.results.length) {
	 var graphic = response.results[0].graphic;
		data = clusterLayer.onClick(graphic);
}
});
}));

將聚合圖層新增到地圖:

map.add(clusterLayer);

下面的ClusterLayer物件:

define([
    "dojo/_base/declare",
    "dojo/_base/array",
    "esri/Color",
  	"dojo/_base/connect",
  	"esri/geometry/SpatialReference",
  	"esri/geometry/Point",
  	"esri/Graphic",
  	"esri/symbols/SimpleMarkerSymbol",
  	"esri/symbols/TextSymbol",
  	"esri/geometry/support/webMercatorUtils",
  	"esri/PopupTemplate",
  	"esri/layers/GraphicsLayer", "esri/layers/mixins/ScaleRangeLayer"
], function (
  declare, arrayUtils, Color, connect,
  SpatialReference, Point, Graphic, SimpleMarkerSymbol, TextSymbol,webMercatorUtils, 
  PopupTemplate, GraphicsLayer,ScaleRangeLayer
) {
	return GraphicsLayer.createSubclass([ScaleRangeLayer],{
		declaredClass : "ClusterLayer",
		properties : {
			view:null,//當前檢視,必須
			map:null,//當前地圖,必須
			id:"clusters",//圖層id,必須
			data:[],//聚類資料,必須
			field : "clusterCount",//聚類的欄位
			distance:100,//距離
			labelColor:"#FFF",//標註顏色,預設為白色
			labelOffset : -4,//標註偏移,預設為-4
			resolution:null,
			clusters : null,
	        singles : null, //單個物件,點選時出現
	        showSingles : true,
	        symbolArray : null,//graphic樣式陣列
	        singleSym:null,//單個graphic樣式
	        graphicSym:null,//要素高亮樣式
	        singleTemplate : new PopupTemplate({ "title": "{type}", "description": "{material}" }),
	        spatialReference : null,//空間參考
	        maxSingles : 1000//單個叢集最大數
		},
		/**
		 * @description 初始化
		 * @creator 王培珍
		 * @createtime 2018-02-06
		 */
		init:function(){
			this.clusters = [];
			this.singles = [];
			this.spatialReference = this.view.spatialReference;
			if(this.symbolArray == null){
				var red = new SimpleMarkerSymbol("circle", 20, null, new Color("green"));
				var blue = new SimpleMarkerSymbol("circle", 20, null, new Color("blue"));
				var green = new SimpleMarkerSymbol("circle", 20, null, new Color("red"));
				this.symbolArray = [red, blue,green];
			}
		},
		/**
		 * @description 執行點聚合事件
		 * @creator 王培珍
		 * @createtime 2018-02-06
		 */
		excuseClusterEvent: function() {
			//判斷當前是否存在該id的圖層,若有,刪除
			var layer = this.map.findLayerById(this.id);
			if(layer != undefined || layer != null)
				this.map.remove(layer);
			//初始化
			this.init();
			//清除當前圖層上的圖形
			this.clear();
			//設定Resolution
			this.setResolution(); 
			//建立聚合圖形
		    this.clusterGraphics();
		    var div = this.inherited(arguments);
		    return div;
		},

		/**
		 * @description 設定Resolution
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		setResolution: function() {
			var e = this.view.extent;
			var rightTop =  new Point(e.xmax, e.ymax, this.spatialReference); //右上角  
			var leftBottom =  new Point(e.xmin, e.ymin, this.spatialReference); //左下角
			var rightTopPoint = webMercatorUtils.geographicToWebMercator(rightTop);  
			var leftBottomPoint = webMercatorUtils.geographicToWebMercator(leftBottom); 
			this.resolution = (rightTopPoint.x - leftBottomPoint.x) / this.view.width;
		},
		/**
		 * @description 地圖縮放處理事件
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		changeExtentEvent:function(){
			//清除當前圖層上的圖形
			this.clear();
			//設定Resolution
			this.setResolution(); 
			//建立聚合圖形
		    this.clusterGraphics();
		},
		/**
		 * @description 移除縮放事件
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
	    removeZoomEnd: function() {
	    	this.inherited(arguments);
	    },

	    /**
		 * @description 新增聚合叢集
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		add : function(p) {
			//判斷點是否落在現有叢集中,若沒有,則新建一個新叢集
			if (p.declaredClass) {
				this.inherited(arguments);
				return;
			}

			//把新資料新增到data中
			this.data.push(p);
			//是否新增到叢集中
			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);
					//更新叢集label資訊
					this.updateLabel(c);
					clustered = true;
					break;
				}
			}

			//如果沒有新增到叢集中,則建立新叢集
			if (!clustered) {
				this.clusterCreate(p);
				p.attributes.clusterCount = 1;
				this.showCluster(p);
			}
		},
		/**
		 * @description 清楚當前所有叢集
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		clear : function() {
			var layer = this.map.findLayerById(this.id);
			if (layer != undefined || layer != null)
				layer.removeAll();
			// Summary: Remove all clusters and data
			// points.
			this.inherited(arguments);
			this.clusters.length = 0;
		},

		/**
		 * @description 清除單個叢集
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		clearSingles : function(singles) {
			var s = singles || this.singles;
			arrayUtils.forEach(s, function(g) {
				this.remove(g);
			}, this);
			this.singles.length = 0;
		},
		/**
		 * @description 點選叢集事件
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		onClick : function(e) {
			this.clear();
			//清除單個要素
			this.clearSingles(this.singles);

			//獲取當前叢集的資料
			var singles = [];
			for (var i = 0, il = this.data.length; i < il; i++) {
				if (e.attributes.clusterId == this.data[i].attributes.clusterId) {
					singles.push(this.data[i]);
				}
			}
			//判斷單個叢集長度是否有大於單個叢集最大長度
			if (singles.length > this.maxSingles) {
				alert("對不起,當前叢集長度大於" + this.maxSingles + "個,請放大到更大級別再進行查詢當個叢集!");
				return null;
			} else {
				//停止地圖點選
				//e.stopPropagation();
				//this.view.popup.content = "<div style='background-color:DarkGray;color:white'> miles.</div>";
				//this.map.infoWindow.show(e.graphic.geometry);
				this.addSingles(singles);
				return singles;
			}
		},

		/**
		 * @description 建立聚合圖形
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		clusterGraphics : function() {
			for (var j = 0, jl = this.data.length; j < jl; j++) {
				var point = this.data[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();
		},

		/**
		 * @description 判斷兩點之間是否屬於同一個叢集
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		clusterTest : function(p, cluster) {
			var c_latlng;
			var p_latlng;
			if (this.spatialReference.isWebMercator) {
				//地圖 為WebMercator座標系
				c_point = new Point(cluster.x,
						cluster.y,
						this.spatialReference);
				p_point = new Point(p.x, p.y,
						this.spatialReference);
			} else {
				//地圖為非WebMercator座標系,則需轉換為墨卡託座標系
				c_latlng = new Point(
						parseFloat(cluster.x),
						parseFloat(cluster.y),
						this.spatialReference);
				p_latlng = new Point(parseFloat(p.x),
						parseFloat(p.y),
						this.spatialReference);
				c_point = webMercatorUtils
						.geographicToWebMercator(c_latlng);
				p_point = webMercatorUtils
						.geographicToWebMercator(p_latlng);
			}
			var distance = (Math.sqrt(Math.pow(
					(c_point.x - p_point.x), 2)
					+ Math.pow((c_point.y - p_point.y),
							2)) / this.resolution);
			return (distance <= this.distance);
		},

		/**
		 * @description 新增新點到現有叢集
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		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++;
			//判斷是否包含attributes欄位,若無,賦值
			if (!p.hasOwnProperty("attributes")) {
				p.attributes = {};
			}
			//給這個屬性一個clusterId值
			p.attributes.clusterId = cluster.attributes.clusterId;
		},

		/**
		 * @description 建立一個新叢集
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		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,
				"attributes" : {
					"clusterCount" : 1,
					"clusterId" : clusterId,
					"extent" : [ p.x, p.y, p.x, p.y ]
				}
			};
			this.clusters.push(cluster);
		},

		/**
		 * @description 顯示所有叢集
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		showAllClusters : function() {
			var array = this.groupData();
			for (var i = 0; i <this.clusters.length; i++) {
				var c = this.clusters[i];
				if(c.attributes.clusterCount > array[0]){
					this.singleSym = this.symbolArray[0];
				}else if(c.attributes.clusterCount > array[1]){
					this.singleSym = this.symbolArray[1];
				}else{
					this.singleSym = this.symbolArray[2];
				}
				this.showCluster(c);
			}
		},
		/**
		 * @description 獲取分組組值陣列
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		groupData:function(){
			//獲取最大最小值
			var max = this.clusters[0].attributes.clusterCount;
			var min = this.clusters[0].attributes.clusterCount;
			for (var i = 0; i <this.clusters.length; i++) {
				var count = this.clusters[i].attributes.clusterCount;
				if(max < count)
					max = count;
				else if(min > count)
					min = count;
			}
			//組距
			var dValue = (max - min)/3;
			return [(max - dValue),(min + dValue)];
		},
		/**
		 * @description 顯示叢集
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		showCluster : function(c) {
			var point = new Point(c.x, c.y,
					this.spatialReference);
			if(this.singleSym == null)
				this.singleSym = new SimpleMarkerSymbol("circle", 20, null, new Color("red"));
			//新增點圖形
			this.add(new Graphic(point, this.singleSym,c.attributes));
			//新增文字到指定位置
			var label = new TextSymbol(c.attributes.clusterCount.toString())
			label.color = new Color(this.labelColor);
			label.xoffset = 0;
			label.yoffset = this.labelOffset;
			this.add(new Graphic(point, label,c.attributes));
		},
		/**
		 * @description 新增單個點
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		addSingles : function(singles) {
			//新增單個點到地圖上
			arrayUtils.forEach(singles, function(p) {
				var g = new Graphic(new Point(p.x, p.y,this.spatialReference),this.graphicSym, p.attributes,this.singleTemplate);
				this.singles.push(g);
				if (this.showSingles) {
					this.add(g);
				}
			}, this);
		},

		/**
		 * @description 更新叢集圖形
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		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);
			}
		},
		/**
		 * @description 更新叢集Label
		 * @creator wpz
		 * @createtime 2018-02-06
		 */
		updateLabel : function(c) {
			//找到已存在的叢集label
			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) {
				//更新叢集Label
				this.remove(label[0]);
				var newLabel = new TextSymbol(c.attributes.clusterCount);
				newLabel.color = new Color(this.labelColor);
				newLabel.xoffset = 0;
				newLabel.yoffset = this.labelOffset;
				this.add(new Graphic(new Point(c.x,c.y, this.spatialReference), newLabel, c.attributes));
			} else {
				console.log("didn't find exactly one label: ",label);
			}
		}

	});
});