问题记录
vue2实现高德地图 JSAPI 2.0可拖拽的路线规划(DragRoute)组件实现对每个经过点设置不同的经过点名称
官方文档及示例
DragRoute相关API
API中没有任何方法让我们对每个经过点进行设置,所以只能我们自己实现
实现效果如下:
集成DragRoute到自己的组件
- 设置变量
- 引入DragRoute组件
以上步骤完成后就集成了DragRoute组件
对每个经过点设置不同的经过点名称
_path中存储的数据如下图是一个LngLat对象,但是转换为json字符串后就是一个经纬度数组
父组件中
getRoutePath(childValue){ this.form.routePathString=JSON.stringify(childValue) },
将数据库中的数据加载到重新加载到route中
此处我将DragRoute的初始化单独抽取成了一个方法,
此时其实已经完成了目的功能
但是存储到后端后再次加载地图所有的经过点的content都是一样的效果如下:
这是因为我们的路径点的content都在初始化时都被
midMarkerOptions
设置为相同的了
解决路径点content相同问题
主要的思路是将route中的marker都重新修改content后再重新加载就可以实现了
updateMindPointContext: function () {
let pathList = this.route._list
console.log(pathList)
let startPoint = pathList[0]
let endPoint = pathList[pathList.length - 1]
let mindPoint = []
pathList.forEach(item => {
if (item.id != startPoint.id && item.id != endPoint.id) {
mindPoint.push(item)
}
})
let count = 1
mindPoint.forEach(item => {
item.marker._opts.label.content = '经过点' + count
count++
item.marker.setContent('')//需要set一下上面代码才会生效
})
pathList = []
pathList.push(startPoint)
pathList.push(...mindPoint)
pathList.push(endPoint)
this.route._list = pathList
},
然后我们在每次初始化时都调用此方法就解决了
组件代码
<template>
<div>
<a-row>
<div id="container"></div>
<div class='input-card-ControlBar' v-show="visible">
<div class="input-item">
<a-checkbox @change="toggleScale" :checked="toggleScaleCheck">比例尺</a-checkbox>
</div>
<div class="input-item">
<a-checkbox @change="toggleToolBar" :checked="toggleToolBarCheck">工具条</a-checkbox>
</div>
<div class="input-item">
<a-checkbox @change="toggleControlBar" :checked="toggleControlBarCheck">工具条方向盘</a-checkbox>
</div>
<div class="input-item">
<a-checkbox @change="toggleOverViewShow" :checked="toggleOverViewShowCheck">显示鹰眼</a-checkbox>
</div>
</div>
<div class="input-card-MouseTool" style='width: 24rem;' v-show="visible">
<div class="input-item">
左击获取经纬度: <input type="text" :value="clickValue">
</div>
<div class="input-item">
<a-radio-group v-model="drawOptionValue" :options="drawOptions" @change="onChangeDrawOption"/>
</div>
<div class="input-item" style="margin-top: 10px">
<a-button type="primary" size="small" style="width: 90px" @click="clearMap">
清除
</a-button>
<a-button type="primary" size="small" style="margin-left: 10px;width: 90px" @click="closeDram">
关闭绘图
</a-button>
</div>
</div>
</a-row>
</div>
</template>
<script>
//这里可以导入其他文件(比如: 组件, 工具 js, 第三方插件 js, json文件, 图片文件等等)
//例如: import 《组件名称》 from '《组件路径》 ';
import AMapLoader from "@amap/amap-jsapi-loader";
// 设置安全密钥
window._AMapSecurityConfig = {
securityJsCode: 'xxxx',
}
export default {
name: 'MapContainer',
//import 引入的组件需要注入到对象中才能使用
components: {},
props: {
visible: Boolean,
drewData: Array,
routePathP: Array,
},
data() {
//这里存放数据
return {
AMap: null,
//此处不声明 map 对象,可以直接使用 this.map赋值或者采用非响应式的普通对象来存储。
map: null,
mouseTool: null,
//监听draw事件可获取画好的覆盖物
overlays: [],
auto: null,
placeSearch: null,
drawOptionValue: '',
drawOptions: [
{label: '画点', value: 'marker'},
{label: '画折线', value: 'polyline'},
{label: '画多边形', value: 'polygon'},
{label: '画矩形', value: 'rectangle'},
{label: '画圆', value: 'circle'},
{label: '路径规划', value: 'routePath'},
{label: '获取经纬度', value: 'position'},
],
//--地图控件 --
toggleOverViewShowCheck: true,
toggleControlBarCheck: true,
toggleToolBarCheck: true,
toggleScaleCheck: true,
scale: null,
toolBar: null,
controlBar: null,
overView: null,
//坐击经纬度
clickValue: '',
//可拖拽路线规划
route: null,
routePath: this.routePathP,
startAndEnd:[],
};
},
//计算属性 类似于 data 概念
computed: {},
//监控 data 中的数据变化
watch: {
overlays(newVal, oldVal) {
this.$emit('getOverlaysValue', newVal)
},
drewData(newValue, oldValue) {
this.mountDrewData()
},
routePathP(newValue, oldValue){
this.routePath=this.routePathP;
this.initPathAssign(this.AMap)
},
startAndEnd(newValue, oldValue){
if (this.startAndEnd.length==2){
this.routePath=this.startAndEnd.map(item=>{
return item.getPosition()
})
console.log(this.routePath)
this.initPathAssign(this.AMap)
this.startAndEnd.forEach(item=>{
item.remove()
})
this.startAndEnd=[]
}
}
},
//方法集合
methods: {
toggleOverViewShow(e) {
this.toggleOverViewShowCheck = e.target.checked
if (e.target.checked) {
this.overView.show();
} else {
this.overView.hide();
}
},
toggleControlBar(e) {
this.toggleControlBarCheck = e.target.checked
if (e.target.checked) {
this.controlBar.show()
} else {
this.controlBar.hide()
}
},
toggleToolBar(e) {
this.toggleToolBarCheck = e.target.checked
if (e.target.checked) {
this.toolBar.show();
} else {
this.toolBar.hide();
}
},
toggleScale(e) {
this.toggleScaleCheck = e.target.checked
if (e.target.checked) {
this.scale.show();
} else {
this.scale.hide();
}
},
closeDram() {
this.mouseTool.close(true)
this.drawOptionValue = ''
},
clearMap() {
this.map.remove(this.overlays)
this.overlays = [];
this.route.destroy()
this.$emit('getRoutePath', [])
// this.$emit('getOverlaysValue', this.overlays)
},
onChangeDrawOption(e) {
console.log('radio checked', e.target.value);
this.draw(e.target.value)
},
initMapTool() {
this.scale = new AMap.Scale();
this.toolBar = new AMap.ToolBar({
position: {
top: '110px',
right: '40px'
}
});
this.controlBar = new AMap.ControlBar({
position: {
top: '10px',
right: '10px',
}
});
this.overView = new AMap.HawkEye({
position: {
top: '10px',
left: '10px',
},
opened: false
});
this.map.addControl(this.scale);
this.map.addControl(this.toolBar);
this.map.addControl(this.controlBar);
this.map.addControl(this.overView);
},
initMouseTool(AMap) {
this.mouseTool = new AMap.MouseTool(this.map);
// 监听draw事件可获取画好的覆盖物
this.mouseTool.on('draw', function (e) {
this.overlays.push(e.obj);
}.bind(this))
//为地图注册click事件获取鼠标点击出的经纬度坐标
this.map.on('click', function (e) {
if (this.drawOptionValue=='routePath'){
if (this.startAndEnd.length==0){
let start = new AMap.Marker({
icon: "//webapi.amap.com/theme/v1.3/markers/n/start.png",
position: [e.lnglat.getLng(),e.lnglat.getLat()],
offset: new AMap.Pixel(-13, -30)
});
start.setMap(this.map);
this.startAndEnd.push(start)
}else if (this.startAndEnd.length==1){
let end = new AMap.Marker({
icon: "//webapi.amap.com/theme/v1.3/markers/n/end.png",
position: [e.lnglat.getLng(),e.lnglat.getLat()],
offset: new AMap.Pixel(-13, -30)
});
end.setMap(this.map);
this.startAndEnd.push(end)
}
}
if (this.drawOptionValue=='position'){
this.clickValue = e.lnglat.getLng() + ',' + e.lnglat.getLat()
}
}.bind(this));
this.mountDrewData()
},
mountDrewData(){
if (this.drewData!=null){
this.drewData.forEach(item => {
this.drew(item.overlayType, item.opts)
})
}
},
updateMindPointContext: function () {
let pathList = this.route._list
console.log(pathList)
let startPoint = pathList[0]
let endPoint = pathList[pathList.length - 1]
let mindPoint = []
pathList.forEach(item => {
if (item.id != startPoint.id && item.id != endPoint.id) {
mindPoint.push(item)
}
})
let count = 1
mindPoint.forEach(item => {
item.marker._opts.label.content = '经过点' + count
count++
item.marker.setContent('')//需要set一下上面代码才会生效
})
pathList = []
pathList.push(startPoint)
pathList.push(...mindPoint)
pathList.push(endPoint)
this.route._list = pathList
},
initPathAssign (AMap) {
// this.routePath.push([104.050025, 30.6683]);
// this.routePath.push([104.044078, 30.671447]);
this.route = new AMap.DragRoute(this.map, this.routePath, AMap.DrivingPolicy.LEAST_FEE, {
midMarkerOptions: {
// icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-1.png',
label: {
content: '路径点'+(this.routePath.length-1)
}
}
}); //构造拖拽导航类
this.route.search(); //查询导航路径并开启拖拽导航
this.route.on('addway', function (e) {
// e.target.midMarkerOptions.icon= '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-'+(this.route.getWays().length+1)+'.png'
e.target.midMarkerOptions.label.content = '路径点' + (this.route.getWays().length + 1)
this.$emit('getRoutePath', this.route._path)
}.bind(this))
this.updateMindPointContext();
},
initMap() {
AMapLoader.load({
key: "xxxxxx", // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
"plugins": [
"AMap.Scale",
"AMap.HawkEye",
"AMap.ToolBar",
"AMap.AutoComplete",
"AMap.PlaceSearch",
"AMap.ControlBar",
"AMap.MouseTool",
"AMap.DragRoute"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
}).then((AMap) => {
this.AMap=AMap
this.map = new AMap.Map("container", { //设置地图容器id
viewMode: "2D", // 是否为3D地图模式
zoom: 13, // 初始化地图级别
center: [104.065735, 30.659462], //中心点坐标 成都
resizeEnable: true
});
this.initMouseTool(AMap);
//地图工具
this.initMapTool();
//路径规划工具初始化
this.initPathAssign(AMap);
}).catch(e => {
console.log(e);
})
},
draw(type) {
switch (type) {
case 'marker': {
this.mouseTool.marker({
//同Marker的Option设置
});
break;
}
case 'polyline': {
this.mouseTool.polyline({
strokeColor: '#80d8ff'
//同Polyline的Option设置
});
break;
}
case 'polygon': {
this.mouseTool.polygon({
fillColor: '#00b0ff',
strokeColor: '#80d8ff'
//同Polygon的Option设置
});
break;
}
case 'rectangle': {
this.mouseTool.rectangle({
fillColor: '#00b0ff',
strokeColor: '#80d8ff'
//同Polygon的Option设置
});
break;
}
case 'circle': {
this.mouseTool.circle({
fillColor: '#00b0ff',
strokeColor: '#80d8ff'
//同Circle的Option设置
});
break;
}
}
},
drew(type, opts) {
switch (type) {
case 'marker': {
opts.map = this.map
let o = new AMap.Marker(opts);
this.overlays.push(o);
break;
}
case 'polyline': {
opts.map = this.map
let o = new AMap.Polyline(opts)
this.overlays.push(o);
break;
}
case 'polygon': {
opts.map = this.map
let o = new AMap.Polygon(opts)
this.overlays.push(o);
break;
}
case 'rectangle': {
opts.map = this.map
let o = new AMap.Rectangle(opts)
this.overlays.push(o);
break;
}
case 'circle': {
opts.map = this.map
let o = new AMap.Circle(opts)
this.overlays.push(o);
break;
}
}
}
},
//生命周期 - 创建完成(可以访问当前 this 实例)
created() {
},
//生命周期 - 挂载完成(可以访问 DOM 元素)
mounted() {
this.initMap();
},
//生命周期 - 创建之前
beforeCreate() {
},
//生命周期 - 挂载之前
beforeMount() {
},
//生命周期 - 更新之前
beforeUpdate() {
},
//生命周期 - 更新之后
updated() {
},
//生命周期 - 销毁之前
beforeDestroy() {
},
//生命周期 - 销毁完成
destroyed() {
},
//如果页面有 keep-alive 缓存功能, 这个函数会触发
activated() {
},
}
</script>
<style scoped>
#container {
padding: 0px;
margin: 0px;
width: 100%;
height: 800px;
}
.input-item {
height: 2.2rem;
}
.input-card-ControlBar {
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border-radius: .25rem;
width: 10rem;
border-width: 0;
border-radius: 0.4rem;
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
position: fixed;
bottom: 12rem;
right: 2rem;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
padding: 0.75rem 1.25rem;
}
.input-card-MouseTool {
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border-radius: .25rem;
width: 10rem;
border-width: 0;
border-radius: 0.4rem;
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
position: fixed;
bottom: 12rem;
right: 12rem;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
padding: 0.75rem 1.25rem;
}
</style>
父组件使用示例代码
<template>
<Map-Container
ref="mapChild"
:visible="drawerVisible"
:drewData="drewData"
:routePathP="routePath"
@getOverlaysValue="getOverlaysValue"
@getRoutePath="getRoutePath">
</Map-Container>
</template>
<script>
import MapContainer from "@/pages/components/map/MapContainer";
export default {
name: 'Post',
components: { MapContainer},
data() {
return {
drewData: [],
form: {
overlays: '',
createBy: '',
routePathString: '',
},
routePath: [],
}
},
methods: {
getRoutePath(childValue){
this.form.routePathString=JSON.stringify(childValue)
},
getOverlaysValue: function (childValue) {
let overlaysString = []
overlaysString = childValue.map(item => {
switch (item.className) {
case 'AMap.Marker': {
item._opts.map = null
let opts = item._opts
let overlay = {
overlayType: 'marker',
opts: opts
}
return overlay
}
case 'Overlay.Polyline': {
item._opts.map = null
let opts = item._opts
let overlay = {
overlayType: 'polyline',
opts: opts
}
return overlay
}
case 'Overlay.Polygon': {
item._opts.map = null
let opts = item._opts
let overlay = {
overlayType: 'polygon',
opts: opts
}
return overlay
}
case 'Overlay.Rectangle': {
item._opts.map = null
let opts = item._opts
let overlay = {
overlayType: 'rectangle',
opts: opts
}
return overlay
}
case 'Overlay.Circle': {
item._opts.map = null
let opts = item._opts
let overlay = {
overlayType: 'circle',
opts: opts
}
return overlay
}
}
})
this.form.overlaysString = JSON.stringify(overlaysString)
},
}
}
</script>
<style lang="less" scoped>
.search {
margin-bottom: 54px;
}
.fold {
width: calc(100% - 216px);
display: inline-block
}
.operator {
margin-bottom: 18px;
}
@media screen and (max-width: 900px) {
.fold {
width: 100%;
}
}
</style>