腾讯地图在弹框中绘制电子围栏 vue3+elementPlus
参考腾讯地图官方示例:https://lbs.qq.com/webDemoCenter/glAPI/glEditor/toolDraw
https://lbs.qq.com/webApi/javascriptGL/glGuide/glGeometry
父组件中通过点击按钮打开弹框,配置相关表单信息及地图选点、围栏绘制
父组件
<el-button type="primary" plain @click="openForm('create')">
新增
</el-button>
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
子组件弹框
<Dialog v-model="dialogVisible" :title="dialogTitle" width="940">
<el-row>
<el-col :span="8">
<el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="110px">
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入" />
</el-form-item>
</el-form>
</el-col>
<el-col :span="15" :offset="1">
<!-- 地图渲染的容器 -->
<div id="container" ref="mapbox"></div>
<!-- 地图编辑的控件 -->
<div id="toolControl">
<div class="toolItem active" id="marker" title="点标记"></div>
<div class="toolItem" id="polygon" title="多边形"></div>
<div class="toolItem" id="circle" title="圆形"></div>
<div class="toolItem" id="rectangle" title="矩形"></div>
<div class="toolItem" id="ellipse" title="椭圆"></div>
</div>
<div class="btn-operation">
<el-radio-group v-model="editorStatus" @change="editorStatusChange">
<el-radio label="draw" value="draw">绘制状态</el-radio>
<el-radio label="edit" value="edit">编辑状态</el-radio>
</el-radio-group>
<el-button type="primary" plain id="delete" size="small" @click="editor.delete()" v-show="isShowDelete">删除</el-button>
</div>
<div class="tip custom-block" v-if="!isShowDelete">
<p>绘制:鼠标左键点击及移动即可绘制图形</p>
<p>结束绘制:鼠标左键双击即可结束绘制折线、多边形会自动闭合;圆形、矩形、椭圆单击即可结束</p>
<p>中断:绘制过程中按下esc键可中断该过程</p>
</div>
<div class="tip custom-block" v-else>
<p>编辑:鼠标单击选中驻点或围栏进入编辑状态</p>
<p>结束编辑:点击绘制状态即可结束</p>
<p>删除:选中驻点或围栏后点击删除按钮,即可进行删除</p>
</div>
</el-col>
</el-row>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
<el-button @click="handleOff">取 消</el-button>
</template>
</Dialog>
在子组件中定义open打开弹窗的方法。
注意
:因为Dialog弹窗组件不打开时不会加载dom结构,此处必须等地图渲染的容器container加载出来后再进行地图初始化。所以地图的初始化不能放在onMounted生命周期中进行,因为在onMounted中无法获取到容器container
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
// 切换激活图层
document.getElementById('toolControl').addEventListener('click', (e) => {
var id = e.target.id;
if (id !== 'toolControl') {
document.getElementById(activeType).className = 'toolItem';
document.getElementById(id).className = 'toolItem active';
activeType = id;
editor.setActiveOverlay(id);
}
});
setTimeout(()=>{
// 初始化地图
initMap();
}, 10)
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
重点在于地图的初始化
/* 地图初始化 */
const initMap = async () => {
// 定义地图中心点坐标
center.value = new TMap.LatLng(34.762115, 113.681975)
// 1-定义map变量,调用 TMap.Map() 构造函数创建地图
map = new TMap.Map(document.getElementById('container'), {
center: center.value,//设置地图中心点坐标
zoom: 14, //设置地图缩放级别
});
// 2-初始化几何图形及编辑器
marker = new TMap.MultiMarker({
map: map
});
polygon = new TMap.MultiPolygon({
map: map,
styles: {
// 定义编辑状态下选中的样式
highlight: new TMap.PolygonStyle({
color: 'rgba(255, 255, 0, 0.6)'
})
}
});
circle = new TMap.MultiCircle({
map: map,
styles: {
highlight: new TMap.CircleStyle({
color: 'rgba(255, 255, 0, 0.6)'
})
}
});
rectangle = new TMap.MultiRectangle({
map: map,
styles: {
highlight: new TMap.RectangleStyle({
color: 'rgba(255, 255, 0, 0.6)'
})
}
});
ellipse = new TMap.MultiEllipse({
map: map,
styles: {
highlight: new TMap.EllipseStyle({
color: 'rgba(255, 255, 0, 0.6)'
})
}
});
editor = new TMap.tools.GeometryEditor({
map: map, // 编辑器绑定的地图对象
// 可编辑的图层
overlayList: [
{
overlay: marker,
id: 'marker',
},
{
overlay: polygon,
id: 'polygon',
selectedStyleId: 'highlight',
},
{
overlay: circle,
id: 'circle',
selectedStyleId: 'highlight'
},
{
overlay: rectangle,
id: 'rectangle',
selectedStyleId: 'highlight'
},
{
overlay: ellipse,
id: 'ellipse',
selectedStyleId: 'highlight'
},
],
actionMode: TMap.tools.constants.EDITOR_ACTION.DRAW, // 编辑器的工作模式 DRAW INTERACT
activeOverlayId: 'marker', // 激活图层
snappable: true, // 开启吸附
selectable: true,// 开启点选功能
});
// 监听绘制结束事件,获取绘制几何图形
editor.on('draw_complete', (geometry) => {
var id = geometry.id;
if (editor.getActiveOverlay().id === 'marker') {
// 获取标记坐标
var geo = marker.geometries.filter(function (item) {
return item.id === id;
});
marker.setGeometries([]); // 清空标记点
// 更新标记点
marker.updateGeometries({
id: 'marker',
position: geo[0].position
});
}
});
// 监听编辑事件
editor.on('adjust_complete', evtResult => {});
// 监听删除事件
editor.on('delete_complete', evtResult => {
if (evtResult[0].id == "marker") {}
});
}
/* 单选按钮组改变 切换绘制和编辑状态 */
const editorStatusChange = (val)=>{
if(val == 'draw'){
// 绘制状态
editor.setActionMode(2);
isShowDelete.value = false;
}else{
// 编辑状态
editor.setActionMode(1);
isShowDelete.value = true;
}
}
/* 绘制围栏 */
const drawFence = () => {
editor.setActionMode(2)
}
/* 编辑围栏 */
const editFence = () => {
editor.setActionMode(1)
}
获取标记点及围栏的数据
判断点是否在围栏中
提交表单时需要根据需求对围栏数据或标记点进行相应处理
/* 创建时驻点及围栏数据处理 */
const submitPoint = () => {
// let resList = editor.getOverlayList();
// 标记点数据处理
let mRes = marker.getGeometries();
// 多边形数据-0
let pRes = polygon.getGeometries();
// 圆形数据处理-1
// let cRes = circle.getGeometries();
let cRes = circle.geometries;
// 矩形数据处理-2
let rectRes = rectangle.geometries;
// 椭圆数据处理-3
let eRes = ellipse.getGeometries();
// 判断驻点是否在围栏内
var is = TMap.geometry.isPointInPolygon(point: LatLng, polygon: LatLng[]);
}
css样式
#container {
/*地图(容器)显示大小*/
width: 100%;
height: 400px;
}
#toolControl {
position: absolute;
top: 40px;
left: 300px;
right: 0px;
margin: auto;
width: 252px;
z-index: 1001;
}
.toolItem {
width: 30px;
height: 30px;
float: left;
margin: 1px;
padding: 4px;
border-radius: 3px;
background-size: 30px 30px;
background-position: 4px 4px;
background-repeat: no-repeat;
box-shadow: 0 1px 2px 0 #e4e7ef;
background-color: #ffffff;
border: 1px solid #ffffff;
}
.toolItem:hover {
border-color: #789cff;
}
.active {
border-color: #d5dff2;
background-color: #d5dff2;
}
#marker {
background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/marker_editor.png');
}
#polygon {
background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/polygon.png');
}
#circle {
background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/circle.png');
}
#rectangle {
background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/rectangle.png');
}
#ellipse {
background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/ellipse.png');
}