当前位置: 首页 > news >正文

高德地图2.0 绘制、编辑多边形覆盖物(电子围栏)

在这里插入图片描述

1. 安装

npm i @amap/amap-jsapi-loader --save

移步:官方文档

2. map组件封装

<script lang="ts" setup>
import AMapLoader from '@amap/amap-jsapi-loader'
import { onMounted, ref } from 'vue'
import { propTypes } from '@/utils/propTypes'defineOptions({ name: 'Map' })const props = defineProps({bindId: propTypes.string.def('mapContainer'),modelValue: propTypes.array.def([]),title: propTypes.string.def(''),width: propTypes.string.def('100%'),height: propTypes.string.def('600px'),polygonPaths: propTypes.array.def([]), // 回显多边形路径 得是<nubmer[]>类型,不然无法编辑districtCode: propTypes.string.def('140101') // 行政区划代码
})watch(() => props.districtCode,(newVal, oldVal) => {if (newVal !== oldVal) {drawBounds()}}
)window._AMapSecurityConfig = {securityJsCode: '4e6ca573a89ac3176f29813d3fcc895e'
}
const mouseTool = ref()
const mapRef = ref(null)
const overlays = ref<object[]>([])
const polyEditor = ref<any>()
const district = ref<any>()
const AMapObj = ref<any>()// 新建
const createPolygon = () => {polyEditor.value.close()polyEditor.value.setTarget()polyEditor.value.open()
}const emits = defineEmits(['update:modelValue'])
//获取
const getPolygon = () => {let overlays = mapRef.value?.getAllOverlays('polygon')let polygonPaths = overlays.map((overlay: any) => overlay.getPath())polygonPaths.shift() // 去掉第一个多边形console.log('🚀 ~ getPolygon ~ polygonPaths:', polygonPaths)const paths: object[] = []polygonPaths.forEach((item: any) => {const pathItem = item.map((cItem: any) => {const lnglat = `${cItem.lng},${cItem.lat}`return lnglat})paths.push(pathItem)})emits('update:modelValue', paths)
}defineExpose({ getPolygon })//清除绘制的多边形
const clearPolygon = () => {try {closeEditor()mapRef.value?.clearMap()drawBounds()} catch (e) {console.log(e)}
}// 开启编辑
const openEditor = () => {if (polyEditor.value) {polyEditor.value.open()}
}// 关闭编辑
const closeEditor = () => {if (polyEditor.value) {polyEditor.value.close()}
}//加载行政区划插件
const drawBounds = () => {if (!district.value) {//实例化DistrictSearchvar opts = {subdistrict: 0, //获取边界不需要返回下级行政区extensions: 'all', //返回行政区边界坐标组等具体信息level: 'district' //查询行政级别为 市}district.value = new AMap.DistrictSearch(opts)}//行政区查询district.value.setLevel('district')var keyword = props.districtCodeif (keyword === '') {console.warn('行政区划不能为空')return}let polygon = nulldistrict.value.search(keyword, function (status, result) {if (polygon) {mapRef.value?.remove(polygon) //清除上次结果polygon = null}if (!result || !result.districtList || !result.districtList[0]) {console.warn('请正确填写名称或更新其他名称')return}var bounds = result.districtList[0].boundariesif (bounds) {//生成行政区划polygonfor (var i = 0; i < bounds.length; i += 1) {//构造MultiPolygon的pathbounds[i] = [bounds[i]]}polygon = new AMap.Polygon({path: bounds,strokeColor: '#F56C6C',strokeWeight: 4,fillOpacity: 0.1,fillColor: '#F56C6C',strokeStyle: 'dashed',strokeDasharray: [12, 3],zIndex: 0})mapRef.value?.add(polygon)mapRef.value?.setFitView(polygon) //视口自适应}})
}// 编辑事件处理
const editPolygon = () => {polyEditor.value.on('add', function (data) {var polygon = data.targetpolyEditor.value.addAdsorbPolygons(polygon)polygon.on('dblclick', (e) => {polyEditor.value.setTarget(polygon)polyEditor.value.open()})})// polyEditor.value.on('adjust', function (data) {//   console.log('🚀 ~ polyEditor-adjust', data)// })// polyEditor.value.on('addnode', function (data) {//   console.log('🚀 ~ polyEditor-addnode', data)// })// polyEditor.value.on('end', function (data) {//   console.log('🚀 ~ polyEditor-end', data)// })
}// 回显多边形
const showPolygon = (polygonArr: any) => {// const polygonArr = [[116.368904, 39.913423], [116.382122, 39.901176],[116.387271, 39.912501],[116.398258, 39.9046]]const polygon = new AMap.Polygon({path: polygonArr,strokeColor: '#1791fc',strokeOpacity: 0.9,strokeWeight: 4,fillColor: '#1791fc',fillOpacity: 0.3,strokeStyle: 'solid', //solid, 线样式还支持 'dashed',strokeDasharray: [12, 4], // strokeStyle是dashed时有效zIndex: 16})// polygon.on('click', (e) => {//   console.log('🚀 ~ polygon.on ~ e:', e)// })mapRef.value?.add(polygon)polyEditor.value.addAdsorbPolygons([polygon])polygon.on('dblclick', () => {polyEditor.value.setTarget(polygon)polyEditor.value.open()})mapRef.value?.setFitView(polygon) //视口自适应
}// defineExpose({ showPolygon })// 加载高德地图
const loader = () => {AMapLoader.load({key: '947ec8e0b6869f9ef9fc6badda641a06',version: '2.0', // 使用合适的版本plugins: ['AMap.Scale', 'AMap.MouseTool', 'AMap.PolygonEditor', 'AMap.DistrictSearch']}).then((AMap) => {AMapObj.value = AMap// 初始化地图mapRef.value = new AMap.Map(props.bindId, {zoom: 15,center: [116.397428, 39.90923] // 设置地图中心点})// 加载行政区划插件drawBounds()// 编辑事件处理polyEditor.value = new AMap.PolygonEditor(mapRef.value)editPolygon()// 回显保存的多边形props.polygonPaths.forEach((item: any) => {showPolygon(item)})mapRef.value?.on('click', (e) => {console.log('🚀 ~ mapRef.value.on ~ e:', e)})}).catch((error) => {console.error('加载高德地图失败', error)})
}onMounted(() => {loader()
})
</script><template><div class="mb-14px"><el-button @click="createPolygon" type="primary">新建</el-button><!-- <el-button @click="openEditor" type="primary">编辑</el-button> --><el-button @click="closeEditor" type="primary">关闭编辑</el-button><el-button @click="clearPolygon" type="danger" plain>清空</el-button><!-- <el-button @click="getPolygon" type="primary">获取</el-button> --></div><div :id="props.bindId" :style="{ width: width, height: height }"></div>
</template>

3. 使用组件

<template><el-drawer v-model="drawer2" :direction="direction" size="75%" :show-close="false"><template #header><div><divclass="w-full flex items-center justify-between border-b border-b-[var(--el-border-color)] border-b-solid pb14px"><div class="font-size-4">服务区域</div><el-button type="primary" @click="close" size="small" circle><Icon icon="ep:close-bold" :size="16" @click="cancelClick" /></el-button></div></div></template><template #default><div class="flex items-center justify-center pb30px font-size-15px color-#666">起始地: {{ curRow.startDistrictName }}<el-icon class="mx-20px"><Switch /></el-icon>目的地: {{ curRow.endDistrictName }}</div><div class="flex justify-center"><div class="mx-10px w-50%"><div><MapbindId="startMap"v-model:modelValue="startPolygonPaths"v-if="drawer2"ref="StartMapRef":polygonPaths="startDetailPaths":districtCode="curRow.startDistrictCode"/></div></div><div class="mx-10px w-50%"><div><MapbindId="endMap"v-model:modelValue="endPolygonPaths"v-if="drawer2"ref="EndMapRef":polygonPaths="endDetailPaths":districtCode="curRow.endDistrictCode"/></div></div></div></template><template #footer><div style="flex: auto"><el-button @click="cancelClick">取消</el-button><el-button type="primary" @click="confirmClick">确认</el-button></div></template></el-drawer>
</template><script lang="ts" setup>
import { Switch } from '@element-plus/icons-vue'
import { ref, nextTick } from 'vue'
import { Map } from '@/components/Map/index'
import { getLinesServiceAreaList, saveLinesServiceArea } from '@/api/routeManage/routeList/index.ts'
const drawer2 = ref(false)
const direction = ref('rtl')
const curRow = ref<object>({})
const dcistrictCode = ref('')
const startPolygonPaths = ref([])
const endPolygonPaths = ref([])
const startDetailPaths = ref([])
const endDetailPaths = ref([])
const message = useMessage()// 打开推窗
const open = async (row) => {curRow.value = rowawait getDetail()drawer2.value = true
}
defineExpose({ open })const StartMapRef = ref(null)
const EndMapRef = ref(null)
const getDetail = async () => {const params = {...}try {const data = await getLinesServiceAreaList(params)...startDetailPaths.value =[[112.557711,37.731122],[112.625256,37.734871],[112.558896,37.680496],[112.558896,37.680496]]endDetailPaths.value = [[112.676067,36.378644],[112.79624,36.385946],[112.732752,36.29097],[112.732752,36.29097]]} finally {}
}// 获取起点数据
const getStartData = () => {const linesServiceAreaList = startPolygonPaths.value.map((item) => {if (item) {return { areaType: 1, pointList: item }}})return linesServiceAreaList || []
}// 获取终点数据
const getEndData = () => {const linesServiceAreaList = endPolygonPaths.value.map((item) => {if (item) {return { areaType: 1, pointList: item }}})return linesServiceAreaList || []
}const confirmClick = async () => {await StartMapRef.value?.getPolygon()await EndMapRef.value?.getPolygon()const params = {areaList: [...getStartData(), ...getEndData()]}try {await saveLinesServiceArea(params)message.success('保存成功')} finally {drawer2.value = false}
}function cancelClick() {drawer2.value = false
}
</script>

相关文章:

高德地图2.0 绘制、编辑多边形覆盖物(电子围栏)

1. 安装 npm i amap/amap-jsapi-loader --save移步&#xff1a;官方文档 2. map组件封装 <script lang"ts" setup> import AMapLoader from amap/amap-jsapi-loader import { onMounted, ref } from vue import { propTypes } from /utils/propTypesdefineO…...

MySQL底层为什么选择用B+树作为索引

首先&#xff0c;我们来想想为什么这么多数据结构&#xff0c;为什么要用树这种数据结构&#xff1f; 众多的数据结构在逻辑层面可分为&#xff1a;线性结构 和 非线性结构。 线性结构有&#xff1a;数组、链表&#xff0c;基于它们衍生出的有哈希表&#xff08;哈希表也称散…...

MATLAB系列05:自定义函数

MATLAB系列05&#xff1a;自定义函数 5. 自定义函数5.1 MATLAB函数简介5.2 在MATLAB中传递变量&#xff1a;按值传递机制5.3 选择性参数5.4 用全局内存分享数据5.5 在函数两次调用之间本地数据的存储5.6 函数的函数(function functions)5.7 子函数和私有函数5.8 总结 5. 自定义…...

C++速通LeetCode简单第20题-多数元素

方法一&#xff1a;暴力解法&#xff0c;放multiset中排序&#xff0c;然后依次count统计&#xff0c;不满足条件的值erase清除。 class Solution { public:int majorityElement(vector<int>& nums) {int ans 0;multiset<int> s;for(int i 0;i < nums.s…...

回收站永久删除的文件还能恢复吗?教你恢复技巧

在数字时代&#xff0c;电脑是我们工作、学习和娱乐的重要工具。然而&#xff0c;随着我们对电脑的频繁使用&#xff0c;误删文件的情况也时有发生。当我们在回收站中不小心永久删除了某个重要文件时&#xff0c;内心可能会充满焦虑和疑惑&#xff1a;这些文件还能恢复吗&#…...

Python Web 微服务架构全面解析与实战指南

Python Web 微服务架构全面解析与实战指南 目录 &#x1f3d7;️ 微服务基础概念 微服务架构与单体架构的对比微服务的优点与挑战 &#x1f504; 服务间通信 使用REST、gRPC或消息队列实现服务通信API网关的使用&#xff08;如Kong、Traefik&#xff09; &#x1f50d; 服务…...

SEAFARING靶场漏洞攻略

寻找漏洞 一&#xff0c;我们打开页面 第一个漏洞 xss漏洞 1.在登录页面显示有弹窗 第二个漏洞 sql注入漏洞 1.在输入框的地方输入-1 union select 1,2,3#我们来查看他的回显点 2.查看数据库表名 -1 union select 1,database(),3# 3.查看表名 -1 union select 1,2,group…...

ROS 编程入门的介绍

2.1 创建 ROS 功能包 ROS&#xff08;Robot Operating System&#xff09;是一种开源的机器人软件框架&#xff0c;广泛用于机器人开发中。通过使用 ROS&#xff0c;开发者可以轻松创建和管理机器人应用程序。在本节中&#xff0c;我们将介绍如何创建一个 ROS 功能包并实现一些…...

第十一章 抽象类与接口

一、抽象类和抽象方法 抽象类&#xff1a;使用abstract修饰的类 抽象方法&#xff1a;在类中没有方法体的方法&#xff0c;称为抽象方法&#xff0c;抽象方法用abstract修饰 抽象类中可以没有抽象方法&#xff0c;包含抽象方法的类必是抽象类 如果子类没有实现父类中的全部…...

请问企业的八大金刚系统是哪些?有什么共同点和区别?

我的理解的八大金刚包括&#xff1a;MES、ERP、WMS、OMS、CRM、SCM、SRM、PLM。 这些系统的主要功能及运用领域是哪些方面?他们互相之前有什么区别&#xff1f;选择时哪些是企业可能根据自身需求选择的必选项目或可选项目&#xff1f; 由于某些系统的必选性取决于企业的具体业…...

【入门】配置 Java 应用程序的完整指南

前言&#xff1a; Java 是一种广泛使用的编程语言&#xff0c;具备跨平台的特性&#xff0c;使得其应用程序可以在多种环境中高效运行。本文将介绍如何将 Java 应用程序从开发环境部署到生产环境&#xff0c;确保其能够稳定、稳定地运行运行。 确定运行环境 Java程序可以运行…...

flutter widget 设置GestureDetector点击无效

有可能是被上层的widget挡住了&#xff0c;虽然你看得到这个widget&#xff0c;但是操作不到。使用相对布局Stack要特别注意&#xff0c;这种布局会和Android一样&#xff0c;先写的布局放在下层&#xff0c;后写的&#xff0c;如果范围较大的话&#xff0c;会盖在之前的widget…...

基于SpringBoot的在线教育平台的设计与实现

文未可获取一份本项目的java源码和数据库参考。 选题的背景与意义&#xff1a; 随着互联网时代信息技术的不断发展&#xff0c;线下已经产生了很多IT技术的培训机构&#xff0c;但是价格却十分昂贵并且需要人们持续不断的去具体培训地点学习&#xff0c;因此更需要一个课程优…...

Django_Vue3_ElementUI_Release_004_使用nginx部署

1. nginx安装配置 1.1 下载nginx Download nginx 1.2 测试一下 1.3 进入nginx用命令操作 2. 部署 2.1 前端部署 2.1.1 修改nginx监听配置 …conf/nginx.conf http {... # 这里不进行修改server {listen 8010; # 监听 80 端口server_name 192.168.10.24; # 输入服务器 ip…...

Java抽象类的案例

抽象类的特点总结 不能实例化&#xff1a;抽象类不能直接创建实例。它只能被继承。即&#xff0c;你不能用 new 关键字创建抽象类的对象。 可以包含抽象方法&#xff1a;抽象类可以包含一个或多个抽象方法&#xff08;没有方法体&#xff09;&#xff0c;这些方法必须在子类中…...

运维工程师面试整理-数据库

在运维工程师的面试中,数据库管理和优化是一个非常重要的环节。面试官可能会通过数据库相关的问题来评估你在数据库部署、管理、备份、性能优化以及故障排除方面的能力。以下是关于数据库部分的详细内容,帮助你更好地准备面试。 1. 数据库基础 ● 常见数据库类型 ○ 关系型数…...

comfyui一键抠图工作流:让你告别PS!

前言 本文涉及的工作流和插件&#xff0c;需要的朋友请扫描免费获取哦~ 在当今的数字时代&#xff0c;图像处理已经成为许多行业的日常需求。无论是电商产品展示、广告设计&#xff0c;还是个人照片编辑&#xff0c;去除背景都是一个常见且重要的步骤。 然而&#xff0c;使用…...

【Hot100】LeetCode—4. 寻找两个正序数组的中位数

目录 1- 思路题目识别二分 2- 实现⭐4. 寻找两个正序数组的中位数——题解思路 3- ACM 实现 原题链接&#xff1a;4. 寻找两个正序数组的中位数 1- 思路 题目识别 识别1 &#xff1a;给定两个数组 nums1 和 nums2 &#xff0c;找出数组的中位数 二分 思路 将寻找中位数 —…...

【LLM text2sql】浅看大模型用于text2sql的综述

前言 之前笔者分享了text2sql & LLM & KG的有机结合实现KBQA的问答&#xff0c; 《【LLM & RAG & text2sql】大模型在知识图谱问答上的核心算法详细思路及实践》、 《【开源分享】KBQA核心技术及结合大模型SPARQL查询生成问答实践》。 我们再来看看大模型在te…...

Node js介绍

目录 概要**对Node的认识****Node的概念理解****Node和浏览器区别****Node的架构图** **Node的应用场景****Node的安装****安装Node的LTS版本****Node的版本管理工具nvm(了解)** **Node的输入和输出**Node程序传递参数Node的输出 **Node的全局对象****特殊的全局对象****其他的…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...