要說GIS空間分析最經典的例子,就是緩沖區分析了。
本例使用geometryEngine來繪制緩沖區環。因為官方給的例子有3D和2D場景,所以就會顯得比較復雜。
當鼠標在視圖上點擊時,就會生成一個緩沖區環(以點擊的點為中心);
當鼠標拖拽時,若不是漫游狀態,則緩沖區環也會跟着一起動。
我會把生成緩沖區的核心代碼用大標題紅色標出,各位可以直接跳到那里學緩沖區的生成。
首先了解一下,緩沖區是以什么樣的東西存在的?
在桌面GIS里,緩沖區就是一個面要素,可以是要素類也可以是shp文件。
在AJS里,緩沖區是一個Polygon或Polygon[],存在於GraphicsLayer圖層對象中。
在正式看這個例子之前,需要了解一個極為重要的工具類:geometryEngine。它提供了數十種空間分析方法,如buffer()、clip()、intersect()等等等等。
在這里就只用到了geodesicBuffer()。//至於geodesicBuffer()和buffer()的區別是什么,暫時還不得知,待查。
好了,有了這些預備知識,我們就可以開始了!
結果展示
在Navigation Mode復選框沒有點選之前,對當前地圖框點擊或者拖拽會生成一個以點擊點為中心的緩沖區圓環。
給出引用
var chkMapView = false, chkSceneView = false;
require([ "esri/Map", "esri/views/SceneView", "esri/views/MapView", "esri/layers/GraphicsLayer", "esri/Graphic", "esri/symbols/SimpleMarkerSymbol","esri/symbols/SimpleFillSymbol", "esri/geometry/geometryEngine", "dojo/on", "dojo/dom", "dojo/domReady!" ], function( Map,SceneView,MapView, GraphicsLayer,Graphic, SimpleMarkerSymbol,SimpleFillSymbol, geometryEngine, on, dom ){...} );
哇2D3D同時用好酷炫。
注意:注意:注意:require上方多了兩個bool類型的變量,有什么用,下面會說。
關鍵就是geometryEngine了。
思路
因為這個例子的多余代碼太多了,我就先講講思路吧,否則讀者會被繞暈。
點擊視圖——獲取點位——傳入geometryEngine的geodesicBuffer()方法——返回Polygon到GraphicsLayer——刷新view的顯示。
骨架
function(...) { var map = new Map({...}); var view3d = new SceneView({...}); var view2d = new MapView({...}); var polySym = new SimpleFillSymbol({...});
var pointSym = new SimpleMarkSymbol({...}); var bufferLayer = new GraphicsLayer(); var pointLayer = new GraphicsLayer(); map.addMany([bufferLayer, pointLayer]); view2d.on('drag', function(evt){...}); view3d.on('drag', function(evt){...}); view2d.on("click", function(evt){...}); view3d.on('click', function(evt){...}); function bufferPoint(point){...} function clearGraphics(){...} on(dom.byId("chkBoxMap"), "click", function(evt){...}); on(dom.byId("chkBoxScene"), "click", function(evt){...}); }
除去6個事件方法體,和老生常談的map、view,就只有polySym和pointSym這兩個符號對象、兩個幾何圖層、兩個功能函數,並不是很難理解這個例子。
//題外話:老外估計寫這個demo也是交叉混寫的,雙引號和單引號隨便用,同一章不同例子的函數參數名有時候也是隨便寫,可能是js的語言特性吧。
在這里,polySym和pointSym兩個對象的作用僅僅是顯示鼠標點擊點和生成緩沖區的圓區域,不作為重點,但是具體代碼還是給有需要的人看看:

var polySym = new SimpleFillSymbol({ color: [140, 140, 222, 0.5], outline: { color: [0, 0, 0, 0.5], width: 2 } }); var pointSym = new SimpleMarkerSymbol({ color: [255, 0, 0], outline: { color: [255, 255, 255], width: 1 }, size: 7 });
先講講兩個方法體有什么作用吧:
兩個方法體:生成緩沖區與清理圖層
function bufferPoint(point) { clearGraphics(); pointLayer.add(new Graphic({ geometry: point, symbol: pointSym })); var buffer = geometryEngine.geodesicBuffer(point, 560, "kilometers"); bufferLayer.add(new Graphic({ geometry: buffer, symbol: polySym })); } function clearGraphics() { pointLayer.removeAll(); bufferLayer.removeAll(); }
后面一個一目了然,清除兩個幾何圖層上的要素。
前一個,先調用后一個,然后把傳入的點添加到點幾何圖層上,使用pointSym符號對象。
最關鍵的一句就是geometryEngine.geodesicBuffer()了,可知傳入的point,是個geometry類的對象,緩沖半徑為560"kilometers".
返回的是一個polygon(因為這里只有一個單點),然后把這個polygon(名為buffer)添加到面幾何圖層上。
——————
其實緩沖區的例子說到這里就可以結束了,但是還有一大堆的事件是告訴我們怎么獲取點擊點的,又怎么把點擊的點轉化成Geometry的,因為事件中肯定會調用這兩個方法體的,不然無法生成緩沖區。
還有興趣的同學可以繼續跟我探尋這6個事件。
先上一個流程圖:
就是這么簡單。
先看看兩個純DOM元素的click事件吧:
on(dom.byId("chkBoxMap"), "click", function(evt) { chkMapView = dom.byId("chkBoxMap").checked; if (chkMapView) { clearGraphics(); } }); on(dom.byId("chkBoxScene"), "click", function(evt) { chkSceneView = dom.byId("chkBoxScene").checked; if (chkSceneView) { clearGraphics(); } });
點擊復選框后,將復選框的值(是否選中)賦給chkMapView和chkSceneView這兩個最開始在require前面的變量。
然后檢查chkMapView和chkSceneView的值,如果是真,即說明剛剛點擊是從緩沖區生成狀態轉變為漫游狀態,則需要執行clearGraphics()方法清理圖層上的圖案。
再來看看四個其他的事件,是兩個view上的事件:

view2d.on('drag', function(evt) { if (!chkMapView) { evt.stopPropagation(); var point = view2d.toMap({ x: evt.x, y: evt.y }); if (point) { bufferPoint(point); } } else if (chkMapView) { clearGraphics(); } }); view3d.on('drag', function(evt) { if (!chkSceneView) { evt.stopPropagation(); var point = view3d.toMap({ x: evt.x, y: evt.y }); if (point) { point.hasZ = false; point.z = undefined; bufferPoint(point); } } else if (chkSceneView) { clearGraphics(); } });
拖拽事件,比click事件略微復雜。
先進去就是if else分支,如果在漫游狀態則調用clearGraphics(),如果不在漫游狀態:
首先停止漫游狀態,調用stopPropagation()方法。
然后獲取單擊的點的信息,使用View的toMap方法,返回一個Point對象(Geometry的子類)。
若返回的Point對象不為空,則執行bufferPoint()方法,生成緩沖區。
在3D視圖中還會檢查z坐標。

view2d.on("click", function(evt) { if (!chkMapView) { if (evt.mapPoint) { bufferPoint(evt.mapPoint); } } else if (chkMapView) { clearGraphics(); } }); view3d.on('click', function(evt) { if (!chkSceneView) { if (evt.mapPoint) { evt.mapPoint.hasZ = false; evt.mapPoint.z = undefined; bufferPoint(evt.mapPoint); } } else if (chkSceneView) { clearGraphics(); } });
這兩個click事件就簡單了,其實就是沒有了drag事件的stopPropagation()那部分,獲取點位也沒那么麻煩了,直接傳evt事件流中的mapPoint屬性即可。
可能有人會問,為什么2d視圖移動點后3d視圖也跟着動呢?
是因為兩個視圖共用了一份map,map中是包含了兩個顯示緩沖區用的GraphicsLayer的。
好了,這個例子就不總結啦,都在最頂頭就說完了。下個例子見。