正文
首先自定义个工具栏,包括测量距离与测量面积的工具以及地图漫游。
图标的话是用的iconfont。我是把这个工具单独写在一个组件里面,这个组件里面里面会用到一些操作地图的方法,我在map这个组件里面把需要用到的方法放在一个对象里面通过prop传到子组件,并且地图这个对象我把他放在了vue的原型链上。Vue.prototype.$map = map;
下面是ma组件的代码
<template>
<div class="wrapper">
<div ref="map" class="map">
<MapTools :MapToolsObject="MapToolsObject" class="map-tools"></MapTools>
</div>
</div>
</template>
<script>
import Vue from "vue";
import esriLoader from "esri-loader";
import MapTools from "./MapTools/index.vue";
export default {
name: "map",
components: { MapTools },
props: {},
data() {
return {
MapToolsObject: {}
};
},
created() {},
mounted() {
const options = { url: "https://js.arcgis.com/3.27/" };
esriLoader
.loadModules(
[
"esri/map",
"esri/toolbars/draw",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/Color",
"esri/SpatialReference",
"esri/geometry/Point",
'esri/graphic',
'esri/geometry/geodesicUtils',
'esri/units',
'esri/symbols/TextSymbol',
'esri/symbols/Font',
'esri/layers/GraphicsLayer',
],
options
)
.then(
([
Map,
Draw,
SimpleMarkerSymbol,
SimpleLineSymbol,
SimpleFillSymbol,
Color,
SpatialReference,
Point,
Graphic,
geodesicUtils,
units,
TextSymbol,
Font,
GraphicsLayer
]) => {
let map = new Map(this.$refs.map, {
backgroundColor: "#eee",
basemap: "streets",
logo: false,
slider: false,
zoom: 7,
minZoom: 7
});
Vue.prototype.$map = map;
//新建一个图层存放symbol
let symbolLayert = new GraphicsLayer()
this.$map.addLayer(symbolLayert)
this.MapToolsObject = {
SpatialReference,
SimpleMarkerSymbol,
SimpleLineSymbol,
SimpleFillSymbol,
Color,
Draw,
Point,
Graphic,
geodesicUtils,
units,
TextSymbol,
Font,
GraphicsLayer,
symbolLayert
};
}
);
},
computed: {},
methods: {}
};
</script>
<style scoped lang='less'>
@import url('https://js.arcgis.com/3.27/esri/css/esri.css');
.wrapper {
width: 100%;
height: 100%;
position: relative;
.map {
width: 100%;
height: 100vh;
position: relative;
}
}
</style>
复制代码
在这里面我们需要定义一个GraphicsLayer用来存储待会儿我们绘制的graphic.
let symbolLayert = new GraphicsLayer()
接下来的话是map-tool组件的代码
<template>
<div class="map-tools">
<div
class="map-toole__btn"
title="测量距离"
@click="measureDistance('distance')"
:class="activeBtn === 'distance' ? 'isSelectBtn' : ''"
>
<i class="iconfont icon-juli"></i>
</div>
<div
class="map-toole__btn"
title="测量面积"
@click="measureArea('area')"
:class="activeBtn === 'area' ? 'isSelectBtn' : ''"
>
<i class="iconfont icon-mianji"></i>
</div>
<div class="map-toole__btn" title="清空图斑" @click="clearGraphics">
<i class="iconfont icon-qingchu-copy"></i>
</div>
<div
class="map-toole__btn"
title="漫游"
@click="mapRoam('roam')"
:class="activeBtn === 'roam' ? 'isSelectBtn' : ''"
>
<i class="iconfont icon-shou"></i>
</div>
</div>
</template>
<script>
import {
getMarkerSymbolStyle,
getLineSymbolStyle,
getFillSymbolStyle,
getTextSymbolStyle,
getLength,
getArea,
getCenterPoint
} from "../js/map.utils";
export default {
name: "MapTools",
components: {},
props: {
MapToolsObject: {
type: Object,
default: null
}
},
data() {
return {
activeBtn: "",
isFullScreen: false,
isLoadShp: false,
isLoadGraphic: false,
drawToolbar: null
};
},
created() {},
mounted() {},
computed: {
SpatialReference() {
let { SpatialReference } = this.MapToolsObject;
return SpatialReference;
},
Point() {
let { Point } = this.MapToolsObject;
return Point;
},
Draw() {
let { Draw } = this.MapToolsObject;
return Draw;
},
symbolLayert() {
let { symbolLayert } = this.MapToolsObject;
return symbolLayert;
},
Graphic() {
let { Graphic } = this.MapToolsObject;
return Graphic;
},
Navigation() {
let { Navigation } = this.MapToolsObject;
return Navigation;
},
SimpleFillSymbol() {
let { SimpleFillSymbol } = this.MapToolsObject;
return SimpleFillSymbol;
}
},
methods: {
controlSelection(val) {
this.activeBtn = val
},
//地图漫游
mapRoam(val) {
this.controlSelection(val);
this.drawToolbar.deactivate();
},
//测量距离
measureDistance(val) {
if (this.drawToolbar) this.drawToolbar.deactivate();
this.controlSelection(val);
this.drawUtils();
this.drawToolbar.activate(this.Draw.LINE);
},
//测量面积
measureArea(val) {
if (this.drawToolbar) this.drawToolbar.deactivate();
this.controlSelection(val);
this.drawUtils();
this.drawToolbar.activate(this.Draw.POLYGON);
},
//初始化画图工具
drawUtils() {
this.drawToolbar = new this.Draw(this.$map);
this.drawToolbar.on("draw-complete", this.addGraphic);
},
//清空图层
clearGraphics() {
this.symbolLayert.clear();
},
addGraphic(evt) {
if (evt.geometry.type === "point" || evt.geometry.type === "multipoint") {
// let graphicSymbol = this.drawPoint(evt)
} else if (
evt.geometry.type === "line" ||
evt.geometry.type === "polyline"
) {
this.addPointGraphic(evt);
} else {
this.addAreaGraphic(evt);
}
},
//标注线段
addPointGraphic(evt) {
let graphicSymbol = this.drawLine(evt),
length = getLength(evt.geometry, this.MapToolsObject)[0],
lengthSymbol = getTextSymbolStyle(this.MapToolsObject);
if (length < 3000) {
lengthSymbol.setText("长度为:" + length.toFixed(2) + "米");
} else {
lengthSymbol.setText(
"长度为:" + parseFloat(length / 1000).toFixed(2) + "千米"
);
}
let graphicText = this.drawText(evt, lengthSymbol);
this.symbolLayert.add(graphicSymbol);
this.symbolLayert.add(graphicText);
},
//标注面积
addAreaGraphic(evt) {
let graphicSymbol = this.drawArea(evt),
area = getArea(evt.geometry, this.MapToolsObject)[0].toFixed(2),
areaSymbol = getTextSymbolStyle(this.MapToolsObject);
areaSymbol.setText("面积为:" + area + "平方公里");
let graphicText = this.drawText(evt, areaSymbol);
this.symbolLayert.add(graphicSymbol);
this.symbolLayert.add(graphicText);
},
//绘制点
drawPoint(evt) {
let symbol = getMarkerSymbolStyle(this.MapToolsObject);
return new this.Graphic(evt.geometry, symbol);
},
//绘制线段
drawLine(evt) {
let symbol = getLineSymbolStyle(this.MapToolsObject);
return new this.Graphic(evt.geometry, symbol);
},
//绘制面积
drawArea(evt) {
let symbol = getFillSymbolStyle(this.MapToolsObject, [64, 169, 255, 0.4]);
return new this.Graphic(evt.geometry, symbol, {
name: "勾绘图斑"
});
},
//绘制文字
drawText(evt, symbol) {
let centerPoint = getCenterPoint(evt.geometry);
return new this.Graphic(centerPoint, symbol);
}
}
};
</script>
<style lang='less' scoped>
.map-tools {
display: inline-block;
position: absolute;
top: 10px;
right: 10px;
z-index: 33;
display: flex;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.15);
.interval-symbol {
color: #dcdee2;
font-size: 20px;
background: white;
padding: 0 2px;
line-height: 38px;
}
.map-toole__btn {
width: 38px;
height: 38px;
display: inline-block;
background-color: white;
line-height: 38px;
text-align: center;
cursor: pointer;
&:hover {
color: #303030;
background-color: #eee;
}
.iconfont {
font-size: 20px;
vertical-align: middle;
}
}
}
</style>
复制代码
这里面主要的操作逻辑就是用户点击测量按钮之后,会初始化地图的绘制工具
this.drawToolbar = new this.Draw(this.$map);
this.drawToolbar.on("draw-complete", this.addGraphic);
复制代码
然后通过激活不同类型的绘制工具来绘制图斑,
this.drawToolbar.activate(this.Draw.POLYGON);绘制多边形
this.drawToolbar.activate(this.Draw.LINE);绘制线条
复制代码
绘制完成之后会有一个回调函数this.addGraphic
,回调函数的参数就是我们刚才绘制的图形, 拿到返回的参数之后,我们再创建一个graphic,然后把graphic添加到我们最初创建的symbolLayert图层上面就OK了。 创建graphic的方法就是new this.Graphic(evt.geometry, symbol);
this.Graphic其实就是我们在computed里面计算的属性,也就是通过map传过来的MapToolsObject对象里面的方法,因为很多函数里面都会用到这个对象里面的属性,所以我直接把他们写在了计算属性里面,当然你也可以不写在计算属性里面,在每一个函数里面去拿也是可以的。类似这样let { SpatialReference } = this.MapToolsObject;
上面有两个参数 evt.geometry, symbol
, evt
的话就是我们绘制完图形时候回调函数返回的参数,而symbol
的话是需要我们自己去创建,根据你绘制的不同类型的图斑你需要去创建不同的symbol,创建的方法我是写在map.utils.js的文件里面的,里面也包含了一些其他的方法。下面是这个文件的代码
//设置点的填充样式
let getMarkerSymbolStyle = MapToolsObject => {
let { SimpleMarkerSymbol, Color } = MapToolsObject
let markerSymbol = new SimpleMarkerSymbol()
markerSymbol.setColor(new Color('#ff7a45'))
markerSymbol.setOutline(getLineSymbolStyle(MapToolsObject))
return markerSymbol
}
//设置线的填充样式
let getLineSymbolStyle = MapToolsObject => {
let { SimpleLineSymbol, Color } = MapToolsObject
let lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color('#ff7a45'), 5)
return lineSymbol
}
//设置面的填充样式
let getFillSymbolStyle = (MapToolsObject, color) => {
color = color || [235, 77, 75, 0.4]
let { SimpleFillSymbol, SimpleLineSymbol, Color } = MapToolsObject
let fillSymbol = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_DASH, new Color([255, 255, 255]), 3),
new Color(color)
)
return fillSymbol
}
//设置文本的填充样式
let getTextSymbolStyle = MapToolsObject => {
let { TextSymbol, Font, Color } = MapToolsObject
let textSymbol = new TextSymbol().setColor(new Color('#17233d')).setFont(new Font('18px').setWeight(Font.WEIGHT_BOLD))
return textSymbol
}
//获取长度
let getLength = (polyline, MapToolsObject) => {
let { geodesicUtils, units } = MapToolsObject
return geodesicUtils.geodesicLengths([polyline], units.METERS)
}
//获取面积
let getArea = (polygon, MapToolsObject) => {
let { geodesicUtils, units } = MapToolsObject
return geodesicUtils.geodesicAreas([polygon], units.SQUARE_KILOMETERS)
}
//获取中心点坐标
let getCenterPoint = polyline => {
return polyline.getExtent().getCenter()
}
export {
getMarkerSymbolStyle,
getLineSymbolStyle,
getFillSymbolStyle,
getTextSymbolStyle,
getLength,
getArea,
getCenterPoint
}
复制代码
这里面的话主要就是一些设置样式和计算图斑面积和长度的一些方法。