要说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], 2 } }); var pointSym = new SimpleMarkerSymbol({ color: [255, 0, 0], outline: { color: [255, 255, 255], 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的。
好了,这个例子就不总结啦,都在最顶头就说完了。下个例子见。