From c061111280618a4acacf2166b3727090f7304f86 Mon Sep 17 00:00:00 2001 From: Teo <2642673902@qq.com> Date: Thu, 24 Apr 2025 18:00:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E5=8F=B3=E9=94=AE=E8=8F=9C?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/openLayersMap/index.vue | 148 ++++++++++++++++++++----- src/utils/snowflake.ts | 93 ++++++++-------- src/views/project/project/index.vue | 13 ++- 3 files changed, 177 insertions(+), 77 deletions(-) diff --git a/src/components/openLayersMap/index.vue b/src/components/openLayersMap/index.vue index 15524b2..ef13083 100644 --- a/src/components/openLayersMap/index.vue +++ b/src/components/openLayersMap/index.vue @@ -1,17 +1,45 @@ @@ -27,11 +55,11 @@ import Feature from 'ol/Feature'; // OpenLayers的要素类,表示地图上的 import Point from 'ol/geom/Point'; // OpenLayers的点几何类,用于表示点状的地理数据 import { Vector as VectorLayer } from 'ol/layer'; // OpenLayers的矢量图层类,用于显示矢量数据 import { Vector as VectorSource } from 'ol/source'; // OpenLayers的矢量数据源类,用于管理和提供矢量数据 -import { Circle, Style, Stroke, Fill, Icon } from 'ol/style'; // OpenLayers的样式类,用于定义图层的样式,包括圆形样式、基本样式、边框、填充和图标 +import { Circle, Style, Stroke, Fill, Icon, Text } from 'ol/style'; // OpenLayers的样式类,用于定义图层的样式,包括圆形样式、基本样式、边框、填充和图标 import LineString from 'ol/geom/LineString'; // OpenLayers的线几何类,用于表示线状的地理数据 import Polygon from 'ol/geom/Polygon'; // OpenLayers的多边形几何类,用于表示面状的地理数据 import * as turf from '@turf/turf'; -import { Snowflake } from '@/utils/snowflake'; +import { SnowflakeIdGenerator } from '@/utils/snowflake'; const props = defineProps({ treeData: { type: Array, @@ -39,19 +67,25 @@ const props = defineProps({ }, projectId: String }); -const snowflake = new Snowflake(1, 1); +const contextMenu = ref(null); +const selectLayer = ref([]); +const treeProps = { + value: 'name' +}; +const snowflake = new SnowflakeIdGenerator(1, 1); let map: any = null; const layerData = reactive({}); -const centerPosition = ref(fromLonLat([107.12932603888963, 23.80590052110889])); +const centerPosition = ref(fromLonLat([107.13761560163239, 23.80480003743964])); const nodeMenu = (e: any) => { console.log(e); }; const jsonData = computed(() => { + let id = 0; props.treeData.forEach((item: any) => { - item.features.forEach((itm, idx) => { - itm.geometry.id = snowflake.nextId(); + item.features.forEach((itm) => { + itm.geometry.id = ++id; itm.geometry.coordinates = convertStrToNum(itm.geometry.coordinates); }); }); @@ -70,7 +104,7 @@ const handleCheckChange = (data: any, bool) => { if (bool) { if (!layerData[data.features[0].properties.id]) { data.features.forEach((item: any) => { - creatPoint(item.geometry.coordinates, item.geometry.type, item.geometry.id); + creatPoint(item.geometry.coordinates, item.geometry.type, item.geometry.id, item.properties.text); }); } else { data.features.forEach((item: any) => { @@ -164,13 +198,13 @@ function convertStrToNum(arr) { } /** - * Date:2024/3/26 - * Author:zx - * Function:【面】 - * @param 无 - */ - -const creatPoint = (pointObj: Array, type: string, id: string) => { + * 创建图层 + * @param {*} pointObj 坐标数组 + * @param {*} type 类型 + * @param {*} id 唯一id + * @param {*} name 名称 + * */ +const creatPoint = (pointObj: Array, type: string, id: string, name?: string) => { // 创建多边形的几何对象 let polygon; if (type === 'Point') { @@ -193,6 +227,14 @@ const creatPoint = (pointObj: Array, type: string, id: string) => { fill: new Fill({ color: 'red' }) + }), + text: new Text({ + font: '12px Microsoft YaHei', + text: name, + scale: 1, + fill: new Fill({ + color: '#7bdd63' + }) }) }); const polygonStyle = new Style({ @@ -216,15 +258,68 @@ const creatPoint = (pointObj: Array, type: string, id: string) => { map.addLayer(layerData[id]); }; +// 控制菜单是否显示 +const isMenuVisible = ref(false); +// 菜单的 x 坐标 +const menuX = ref(0); +// 菜单的 y 坐标 +const menuY = ref(0); + +// 显示菜单的方法 +const showMenu = (event: MouseEvent, data) => { + console.log(data); + contextMenu.value = data.name; + isMenuVisible.value = true; + menuX.value = event.clientX; + menuY.value = event.clientY; +}; + +// 处理菜单项点击事件的方法 +const handleMenuItemClick = (option: string) => { + selectLayer.value.push(`${contextMenu.value}被选中为${option}`); + isMenuVisible.value = false; +}; + +//删除菜单 +const delLayer = (index) => { + selectLayer.value.splice(index, 1); +}; + +// 点击页面其他区域隐藏菜单 +const closeMenuOnClickOutside = (event: MouseEvent) => { + if (isMenuVisible.value) { + const menuElement = document.querySelector('.fixed.bg-white'); + if (menuElement && !menuElement.contains(event.target as Node)) { + isMenuVisible.value = false; + } + } +}; + +// 添加全局点击事件监听器 +window.addEventListener('click', closeMenuOnClickOutside); + +// 组件卸载时移除事件监听器 +const onUnmounted = () => { + window.removeEventListener('click', closeMenuOnClickOutside); +}; + onMounted(() => { // 地图初始化 initOLMap(); -}); - -onDeactivated(() => { - console.log('地图销毁'); - - map.getOverlays().clear(); + creatPoint( + [ + [ + [107.13761912095511, 23.80479336386864], + [107.13776644838967, 23.804823038597075], + [107.13775276784109, 23.80486256412652], + [107.1376054403658, 23.80483288938397], + [107.13761912095511, 23.80479336386864] + ] + ], + 'Polygon', + '1' + ); + // creatPoint([107.13761560163239, 23.80480003743964], 'Point', '2', '点'); }); diff --git a/src/utils/snowflake.ts b/src/utils/snowflake.ts index 12ad0e1..7271a67 100644 --- a/src/utils/snowflake.ts +++ b/src/utils/snowflake.ts @@ -1,59 +1,33 @@ -export class Snowflake { - private startTimeStamp: number = 1609459200000; - private workerIdBits: number = 5; - private dataCenterIdBits: number = 5; - private sequenceBits: number = 12; +export class SnowflakeIdGenerator { + private readonly startTimeStamp = 1609459200000; // 起始时间戳,这里设置为 2021-01-01 00:00:00 + private readonly workerIdBits = 5; + private readonly dataCenterIdBits = 5; + private readonly sequenceBits = 12; - private maxWorkerId: number = -1 ^ (-1 << this.workerIdBits); - private maxDataCenterId: number = -1 ^ (-1 << this.dataCenterIdBits); + private readonly maxWorkerId = -1 ^ (-1 << this.workerIdBits); + private readonly maxDataCenterId = -1 ^ (-1 << this.dataCenterIdBits); - private workerIdShift: number = this.sequenceBits; - private dataCenterIdShift: number = this.sequenceBits + this.workerIdBits; - private timestampLeftShift: number = this.sequenceBits + this.workerIdBits + this.dataCenterIdBits; - private sequenceMask: number = -1 ^ (-1 << this.sequenceBits); + private readonly workerIdShift = this.sequenceBits; + private readonly dataCenterIdShift = this.sequenceBits + this.workerIdBits; + private readonly timestampLeftShift = this.sequenceBits + this.workerIdBits + this.dataCenterIdBits; + private readonly sequenceMask = -1 ^ (-1 << this.sequenceBits); private workerId: number; private dataCenterId: number; - private sequence: number = 0; - private lastTimestamp: number = -1; + private sequence = 0; + private lastTimestamp = -1; constructor(workerId: number, dataCenterId: number) { if (workerId > this.maxWorkerId || workerId < 0) { - throw new Error(`Worker ID 不能大于 ${this.maxWorkerId} 或小于 0`); + throw new Error(`Worker ID 必须在 0 到 ${this.maxWorkerId} 之间`); } if (dataCenterId > this.maxDataCenterId || dataCenterId < 0) { - throw new Error(`数据中心 ID 不能大于 ${this.maxDataCenterId} 或小于 0`); + throw new Error(`数据中心 ID 必须在 0 到 ${this.maxDataCenterId} 之间`); } this.workerId = workerId; this.dataCenterId = dataCenterId; } - public nextId(): number { - let timestamp = this.getCurrentTimestamp(); - if (timestamp < this.lastTimestamp) { - throw new Error('检测到时钟回拨,拒绝生成 ID'); - } - if (timestamp === this.lastTimestamp) { - this.sequence = (this.sequence + 1) & this.sequenceMask; - if (this.sequence === 0) { - timestamp = this.waitNextMillis(this.lastTimestamp); - } - } else { - this.sequence = 0; - } - this.lastTimestamp = timestamp; - return ( - ((timestamp - this.startTimeStamp) << this.timestampLeftShift) | - (this.dataCenterId << this.dataCenterIdShift) | - (this.workerId << this.workerIdShift) | - this.sequence - ); - } - - private getCurrentTimestamp(): number { - return Date.now(); - } - private waitNextMillis(lastTimestamp: number): number { let timestamp = this.getCurrentTimestamp(); while (timestamp <= lastTimestamp) { @@ -61,11 +35,34 @@ export class Snowflake { } return timestamp; } -} -// 使用示例 -// const workerId: number = 1; -// const dataCenterId: number = 1; -// const snowflake = new Snowflake(workerId, dataCenterId); -// const id: number = snowflake.nextId(); -// console.log('生成的唯一 ID:', id); + private getCurrentTimestamp(): number { + return Date.now(); + } + + nextId(): number { + let timestamp = this.getCurrentTimestamp(); + + if (timestamp < this.lastTimestamp) { + throw new Error('时钟回拨,拒绝生成 ID 达 ' + (this.lastTimestamp - timestamp) + ' 毫秒'); + } + + if (timestamp === this.lastTimestamp) { + this.sequence = (this.sequence + 1) & this.sequenceMask; + if (this.sequence === 0) { + timestamp = this.waitNextMillis(this.lastTimestamp); + } + } else { + this.sequence = 0; + } + + this.lastTimestamp = timestamp; + + return ( + ((timestamp - this.startTimeStamp) << this.timestampLeftShift) | + (this.dataCenterId << this.dataCenterIdShift) | + (this.workerId << this.workerIdShift) | + this.sequence + ); + } +} diff --git a/src/views/project/project/index.vue b/src/views/project/project/index.vue index ee30b2c..339f0bd 100644 --- a/src/views/project/project/index.vue +++ b/src/views/project/project/index.vue @@ -261,7 +261,12 @@ - + + + 光伏板 + 桩点/支架 + 方阵 +