您的位置:首页 > Web前端 > JavaScript

0305-二维地图开发-算下经常散步的这条路到底有多长(地图测量)

2018-02-09 11:39 309 查看
上一小节介绍了在地图上任性涂鸦,画了个人头像,功能是实现了,但是效果凑合。说到绘制,其实它的应用场景还是挺多的,特别是在日常工作的设计环节。譬如:要搞个活动,活动的区域在哪?活动的线路从哪里到哪里?等等。这些都是大家很多日常的工作中都会涉及到的,在地图上打些点、绘个线、标个区域,再把做好的这张图跟参与活动的成员说明,这个沟通方式效率上肯定高很多。所以,不要小看标绘这么个小小的功能。再往大了说,打仗的时候,军队常用到电子沙盘,在电子沙盘上排兵布阵,其实就是用到了地图的标绘功能,而且标绘还是重要的核心功能。所以,标绘虽然很基础但也很重要。

标绘完成之后,还有一个需要了解的信息是:标绘的线路到底有多长,标绘的区域有多大?这些也是很多时候我们需要关注的。因为线路的长短、区域的大小对于资源的投入来说是非常重要。举个栗子:现在各大城市都流行跑马拉松,包括半马和全马,假设赛事的组织方不提前告知跑者线路的长度,大家心里肯定犯嘀咕(最早菲迪皮茨从马拉松海边跑回雅典将胜利的消息告知乡亲们,就是不知道这段距离的长短,跑回去的时候已经上气不接下气)。所以,对于跑者来说提前了解线路的长短,对于是否参加这项赛事是非常重要的信息。同样对于组织者来说也是两个级别的赛事,需要投入的后勤保障和赛事运营资源也就不在一个体量上。特别是在起点和终点区域的选择上,更需要提前知道区域的面积到底有多大,能不能满足相应赛事的跑者聚集在这个区域。所以,你看长短和大小在日常中非常重要。

言归正卷。这一小节,我们接着上一小节已写好的素描工具,再利用API中提供的测长度和测面积的接口来实现线路的距离测量和区域面积的测量。要测量,我们需要使用的就是geometryEngine这个接口。这个接口包含了很多关于几何的操作,除了测量之外,还包括缓存区计算、坐标转换、相交分析、包含分析等等和几何空间关系有关的常用操作。那么,要测量长度,我们需要geometryEngine这个接口中的方法是:geodesicLength()或者planarLength(),该如何选择这两个方法,看下面这段注释:

//**********************
//计算线的长度:如果计算的几何坐标是WGS84(wkid: 4326)或者Web Mercato(wkid:3857)
//建议采用geodesicLength()为最佳
//否则采用平面坐标计算方法planarLength()
//**********************


同样的,要测量一个区域的面积,geometryEngine接口也提供了两个不同的方法geodesicArea()和planarArea(),选择的时候也是参考以下注释:

////**********************
//计算多边形的面积:如果计算的几何坐标是WGS84(wkid: 4326)或者Web Mercato(wkid:3857)
//建议采用geodesicArea()为最佳
//否则采用平面坐标计算方法planarArea()
//**********************


看到这里,你可能也已经猜出来了,测量长度和测量面积的方法都有两种方法,一个是基于球面的测量,一个是基于平面的测量。为什么会有球面和平面的区别?这会涉及到坐标系方面的基础知识,感兴趣的可以google下这方面的信息。但是不管是用哪种方法,它们接收的参数都是一样的,一个参数是几何,一个参数是计算的单位:









好了,这里关键的信息都已经解读完了,下面是全部的代码:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
<title>二维地图开发-量测</title>
<link rel="stylesheet" href="http://192.168.1.144/4.6/esri/css/main.css" />
<style>
html,
body,
#mapViewDiv {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
color:#8E980F;
}
#sketchToolsDiv {
background: #fff;
position: absolute;
top: 15px;
right: 15px;
padding: 10px;
}

.action-button {
font-size: 16px;
background-color: transparent;
border: 1px solid #D3D3D3;
color: #6e6e6e;
height: 32px;
width: 32px;
text-align: center;
box-shadow: 0 0 1px rgba(0, 0, 0, 0.3);
}

.action-button:hover,
.action-button:focus {
background: #0079c1;
color: #e4e4e4;
}

.active {
background: #0079c1;
color: #e4e4e4;
}
</style>
<script src="http://192.168.1.144/4.6/dojo/dojo.js"></script>
<script>
var myMap, mapView;

require([
"esri/Basemap",
"esri/layers/TileLayer",
"esri/Map",
"esri/views/MapView",
"esri/widgets/Sketch/SketchViewModel",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/geometry/geometryEngine",
"dojo/domReady!"
], function (Basemap, TileLayer, Map, MapView, SketchViewModel, Graphic, GraphicsLayer, geometryEngine){

// *************************************
// TileLayer接口负责加载ArcGIS Server发布的MapServer缓存切片服务
// http://map.geoq.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer是GeoQ提供的以中国区域为主的缓存切片服务 // TileLayer将作为Basemap对象的一个图层添加到Map对象中。
// *************************************
var layer = new TileLayer({
url: "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer"
});

// *************************************
// Basemap:负责管理所有自定义的基础地图
// 我们可以把所有的基础地图都放在Basemap对象中
// 每个基础地图服务在Basemap对象中都作为一个图层
// *************************************
var customBasemap = new Basemap({
baseLayers: [layer],
title: "基础地图",
id: "gisBasemap"
});

myMap = new Map({
basemap: customBasemap
});

mapView = new MapView({
center: [113.293701, 23.096313], //初始化地图居中时的中心经度、维度
container: "mapViewDiv", //地图展示区域,对应页面上的DIV
map: myMap, //MapView包含Map对象
zoom: 18 //初始显示地图级别
});

// *************************************
// 定义有一个GraphicsLayer,它的职能是作为存储在地图上绘制的点、线、多边形要素.
// GraphicsLayer简称客户端图层,它所保存的要素全部在浏览器端绘制。
// *************************************
sketchGraphicsLayer = new GraphicsLayer();
myMap.add(sketchGraphicsLayer);

//监听地图在加载完成之后,再初始化SketchViewModel
mapView.when(function() {

// *************************************
// SketchViewModel简化了将临时几何图形添加到MapView的过程,它节省了大量编写不同几何类型的代码的工作量。
// 要使用SketchViewModel,只需要配置对应的GraphicsLayer,以及点、线、多边形的符号。
// *************************************
var sketchViewModel = new SketchViewModel({
view: mapView,
sketchayer: sketchGraphicsLayer,
polylineSymbol: { // symbol used for polylines
type: "simple-line", // autocasts as new SimpleMarkerSymbol()
color: "#FCA800",
width: "3",
style: "solid"
},
polygonSymbol: { // symbol used for polygons
type: "simple-fill", // autocasts as new SimpleMarkerSymbol()
color: "#FCA800",
style: "solid",
outline: {
color: "#A5A5A5",
width: 1
}
}
});

//************************************************************
//监听鼠标绘制完成事件
//当绘制完成后,把绘制的图形添加到地图上
//注意,如果是绘制线的话,使用鼠标右键绘制,点击鼠标左键完成绘制
//***********************************************************
sketchViewModel.on("draw-complete", function(evt) {
// add the graphic to the graphics layer
sketchGraphicsLayer.add(evt.graphic);
calculateGeometry(evt.graphic.geometry);
setActiveButton();
});

// ****************************************
// 监听绘制线按钮鼠标点击事件
// 当点击该按钮时,激活sketchViewModel的线绘制功能
// ****************************************
var drawLineButton = document.getElementById("polylineButton");
drawLineButton.onclick = function() {
// set the sketch to create a polyline geometry
sketchViewModel.create("polyline");
setActiveButton(this);
};

// ***************************************
// 监听绘制多边形按钮鼠标点击事件
// 当点击该按钮时,激活sketchViewModel的多边形绘制功能
// ***************************************
var drawPolygonButton = document.getElementById("polygonButton");
drawPolygonButton.onclick = function() {
// set the sketch to create a polygon geometry
sketchViewModel.create("polygon");
setActiveButton(this);
};

// **************
// 清除在地图上绘制的图形
// **************
document.getElementById("resetBtn").onclick = function() {
sketchGraphicsLayer.removeAll(); //删除GraphicsLayer中的所有要素
sketchViewModel.reset(); //重新恢复sketchViewModel的初始状态
setActiveButton();
};

/**
* 激活按钮,以提醒当前在使用的工具
* @param electedButton
*/
function setActiveButton(selectedButton) {
// focus the view to activate keyboard shortcuts for sketching
mapView.focus();
var elements = document.getElementsByClassName("active");
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove("active");
}
if (selectedButton) {
selectedButton.classList.add("active");
}
}

/**
* 量测线的距离或多边形的面积
* @param geometry
* @return null
*/
function calculateGeometry(geometry) {
var labelPoint; //显示测量数值的坐标点
var valueLabel; //测量值
var unitLabel; //测量显示单位
if(geometry.type=="polyline"){
//********************** //计算线的长度:如果计算的几何坐标是WGS84(wkid: 4326)或者Web Mercato(wkid:3857) //建议采用geodesicLength()为最佳 //否则采用平面坐标计算方法planarLength() //**********************
valueLabel = geometryEngine.geodesicLength(geometry, "meters");
//在线的末端显示测量的结果
var lastPathIndex = geometry.paths.length-1;
var lastPointIndex = geometry.paths[lastPathIndex].length-1;
labelPoint = geometry.getPoint(lastPathIndex,lastPointIndex);
unitLabel = "米";
}else if(geometry.type=="polygon"){
////********************** //计算多边形的面积:如果计算的几何坐标是WGS84(wkid: 4326)或者Web Mercato(wkid:3857) //建议采用geodesicArea()为最佳 //否则采用平面坐标计算方法planarArea() //**********************
valueLabel = geometryEngine.geodesicArea(geometry, "square-kilometers");
labelPoint = geometry.centroid;
unitLabel = "平方公里";
}
valueLabel = Math.abs(valueLabel);
var graphic = new Graphic({
geometry: labelPoint,
symbol: {
type: "text",
color: "#FC0101",
haloColor: "#FFFFFF",
haloSize: "10px",
text: valueLabel.toFixed(2) + unitLabel,
font: { // autocast as Font
size: 14,
family: "sans-serif"
}
}
});
sketchGraphicsLayer.add(graphic);
}
});
});
</script>
</head>
<body>
<div id="mapViewDiv">
</div>
<div id="sketchToolsDiv">
<button class="action-button esri-icon-polyline" id="polylineButton" type="button"
title="量距离"></button>
<button class="action-button esri-icon-polygon" id="polygonButton" type="button"
title="量面积"></button>
<button class="action-button esri-icon-trash" id="resetBtn" type="button" title="清除"></button>
</div>
</body>
</html>


运行的效果如下:



写到这里好像跟标题没什么关系,有点标题党了!

PS:上图中的位置是以前经常散步的区域,一直也不知道到底有多长,只知道走一个小时就撤了,现在大概知道了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ArcGIS API for Javascript4.6