【天地图】绘制、删除点线面

使用天地图绘制、删除点线面

  • 实现效果图
  • 地图组件完整代码
  • 使用地图组件完整代码

实现效果图

在这里插入图片描述

地图组件完整代码


// 天地图组件
<template><div class="map-container"><div id="mapCon"></div></div>
</template><script>
import markerIcon from "@/assets/images/marker-icon.png";
let handler;
export default {name: "MapEle",props: {mapData: {type: Object,default: () => {return {pointData: [],lineData: {},rangeData: {},};},},},data() {return {map: null,zoom: 14,longitude: 117.119529,latitude: 36.650396,};},watch: {// 只关注mapData数据源即可,监听mapData数据源改变清空地图,重新打点\线\面mapData: {handler(newV, oldV) {this.map.clearOverLays();this.drawMap();},deep: true,},},methods: {initMap() {this.map = new T.Map("mapCon");this.map.centerAndZoom(new T.LngLat(this.longitude, this.latitude),this.zoom);this.drawMap();},drawMap() {this.drawPoint();this.drawLine();this.drawRange();},// 绘制点drawPoint() {this.mapData?.pointData?.forEach((item) => {var marker = new T.Marker(new T.LngLat(item[0], item[1]));this.map.addOverLay(marker);var label = new T.Label({text: item[2],position: new T.LngLat(item[0], item[1]),offset: new T.Point(0, 0),style: {fontSize: "14px",color: "#000",backgroundColor: "rgba(255, 255, 255, 0.8)",padding: "5px",borderRadius: "5px",border: "1px solid #ccc",},});this.map.addOverLay(label);});},// 绘制线drawLine() {if (this.mapData.lineData) {let coordinates;if (this.mapData.lineData.length > 0 &&Array.isArray(this.mapData.lineData[0])) {coordinates = this.mapData.lineData[0].map((coord) => new T.LngLat(coord[0], coord[1]));} else {coordinates = this.mapData.lineData.map((coord) => new T.LngLat(coord[0], coord[1]));}if (coordinates.length > 1) {const polyline = new T.Polyline(coordinates, {color: "#ff0000",weight: 3,});this.map.addOverLay(polyline);this.map.panTo(coordinates[0]);}}},// 绘制面drawRange() {if (this.mapData.rangeData) {let coordinates;if (this.mapData.rangeData.length > 0 &&Array.isArray(this.mapData.rangeData[0])) {coordinates = this.mapData.rangeData[0].map((coord) => new T.LngLat(coord[0], coord[1]));} else {coordinates = this.mapData.rangeData.map((coord) => new T.LngLat(coord[0], coord[1]));}if (coordinates.length > 2) {var polygon = new T.Polygon(coordinates, {color: "green",weight: 3,opacity: 0.5,fillColor: "red",fillOpacity: 0.5,strokeStyle: "solid",});this.map.addOverLay(polygon);if (coordinates.length > 0) {const center = this.getPolygonCenter(coordinates);// this.map.panTo(center);}}}},// 打点async handlePoint(i) {if (handler) handler.close(); // 如果已有打点工具打开,先关闭handler = new T.MarkTool(this.map, {follow: true,icon: new T.Icon({iconUrl: markerIcon,iconSize: new T.Point(25, 41),}),});handler.open(); // 打开打点工具handler.addEventListener("mouseup", async (e) => {try {// 获取打点位置的名称const locationName = await this.getLocationName(e.currentLnglat.lng,e.currentLnglat.lat);// 通知父组件打点完成this.$emit("finishPoint",[e.currentLnglat.lng, e.currentLnglat.lat, locationName],i);} catch (error) {console.error("获取位置名称失败:", error);} finally {handler.close(); // 关闭打点工具}});},// 画线handleLine() {if (this.handler) this.handler.close(); // 如果已有绘线工具打开,先关闭this.handler = new T.PolylineTool(this.map, {color: "#ff0000", // 线的颜色weight: 3, // 线的宽度});this.handler.open(); // 打开绘线工具this.handler.addEventListener("draw", (e) => {// 将绘制的线的坐标转换为二维数组const lineCoordinates = e.currentLnglats.map((item) => [item.lng,item.lat,]);// 发射事件,通知父组件绘线完成this.$emit("finishLine", lineCoordinates);});},// 画范围handleRange() {if (this.handler) this.handler.close(); // 如果已有绘图工具打开,先关闭this.handler = new T.PolygonTool(this.map, {color: "#ff0000", // 多边形边框颜色weight: 3, // 多边形边框宽度});this.handler.open(); // 打开绘图工具this.handler.addEventListener("draw", (e) => {// 将绘制的多边形的坐标转换为二维数组const polygonCoordinates = e.currentLnglats.map((item) => [item.lng,item.lat,]);// 通知父组件绘制完成this.$emit("finishRange", polygonCoordinates);});},// 计算多边形的中心点getPolygonCenter(coordinates) {let sumLng = 0;let sumLat = 0;coordinates.forEach((coord) => {sumLng += coord.lng;sumLat += coord.lat;});const centerLng = sumLng / coordinates.length;const centerLat = sumLat / coordinates.length;return new T.LngLat(centerLng, centerLat);},// 根据经纬度获取当前地名称getLocationName(lng, lat) {const geocoder = new T.Geocoder();return new Promise((resolve, reject) => {geocoder.getLocation(new T.LngLat(lng, lat), (result) => {if (result.getStatus() === 0) {const address = result.getAddress();resolve(address); // address即为当前点名称} else {reject(result.getMsg());}});});},},mounted() {this.initMap();},
};
</script><style scoped lang="scss">
.map-container {position: relative;#mapCon {height: 70vh;}
}
</style>

使用地图组件完整代码

// 编辑地图信息弹窗
<template><div class="container-box"><el-dialogv-if="visible":title="title":visible.sync="visible"width="90vw"custom-class="dialog-class"><el-row :gutter="20"><el-col :span="12"><MapEleref="mapEleRef":mapData="mapData"@finishPoint="finishPoint"@finishLine="finishLine"@finishRange="finishRange"/></el-col><el-col :span="12"><el-form ref="form" :model="form" :rules="rules" label-width="140px"><el-row :gutter="20"><el-col :span="24"><el-form-item label="名称" prop="name"><el-inputv-model="form.name"placeholder="请输入名称"/> </el-form-item></el-col><el-col :span="24"><el-form-item label="起点位置" prop="startLocation"><el-inputv-model="form.startLocation"placeholder="请选择起点位置"readonlydisabled><template slot="append"><el-buttonicon="el-icon-location-outline"@click="drawPoint(0)"></el-button><el-dividerdirection="vertical"class="divider-class"></el-divider><el-buttonicon="el-icon-delete"@click="delPoint(0)"></el-button> </template></el-input> </el-form-item></el-col><el-col :span="24"><el-form-item label="终点位置" prop="endLocation"><el-inputv-model="form.endLocation"placeholder="请选择终点位置"readonlydisabled><template slot="append"><el-buttonicon="el-icon-location-outline"@click="drawPoint(1)"></el-button><el-dividerdirection="vertical"class="divider-class"></el-divider><el-buttonicon="el-icon-delete"@click="delPoint(1)"></el-button></template> </el-input></el-form-item></el-col><el-col :span="24"><el-form-item label="线" prop="pipelayer"><el-inputv-model="form.pipelayer"disabledplaceholder="请绘制线"><template slot="append"><el-buttonicon="el-icon-edit-outline"@click="drawLine"></el-button><el-dividerdirection="vertical"class="divider-class"></el-divider><el-buttonicon="el-icon-delete"@click="delLine"></el-button></template> </el-input></el-form-item></el-col><el-col :span="24"><el-form-item label="区域" prop="piperange"><el-inputv-model="form.piperange"disabledplaceholder="请绘制区域"><template slot="append"><el-buttonicon="el-icon-edit-outline"@click="drawRange"></el-button><el-dividerdirection="vertical"class="divider-class"></el-divider><el-buttonicon="el-icon-delete"@click="delRange"></el-button></template></el-input> </el-form-item></el-col><el-col :span="24"><el-form-item label="高度差" prop="altitude"><el-inputv-model="form.altitude"placeholder="请输入高度差"/> </el-form-item></el-col><el-col :span="24"><el-form-item label="面积(㎡)" prop="heatArea"><el-inputv-model="form.heatArea"placeholder="请输入面积"/> </el-form-item></el-col></el-row></el-form></el-col></el-row><div slot="footer" class="dialog-footer"><el-button type="primary" v-if="!enterprise" @click="submitForm">确 定</el-button><el-button @click="cancel">取 消</el-button></div></el-dialog></div>
</template><script>
import { cloneDeep as _cloneDeep } from "lodash";
import { updateApi, getGateway } from "@/api/basicData/mainPipeNetwork.js";
import MapEle from "@/components/MapEle";
export default {components: { MapEle },data() {return {title: "",visible: false,defaultForm: {name: undefined,startLocation: undefined,endLocation: undefined,startLongitude: undefined,startLatitude: undefined,endLongitude: undefined,endLatitude: undefined,altitude: undefined,heatArea: undefined,pipelayer: undefined,piperange: undefined,},rules: {name: [{ required: true, message: "主网名称不能为空", trigger: "blur" },],startLocation: [{ required: true, message: "起点位置不能为空", trigger: "blur" },],endLocation: [{ required: true, message: "终点位置不能为空", trigger: "blur" },],pipelayer: [{ required: true, message: "线不能为空", trigger: "blur" }],piperange: [{ required: true, message: "区域不能为空", trigger: "blur" },],altitude: [{ required: true, message: "高度差不能为空", trigger: "blur" },],heatArea: [{ required: true, message: "面积不能为空", trigger: "blur" },],},form: {},enterprise: false, // 企业标识mapVisible: false,mapFlag: 1,mapData: {pointData: [],lineData: {coordinates: [],},rangeData: {coordinates: [],},},};},created() {// 判斷當前用戶是否有企业标识 qiyeif (this.$store.state.user?.roles.length &&this.$store.state.user?.roles.indexOf("qiye") >= 0) {this.enterprise = true;}},methods: {// 绘制点,这里的i标识起点(0)和终点(1)(根据个人情况使用)drawPoint(i) {// 绘制当前点时先将之前点清空,再绘制this.delPoint(i);this.$nextTick(() => {this.$refs.mapEleRef.handlePoint(i);});},// 绘制线drawLine() {this.delLine();this.$nextTick(() => {this.$refs.mapEleRef.handleLine();});},// 绘制面drawRange() {this.delRange();this.$nextTick(() => {this.$refs.mapEleRef.handleRange();});},// 删除点delPoint(i) {// 获取要删除的点的经纬度const { longitude, latitude } =i === 1? {longitude: this.form.endLongitude,latitude: this.form.endLatitude,}: {longitude: this.form.startLongitude,latitude: this.form.startLatitude,};// 从 mapData.pointData 中移除对应的点this.mapData.pointData = this.mapData.pointData.filter((item) => {return !(item[0] === longitude && item[1] === latitude);});// 清空表单中的位置信息if (i === 1) {this.form.endLocation = "";this.form.endLongitude = "";this.form.endLatitude = "";} else {this.form.startLocation = "";this.form.startLongitude = "";this.form.startLatitude = "";}},// 删除线delLine() {this.form.pipelayer = "";this.$forceUpdate();this.mapData.lineData = [];},// 删除面delRange() {this.form.piperange = "";this.$forceUpdate();this.mapData.rangeData = [];},// 绘制完点后触发的方法finishPoint(arr, i) {// 将点的坐标和名称保存到 mapData.pointData 中this.mapData.pointData.push(arr);// 根据索引 i 更新表单中的起点或终点信息const updateForm = (location, longitude, latitude) => {this.form[location] = arr[2];this.form[longitude] = arr[0];this.form[latitude] = arr[1];};if (i === 1) {updateForm("endLocation", "endLongitude", "endLatitude");} else {updateForm("startLocation", "startLongitude", "startLatitude");}},// 绘制完线后触发的方法finishLine(arr) {this.mapData.lineData = [arr];this.form.pipelayer = JSON.stringify(arr);this.$forceUpdate();},// 绘制完面后触发的方法finishRange(arr) {this.mapData.rangeData = [arr];this.form.piperange = JSON.stringify(arr);this.$forceUpdate();},// 打开编辑页面async open(row) {try {// 获取地图数据const res = await this.getMapData(row);const tempData = JSON.parse(res?.data);// 初始化地图数据this.mapData = {pointData: [[row.startLongitude, row.startLatitude, row.startLocation],[row.endLongitude, row.endLatitude, row.endLocation],],lineData: tempData?.features?.[0]?.pipelayer?.coordinates,rangeData: tempData?.features?.[0]?.piperange?.coordinates,};// 初始化表单数据this.form = _cloneDeep(this.defaultForm);this.form = { ...row };this.form.pipelayer = JSON.stringify(tempData?.features?.[0]?.pipelayer?.coordinates[0] || []);this.form.piperange = JSON.stringify(tempData?.features?.[0]?.piperange?.coordinates[0] || []);// 设置对话框标题和可见性this.title = "修改";this.visible = true;} catch (error) {console.error("打开对话框时出错:", error);}},// 获取地图线和区域数据getMapData(row) {return new Promise((resolve, reject) => {getGateway({ bh: row.code }).then((response) => {resolve(response);}).catch((error) => {reject(error);});});},// 关闭弹窗页`cancel() {this.visible = false;},// 提交submitForm() {this.$refs["form"].validate((valid) => {if (valid) {// 构建提交参数const params = {...this.form,layer: {pipeLayerVar: this.form.pipelayer,pipeRangeVar: `[${this.form.piperange}]`,},};// 调用更新接口updateApi(params).then((response) => {this.$modal.msgSuccess("修改成功");this.cancel();this.$emit("refreshList");}).catch((error) => {this.$modal.msgError("修改失败:" + error.message);});} else {this.$modal.msgWarning("表单验证失败,请检查输入内容");}});},},
};
</script><style scoped lang="scss">
.container-box {::v-deep .el-dialog.dialog-class {height: auto;height: 90vh;overflow-y: auto;}::v-deep .el-dialog__body {height: 75vh !important;}
}.divider-class {margin: 0 20px;
}
</style>

文档:http://lbs.tianditu.gov.cn/api/js4.0/examples.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/70061.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java八股文详细文档.2(基于黑马、ChatGPT、DeepSeek)

通过B站黑马程序员的八股文教学&#xff0c;自己也二刷了&#xff0c;结合ChatGpt、deepSeek总结了一下,Java八股文详细文档.2&#xff08;Redis篇和消息中间件篇&#xff0c;还没有写完&#xff0c;这只是一部分&#xff09; Java八股文详细文档.1&#xff08;包含JVM篇、数据…

简述 tsconfig.json 中 rootDir 和 include 之间的关系

tsconfig.json 中的 rootDir 和 include 之间有一定的关系&#xff0c;但它们的作用是不同的。理解它们的关系可以帮助你更好地配置 TypeScript 项目。 1. rootDir 的作用 rootDir 用于指定 TypeScript 编译器&#xff08;tsc&#xff09;的“根目录”。它的主要作用是&#x…

如何在Spring Boot中使用Profiles实现环境隔离

文章目录 如何在Spring Boot中使用Profiles实现环境隔离什么是Spring Profiles1.基本概念2.配置管理3.使用场景4.条件化配置5.优点Spring Profiles的基础知识1.Profile的定义2.配置文件3.激活Profiles4.条件化配置5.Profile的优先级与合并6.Profiles的最佳实践配置文件的组织1.…

SpringBoot使用TraceId日志链路追踪

项目场景&#xff1a; ??有时候一个业务调用链场景&#xff0c;很长&#xff0c;调了各种各样的方法&#xff0c;看日志的时候&#xff0c;各个接口的日志穿插&#xff0c;确实让人头大。为了解决这个痛点&#xff0c;就使用了TraceId&#xff0c;根据TraceId关键字进入服务…

微信小程序网络请求封装

微信小程序的网络请求为什么要封装&#xff1f;封装使用有什么好处&#xff1f; 封装的目的是为了偷懒&#xff0c;试想一下每次都要wx.request&#xff0c;巴拉巴拉传一堆参数&#xff0c;是不是很麻烦&#xff0c;有些公共的参数例如header&#xff0c;baseUrl是不是可以封装…

Element Plus table 去除行hover效果

需求&#xff1a; 给table的指定行设置高亮背景色且去除掉这些行的hover效果 思路&#xff1a; 给指定行设置css类名选择需要设置高亮的行的单元格&#xff0c;设置鼠标禁用属性让高亮行继承父元素的背景色 考虑到表格的第一列是勾选框&#xff0c;因此仅选择 tr 下除了第一…

认识vue-admin

认识vue-admin **核心交付:** 为什么要基于现成架子二次开发 什么是二次开发&#xff1a;基于已有的代码&#xff08;项目工程&#xff0c;脚手架&#xff09;开进行新功能的开发 所以看懂已有的框架中的既有代码&#xff0c;变得很重要了 1. 背景知识 后台管理系统是一种最…

无人机航迹规划:孟加拉虎优化( Savannah Bengal Tiger Optimization ,SBTO)算法求解无人机路径规划MATLAB

一、孟加拉虎优化算法 孟加拉虎优化&#xff08; Savannah Bengal Tiger Optimization &#xff0c;SBTO&#xff09;算法模拟了孟加拉虎的群体狩猎行为&#xff0c;采用了猎物搜索、隐身接近和攻击狩猎三种策略。 参考文献&#xff1a; [1]Yujing Sun, Xingguo Xu. Savann…

sib报错:com.*.xctrunner is not in your device!

1、问题描述 在使用sonic集成IOS设备的时候,我们需要通过sonic-agent服务去识别IOS设备。但是在识别的时候提示如下问题: 本质就是在你这个设备中找不到这个设备也就是找不到WebDriverAgentRunner,但是确实安装了,甚至appium可以正常的调用。 或执行如下命令的时候报错:…

c++中什么时候应该使用final关键字?

在C中&#xff0c;final关键字是自C11标准引入的重要特性&#xff0c;主要用于类继承和虚函数重写机制的约束。下面从技术原理、使用场景和最佳实践三个维度进行系统分析&#xff0c;并给出工业级代码示例。 目录 一、技术原理深度解析 二、关键使用场景分析 1. 类级别的fi…

【AI】Docker中快速部署Ollama并安装DeepSeek-R1模型: 一步步指南

【AI】Docker中快速部署Ollama并安装DeepSeek-R1模型: 一步步指南 一、前言 为了确保在 Docker 环境中顺利安装并高效运行 Ollama 以及 DeepSeek 离线模型&#xff0c;本文将详细介绍整个过程&#xff0c;涵盖从基础安装到优化配置等各个方面。通过对关键参数和配置的深入理解…

文件夹上传到github分支最后github上面还是没有文件和文件夹

环境&#xff1a; github 问题描述&#xff1a; 文件夹上传到github分支最后github上面还是没有文件和文件夹, 和这样一样 解决方案&#xff1a; 从 git ls-tree -r HEAD 的输出中可以看到&#xff0c;metahuman-stream 文件夹显示为如下内容&#xff1a; 160000 commi…

【JavaEE进阶】验证码案例

目 &#x1f332;实现说明 &#x1f384;Hutool介绍 &#x1f333;准备工作 &#x1f334;约定前后端交互接口 &#x1f6a9;接口定义 &#x1f6a9;实现服务器后端代码 &#x1f6a9;前端代码 &#x1f6a9;整体测试 &#x1f332;实现说明 随着安全性的要求越来越⾼…

4G模块非必要,不关机!关机建议先进飞行模式

给4G模组VBAT断电关机&#xff0c;模组关机前未能及时退出当前基站&#xff0c;会有什么影响呢&#xff1f; 基站会误以为设备还在线&#xff0c;下次开机仍会拿着上次驻网信息去连基站。基站一看&#xff0c;上次链接还在——认为你是非法设备&#xff0c;拒绝链接&#xff…

Flutter中 List列表中移除特定元素

在 Dart 语言里&#xff0c;若要从子列表中移除特定元素&#xff0c;可以使用以下几种方法&#xff0c;下面为你详细介绍&#xff1a; 方法一&#xff1a;使用 where 方法创建新列表 where 方法会根据指定的条件筛选元素&#xff0c;然后通过 toList 方法将筛选结果转换为新列…

CF 148A.Insomnia cure(Java实现)

题目分析 这道题翻译出来后比较难理解&#xff0c;但是实际情况就是从1遍历d&#xff0c;看能不能被前四个值整除 思路分析 由上所述&#xff0c;存值后判断是否能整除&#xff0c;整除就答案1 代码 import java.util.*;public class Main {public static void main(String[]…

Java:单例模式(Singleton Pattern)及实现方式

一、单例模式的概念 单例模式是一种创建型设计模式&#xff0c;确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例&#xff0c;是 Java 中最简单的设计模式之一。该模式常用于需要全局唯一实例的场景&#xff0c;例如日志记录器、配置管理、线程池、数据库…

企业SSL 证书管理指南

文章从以下几个部分展开 SSL证书的用途和使用场景SSL证书的申请类型和实现方式SSL证书的管理SSL证书的续签 一、SSL 证书的用途和使用场景 1.1 为什么要使用 SSL 证书&#xff1f; 1. 数据安全 &#x1f6e1;️- 在 HTTP 传输中&#xff0c;TCP 包可以被截获&#xff0c;攻…

网络安全-攻击流程-传输层

传输层攻击主要针对OSI模型的第四层&#xff0c;涉及TCP和UDP协议的安全漏洞。以下是常见攻击类型及其流程&#xff0c;以及防御措施&#xff1a; 1. SYN洪水攻击&#xff08;TCP半连接攻击&#xff09; 攻击流程&#xff1a; 目标选择&#xff1a;确定目标服务器的IP地址和开…

朝天椒USB服务器解决前置机U盾虚拟机远程连接

本文探讨朝天椒USB服务器用Usb Over Network技术&#xff0c;解决前置机虚拟化部署后U盾的远程连接问题。 在金融、电信等关键行业&#xff0c;后台核心处理系统承担着至关重要的业务数据交互职责。为保障系统安全&#xff0c;这些单位要求企业通过前置机与他们的内网进行数据…