Flex熱點圖客戶端渲染

相信大家都用過用GIS做熱點圖的經歷,那麼通常的流程是,構建一個熱點圖工具,測試運行,在ArcMap中將工具添加到TOC中,然後發佈一個GP服務並且帶有ResultMap Service,這樣在前端需要熱點圖的時候,發出請求,執行GP服務,返回生成的熱地圖服務,添加到客戶端的MAP中。這樣一個過程不僅複雜而且容易出錯,同時響應慢,有時需要等待一段時間。

既然如此,下面就向大家介紹一種Flex客戶端生成熱點圖的方法,通過客戶端生成熱點圖,方便快捷。

原理:

1、針對空間座標的各個點,計算出屏幕座標,並保存在數組中。

2、利用BitmapData對象,在各個點的屏幕座標處,繪製圓形,圓形的大小可以根據當前點的相關屬性進行設置。

3、對BitMapData繪製的圖形進行處理,比如閥值處理,漸變處理,濾鏡處理等。如下圖:




客戶端熱點圖渲染示例

實現步驟:

1、針對空間數據的熱點圖客戶端渲染,利用ArcGIS API for Flex接口,通過自定義heatmap圖層,並繼承FeatureLayer,用於顯示,獲取數據。

public class HeatmapLayer extends FeatureLayer

2、計算FeatureLayer中點數據的屏幕座標並保存在數組中:

private function updatePoints():Boolean {
			m_x.length = 0;
			m_y.length = 0;
			
			var max:Number = 5.0;
			
			const mapW:Number = super.map.width;
			const mapH:Number = super.map.height;
			const extW:Number = super.map.extent.width;
			const extH:Number = super.map.extent.height;
			const facX:Number = mapW / extW;
			const facY:Number = mapH / extH;
			
			var weight:Number  = 1;
			
			const dict:Dictionary = new Dictionary(true);
			var ac:ArrayCollection = this.graphicProvider as ArrayCollection;
			for each (var g:Graphic in ac) {
				if (g.geometry.type != com.esri.ags.geometry.Geometry.MAPPOINT) {return false;}
				g.alpha = (m_showPoints) ? 1 : 0;
				if (super.map.extent.contains(g.geometry)) {
					const sx:Number = ((g.geometry as MapPoint).x - super.map.extent.xmin ) * facX;
					const sy:Number = mapH - ((g.geometry as MapPoint).y - super.map.extent.ymin ) * facY;
					
					m_x.push(sx);
					m_y.push(sy);
					
					const key:String = Math.round(sx) + "_" + Math.round(sy);
					var val:Number = dict[key] as Number;
					if (m_valueField != "") {
						weight = g.attributes[m_valueField] || 1;
					}
					if (isNaN(val)) {
						val = weight;
					} else {
						val += weight;
					}
					dict[key] = val;
					max = Math.max(max, val);
				}
			}
			m_centerValue = Math.max(19.0, 255.0 / max);
			return true;
		}

3、利用BitMapData繪製圓形,並對圖像進行處理

private function drawHeatMap():void {
			const heatDiameter:int = _heatRadius * 2;  //熱點的直徑
			const matrix1:Matrix = new Matrix();           //轉換矩陣
			trace("a="+matrix1.a.toString());
			trace("b="+matrix1.b.toString());
			trace("c="+matrix1.c.toString());
			trace("d="+matrix1.d.toString());
			trace("tx="+matrix1.tx.toString());
			trace("ty="+matrix1.ty.toString());
			matrix1.createGradientBox(heatDiameter, heatDiameter, 0, -_heatRadius, -_heatRadius);
			
			m_shape.graphics.clear();
			trace(m_centerValue.toString());
			//指定漸變填充參數,放射狀填充,指定填充顏色
			m_shape.graphics.beginGradientFill(GradientType.RADIAL, [m_centerValue, 0], [1,1], [0,255], matrix1);  
			m_shape.graphics.drawCircle(0, 0, _heatRadius);   //畫圓
			m_shape.graphics.endFill();   //按照指定的參數進行填充
			m_shape.cacheAsBitmap = true;   //緩存
			
			//創建一個完全透明的位圖
//			trace("m_shape.width="+m_shape.width.toString());
//			trace("m_shape.height="+m_shape.height.toString());
			const bitmapDataShape:BitmapData = new BitmapData(m_shape.width, m_shape.height, true, 0x00000000);
			const matrix2:Matrix = new Matrix();
			//matrix2沿着橫縱方向移動半徑的距離
			matrix2.tx = _heatRadius;
			matrix2.ty = _heatRadius;
			
			//將之前定義的圓形(m_shape)繪製出來,並在橫縱座標移動一個半徑的距離
			bitmapDataShape.draw(m_shape, matrix2);
			
			//clip是與Map完全重合的一個矩形
			const clip:Rectangle = new Rectangle(0, 0, super.map.width, super.map.height);
			
//			trace(m_bitmapDataLayer.width.toString());
			if (m_bitmapDataLayer && m_bitmapDataLayer.width !== map.width && m_bitmapDataLayer.height !== map.height)
			{
				//釋放用來存儲 m_bitmapDataLayer 對象的內存
				m_bitmapDataLayer.dispose();
				m_bitmapDataLayer = null;
			}
			if (m_bitmapDataLayer === null)
			{
				//第一次運行,創建一個和map一樣大小的全透明的BitMapData
				m_bitmapDataLayer = new BitmapData(map.width, map.height, true, 0x00000000);
			}
			//透明填充
			m_bitmapDataLayer.fillRect(clip, 0x00000000);
			const len:int = m_x.length;
			for (var i:int = 0; i < len; i++)
			{
				matrix2.tx = m_x[i] - _heatRadius;
				matrix2.ty = m_y[i] - _heatRadius;
				m_bitmapDataLayer.draw(bitmapDataShape, matrix2, null, BlendMode.SCREEN);
			}
			//釋放bitmapDataShape的內存
			bitmapDataShape.dispose();
			
			// paletteMap leaves some artifacts unless we get rid of the blackest colors 
			m_bitmapDataLayer.threshold(m_bitmapDataLayer, m_bitmapDataLayer.rect, POINT, "<=", 0x00000003, 0x00000000, 0x000000FF, true);
			
			// Replace the black and blue with the gradient. Blacker pixels will get their new colors from
			// the beginning of the gradientArray and bluer pixels will get their new colors from the end. 
			m_bitmapDataLayer.paletteMap(m_bitmapDataLayer, m_bitmapDataLayer.rect, POINT, null, null, gradientArray, null);
			
			// This blur filter makes the heat map looks quite smooth.
			m_bitmapDataLayer.applyFilter(m_bitmapDataLayer, m_bitmapDataLayer.rect, POINT, m_blurFilter);
			
			graphics.clear();
			
			var matrix3:Matrix = new Matrix(1.0, 0.0, 0.0, 1.0, parent.scrollRect.x, parent.scrollRect.y);
			
			graphics.beginBitmapFill(m_bitmapDataLayer, matrix3, false, false);
			graphics.drawRect(parent.scrollRect.x, parent.scrollRect.y, map.width, map.height);
			graphics.endFill();
			
		}

4、把自定義的熱點圖圖層像普通的圖層一樣加載到Map中就可以實現熱地圖的客戶端渲染了。

通過以上介紹就可以不用服務端,在客戶端實現熱點圖的渲染,非常簡單,快捷方便。

還可以通過ArcGIS Flex幫助裏面的示例去體驗與瞭解熱地圖的客戶端渲染,點此體驗

同時爲大家提供了HeatmapLayer的在線下載,點此下載



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章