ArcGIS JS其实已经提供了量算的Widget,但是用过的童鞋都知道,那个玩意儿实在是太丑了,和程序搭配起来实在很突兀,因此自己实现一个量算工具是无疑是最好的办法,无图无真相,我先放两张效果图。
图1.量算面积
图2 量算距离
官方给出的Sample里,测量距离和面积都要用到GeoServeice,而且网上也都是类似的代码,都不是直接在客户端进行的量算。好在ArcGIS JS 在 3.13版本增加了 "esri/geometry/geometryEngine" 模块,借助这个模块就可以实现客户端的量算。
这个模块还有很多方法,具体内容可以到官网上查看geometryEngine的详细信息。
//计算距离
_calDistance: function (point1, point2) { var line = new Polyline(this.defaults.map.spatialReference)
line.addPath([point1, point2]) if (this.defaults.map.spatialReference.isWebMercator()||this.defaults.map.spatialReference.wkid == "4326") {//在web麦卡托投影和WGS84坐标系下的计算方法
return geometryEngine.geodesicLength(line, "meters")
} else {//在其他投影坐标系下的计算方法
return geometryEngine.planarLength(line, "meters")
}
},
//计算面积
_calArea: function (polygon) { var spatialReference = this.defaults.map.spatialReference if (spatialReference.isWebMercator()||spatialReference.wkid == "4326" ) { return geometryEngine.geodesicArea(polygon, "square-meters")
} else { return geometryEngine.planarArea(polygon, "square-meters")
}
},
好了,解决了核心问题,剩下的就只需要如何分段显示距离和提高用户体验了。
1.测量距离
绘制线的时候,用的是ArcGIS JS 的Draw 模块在开始测量的时候,监听地图点击事件,把在地图上点击到的点加到 this._stopPoints 数组中,然后每次点击地图,就用当前点和上一个点进行距离计算,计算结果添加到this_stopDistances数组中,接着把计算结果用graphic添加到地图上。
//开始测量距离
_startMeasureDistance: function () { this._clearMapMouseClickEvent() this._stopPoints = [] this._stopDistances = [] this._measureLayer.clear() this.toolbar.deactivate() this.toolbar.activate(Draw.POLYLINE) var stopPoints = this._stopPoints var stopDistances = this._stopDistances var self = this this._mapClickFlag = this.defaults.map.on("click", function (evt) { var distance = 0 var stopPoint = evt.mapPoint if (stopPoints.length >0) { var startPoint = stopPoints[stopPoints.length - 1]
distance = self._calDistance(startPoint, stopPoint) if (self._stopDistances.length >0) {
distance += self._stopDistances[self._stopDistances.length - 1]
}
stopDistances.push(distance)
}
stopPoints.push(stopPoint) var stopGraphic = new Graphic(stopPoint, self.defaults.markerSymbol) var textGraphic = self._getStopPointGraphic(stopPoint, distance)
self._measureLayer.add(stopGraphic)
self._measureLayer.add(textGraphic)
})
},
结束量测,添加清除按钮,这里的清除按钮是用svg路径绘制的,在代码最后的this._clearMapMouseClickEvent()是用于取消监听map的click事件,在最后我会贴出全部代码。
//测量距离结束,添加清除按钮、测量线段
_endMeasureDistance:function(line,endPoint){ var lineGraphic = new Graphic(line, this.toolbar.lineSymbol) var clearGraphic = this._createClearBtn(endPoint) this._measureLayer.add(clearGraphic) this._measureLayer.add(lineGraphic)
lineGraphic.getDojoShape().moveToBack() this._clearMapMouseClickEvent()
},
2.面积量测
面积量测就相对简单了,用Draw模块绘制完成Polygon后,利用之前贴出的计算面积的方法计算完成后再把结果添加到地图上。
//开始测量面积
_startMeasureArea: function () { this._clearMapMouseClickEvent() this._measureLayer.clear() this.toolbar.deactivate() this.toolbar.activate(Draw.POLYGON)
}, //测量面积结束,添加清除按钮、测量结果
_endMeasureArea: function (polygon) { var area = this._calArea(polygon) if (area >1000000) {
area = (area / 1000000).toFixed(2) + "平方千米"
} else {
area = area.toFixed(2) + "平方米"
} var center = polygon.getCentroid() var ploygonGraphic = new Graphic(polygon, this.toolbar.fillSymbol) var textSymbol = this._createTextSymbol(area)
textSymbol.setOffset(30, 10) var textGraphic = new Graphic(center, textSymbol) var clearBtn = this._createClearBtn(center) this._measureLayer.add(ploygonGraphic) this._measureLayer.add(textGraphic) this._measureLayer.add(clearBtn)
ploygonGraphic.getDojoShape().moveToBack()
},
下面我们就来看一看如何使用这个自定义的测量模块了。
<!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8">
<title>Extra-Map-App</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.16/esri/css/esri.css">
<link rel="stylesheet" href="css/mainApp.css">
<script>
var dojoConfig = {
packages: [{
name: 'custom',
location: location.pathname.replace(/\/[^/]+$/, '') + '/custom'//从cdn加载自己定义的模块方法
},
{
name: 'dextra',
location: '/extra.arcgis.3.x/dist/'//从cdn加载自己定义的模块方法 }]
} </script>
<script src="https://js.arcgis.com/3.16/"></script>
<script src="js/mainApp.js"></script>
<style>
#measureTools {
position: absolute
top: 50px
left: 50px
z-index: 1000
}
</style></head><body><div id="measureTools">
<button class="measure-distance">距离</button>
<button class="measure-area">面积</button></div><div id="map" style="overflow: hidden"></div></body></html>
在使构造时测量工具时,添加”.measure-distance”类表示测量距离;添加”.measure-area”类表示测量面积。在这个例子中,我的自定义模块名叫dextra,添加引用时按照dojo的AMD规范来进行加载。
require([ "esri/map", "dextra/dijit/MeasureTools", "dextra/layers/GoogleImageLayer", "dextra/layers/GoogleImageAnnoLayer", "dojo/domReady!"], function(Map,
deMeasureTools,GoogleImageLayer,GoogleImageAnnoLayer) { var map = new Map("map", {
showAttribution:false,
fadeOnZoom:true,
force3DTransforms:true,
center: [101.7, 24.6],
zoom: 10,
autoResize:true,
sliderPosition:"bottom-right",
logo:false,
}) var googleimgLayer=new GoogleImageLayer() var googleAnnoLayer=new GoogleImageAnnoLayer()
map.addLayer(googleimgLayer)
map.addLayer(googleAnnoLayer) var measureTool=new deMeasureTools({
map:map
},"measureTools")
})
CircleGeometry圆形
RingGeometry
环形
PlaneGeometry
矩形的几何体
ShapeGeometry
通过路径构建一个多边形=>自定义形状
BoxGeometry
长方体
TetrahedronGeometry
四面体
ConeGeometry
圆锥
CylinderGeometry
圆柱
DodecahedronGeometry
十二面体
IcosahedronGeometry
二十面体
OctahedronGeometry
八面体
SphereGeometry
球体
TorusGeometry
圆环几何
TubeGeometry
管状体
LatheGeometry
轴向对称:例如花瓶
PolyhedronGeometry
多面体 =顶点+面
注:将它们投射到球体上,然后将其分割到所需的细节水平
ParametricGeometry
通过函数构建几何体,参量体
TextGeometry
文字体
TorusKnotGeometry
创建圆环结,其特殊形状由一对互质整数p和q定义。如果p和q不是互质的,结果将是环面连接。
ExtrudeGeometry
伸出的几何体,该对象将2D形状挤出到3D几何体。
EdgesGeometry
获取几何体的边线
WireframeGeometry
作帮助对象来将几何 对象视为线框