uniapp地图电子围栏(多边形)绘制和编辑

uniapp地图电子围栏(多边形)绘制和编辑

背景

最近项目中需要在地图上进行电子围栏的绘制和编辑,这里将实现的思路给大家分享下。由于uniapp官方提供的map组件功能不全,还有在APP端(非nvue)还存在层级问题,所以这里就不考虑使用官方map组件,而是使用renderjs来实现。renderjs中如何使用地图可以参考uniapp地图开发(APP,H5)之前这一篇文章。

在开始实现之前,我们先看下效果图
请添加图片描述

实现思路

1、我们首先需要在页面展示地图底板
2、DOM中添加四个操作按钮
3、监听地图点击事件,以地图中心点和点击点为两个点生成多边形
4、实现清除、编辑、保存、确定等按钮逻辑

代码实现

其实我们写代码是要先有思路,我们的代码也是根据上面的思路来分步来实现。
接下来就直接上主逻辑页面代码(second.vue)。

<template>
	<div id='container' class="map" :style="'height:'+maph+'px'">
		<view :originPolygon="originPolygon" :change:originPolygon="renderJS.receiveOriginPolygon" />
	</div>
</template>

<script>
	export default {
		data() {
			return {
				maph: 0,
				//如果需要编辑多边形,传进来多边形字符串
				originPolygon: '',
				polygon: []
			}
		},
		onLoad(option) {
			this.maph = uni.getSystemInfoSync().windowHeight
			this.originPolygon = option.polygon || ''
		},
		methods: {
			polygonSave(result) {
				this.polygon = result
				const eventChannel = this.getOpenerEventChannel();
				eventChannel.emit('polygonResult',{
					result: JSON.stringify(this.polygon)
				})
				uni.navigateBack({
					delta: 1
				})
			}
		}
	}
</script>
<script module="renderJS" lang="renderjs">
	let map = null
	//是否编辑模式
	let isEditMode = false
	//其他页面传入的多边形,用作多边形编辑
	let originPolygon = null
	//多边形的关键点
	let path = []
	//多边形编辑器
	let polygonEditor = null
	let ownerInstance = null
	//选定并保存好的多边形
	let polygonSave = []
	//编辑还未保存的多边形
	let polygonSaveTemp = []
	let that
	export default {
		data() {
			return {

			}
		},
		mounted() {
			that = this
			window._AMapSecurityConfig = {
				securityJsCode: '高德申请的securityJsCode',
			}
			if (typeof window.AMap == 'function') {
				this.initAmap();
			} else {
				// 动态引入较大类库避免影响页面展示
				const script = document.createElement('script');
				script.src = 'https://webapi.amap.com/maps?v=2.0&key=高德申请的key';
				script.onload = this.initAmap.bind(this);
				document.head.appendChild(script);
			}
		},
		//页面卸载清空
		unmounted() {
			map.clearMap()
			map = null
			//是否编辑模式
			isEditMode = false
			//其他页面传入的多边形,用作多边形编辑
			originPolygon = null
			//多边形的关键点
			path = []
			//多边形编辑器
			polygonEditor = null
			ownerInstance = null
			//选定并保存好的多边形
			polygonSave = []
			//编辑还未保存的多边形
			polygonSaveTemp = []
			that = null
		},
		methods: {
			//获取到传进来的多边形
			receiveOriginPolygon(newValue, oldValue, ownerVm, vm) {
				if (!ownerInstance) {
					ownerInstance = ownerVm
				}
				if(!newValue){
					return
				}
				originPolygon = JSON.parse(newValue)
				isEditMode = true
			},
			initAmap(e, ownerVm) {
				map = new AMap.Map("container", {
					zoom: 12, //设置地图显示的缩放级别
					viewMode: '2D' //设置地图模式
				});
				map.on('click', (e) => {
					if (!originPolygon) {
						if (isEditMode) {
							if (path.length <= 0) {
								path.push(map.getCenter())
							}
							if (polygonEditor) {
								polygonEditor.close()
							}
							map.clearMap()
							path.push(new AMap.LngLat(e.lnglat.lng, e.lnglat.lat))
							this.drawPolygon()
						} else {
							alert('请点击编辑按钮进行绘制')
						}
					}else {
						if (polygonEditor) {
							polygonEditor.close()
						}
						map.clearMap()
						path.push(new AMap.LngLat(e.lnglat.lng, e.lnglat.lat))
						this.drawPolygon()
					}
				})
				map.on('complete', () => {
					console.log('地图加载完成')
					if (originPolygon) {
						originPolygon.forEach(ele => {
							path.push(ele)
						})
					}
					this.drawPolygon()
				})
				this.initDivs()
			},
			//画多边形
			drawPolygon() {
				if(path.length <= 0){
					return
				}
				let polygon = new AMap.Polygon({
					path: path, //路径
					fillColor: "#FF615F", //多边形填充颜色
					fillOpacity: 0.2,
					strokeStyle: 'dashed',
					strokeWeight: 2, //线条宽度,默认为 2
					strokeColor: "#FF615F", //线条颜色
				});
				//多边形 Polygon对象添加到 Map
				map.add(polygon);
				//将覆盖物调整到合适视野
				map.setFitView([polygon])
				map.plugin(["AMap.PolygonEditor"], function() {
					//实例化多边形编辑器,传入地图实例和要进行编辑的多边形实例
					polygonEditor = new AMap.PolygonEditor(map, polygon);
					//开启编辑模式
					polygonEditor.open();
					polygonEditor.on('end', (e) => {
						let polygonPaths = e.target.getPath()
						if (polygonPaths.length <= 1) {
							return
						}
						//清除了
						if (path.length <= 0) {
							polygonSaveTemp = []
							return
						}
						let paths = []
						polygonPaths.forEach(ele => {
							let temp = [ele.lng, ele.lat]
							paths.push(temp)
						})
						polygonSaveTemp = paths
					})
				});
			},
			//创建单个div
			createDiv(inner) {
				let div = document.createElement('div');
				div.style.width = '70px';
				div.style.height = '30px';
				div.style.background = '#FFFFFF';
				div.style.boxShadow = '0px 0px 3px 1px rgba(0, 0, 0, 0.1)';
				div.style.borderRadius = '10px';
				div.style.fontSize = '15px';
				div.style.lineHeight = '30px';
				div.style.textAlign = 'center';
				div.innerHTML = inner
				return div
			},
			initDivs() {
				const div = document.createElement('div');
				div.style.display = 'flex';
				div.style.flexDirection = 'row';
				div.style.width = 'calc(100% - 40px)';
				div.style.alignItems = 'center';
				div.style.height = '40px';
				div.style.justifyContent = 'space-between';
				div.style.position = 'fixed';
				div.style.bottom = '40px';
				div.style.left = '20px';
				div.style.fontSize = '30px';
				div.style.zIndex = 999
				document.body.appendChild(div);

				const clearDiv = this.createDiv('清除')
				div.appendChild(clearDiv)
				clearDiv.addEventListener('click', function() {
					path = []
					polygonSave = []
					polygonSaveTemp = []
					originPolygon = null
					if (polygonEditor) {
						polygonEditor.close()
						polygonEditor = null
					}
					if (map) {
						map.clearMap()
					}
					console.log('清除')
				});

				const editDiv = this.createDiv('编辑')
				div.appendChild(editDiv)
				editDiv.addEventListener('click', function() {
					isEditMode = true
					if (polygonEditor) {
						polygonEditor.open()
					}
					console.log('编辑')
				});

				const saveDiv = this.createDiv('保存')
				div.appendChild(saveDiv)
				saveDiv.addEventListener('click', function() {
					isEditMode = false
					if (polygonEditor) {
						polygonEditor.close()
					}
					if(polygonSaveTemp){
						polygonSave = polygonSaveTemp
					}
					setTimeout(function() {
						if (map) {
							map.setFitView()
						}
					}, 200);
					console.log('保存')
				});

				const confirmDiv = this.createDiv('确定')
				div.appendChild(confirmDiv)
				confirmDiv.addEventListener('click', function() {
					if (polygonSave && polygonSave.length > 0) {
						ownerInstance.callMethod('polygonSave', polygonSave)
					}else {
						if(polygonEditor){
							alert('请先保存多边形')
						}else {
							alert('还未绘制多边形')
						}
					}
					console.log('确定')
				});

			}
		}
	}
</script>
<style>
	.map {
		z-index: 1;
		height: 100%;
		width: 750rpx;
	}
</style>

还有一个测试页面index.vue,这个页面主要是一个按钮和点击事件,这里我就只写点击事件了。

//代码省略...
goSecond(){
	uni.navigateTo({
		url: `/pages/second/second?polygon=${this.polygon}`,
		events: {
			polygonResult: res=>{
				//回调结果,页面展示用
				this.polygon = res.result
			}
		}
	})			
}
//代码省略...

注意事项

我这里使用的是高德地图,开发这需要去高德官网申请应用的key,并填入文章中代码标识处。支持电子围栏的绘制和已有电子围栏的展示和编辑。通过高德地图API,还可以实现矩形和圆形等多种电子围栏实现。由于使用renderjs实现,只支持H5和APP,小程序不支持。

尾巴

今天的文章就到这里了,希望能给大家帮助,如果喜欢我的文章,欢迎给我点赞,评论,关注,谢谢大家!
PS:很多博主都把文章设置为关注后才能查看,感觉这样有点恶心。如果我的文章切实能给各位观众老爷们带来帮助,真心求点个关注,再次感谢各位观众老爷们了。

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值