From a7c52546d20c34185c3d74a2ac08754548e2fe9d Mon Sep 17 00:00:00 2001 From: ctw <1051735452@qq.com> Date: Mon, 19 Jan 2026 11:22:18 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=82=B9=E7=BA=BF?= =?UTF-8?q?=E9=9D=A2=E7=BB=98=E5=88=B6=EF=BC=8C=E4=BC=98=E5=8C=96=E6=B5=8B?= =?UTF-8?q?=E8=B7=9D=E6=B5=8B=E9=9D=A2=E7=A7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/src/views/cesiumMap/index.vue | 570 ++++++++++++++++++++++----------- 1 file changed, 384 insertions(+), 186 deletions(-) diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue index 6d491f4..123c394 100644 --- a/ruoyi-ui/src/views/cesiumMap/index.vue +++ b/ruoyi-ui/src/views/cesiumMap/index.vue @@ -212,7 +212,8 @@ export default { // 绘制相关 drawingMode: null, // 'point', 'line', 'polygon', 'rectangle', 'circle' drawingHandler: null, - tempEntity: null, + tempEntity: null, // 最终实体 + tempPreviewEntity: null, // 预览实体(新增) drawingPoints: [], drawingStartPoint: null, isDrawing: false, @@ -462,20 +463,26 @@ export default { stopDrawing() { if (this.drawingHandler) { - this.drawingHandler.destroy() - this.drawingHandler = null + this.drawingHandler.destroy(); + this.drawingHandler = null; } if (this.tempEntity) { - this.viewer.entities.remove(this.tempEntity) - this.tempEntity = null + this.viewer.entities.remove(this.tempEntity); + this.tempEntity = null; + } + + // 确保也清理预览实体 + if (this.tempPreviewEntity) { + this.viewer.entities.remove(this.tempPreviewEntity); + this.tempPreviewEntity = null; } - this.drawingPoints = [] - this.drawingStartPoint = null - this.isDrawing = false + this.drawingPoints = []; + this.drawingStartPoint = null; + this.isDrawing = false; - this.viewer.scene.canvas.style.cursor = 'default' + this.viewer.scene.canvas.style.cursor = 'default'; }, // ******************************************************************** // 绘制点 @@ -490,18 +497,66 @@ export default { }, // 绘制线 + // 绘制线 startLineDrawing() { + this.drawingPoints = []; + // 记录当前鼠标的实时位置 + let activeCursorPosition = null; + + // 清除可能存在的旧实体 + if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); + if (this.tempPreviewEntity) this.viewer.entities.remove(this.tempPreviewEntity); + this.tempEntity = null; + this.tempPreviewEntity = null; + + // 1. 鼠标移动事件:仅更新坐标变量,不操作实体 + this.drawingHandler.setInputAction((movement) => { + const newPosition = this.getClickPosition(movement.endPosition); + if (newPosition) { + activeCursorPosition = newPosition; + } + }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); + + // 2. 鼠标点击事件:确定点位 this.drawingHandler.setInputAction((click) => { - const position = this.getClickPosition(click.position) + const position = this.getClickPosition(click.position); if (position) { - this.drawingPoints.push(position) - - // 更新临时线 - if (this.tempEntity) { - this.viewer.entities.remove(this.tempEntity) - } - - if (this.drawingPoints.length > 1) { + this.drawingPoints.push(position); + + // === 第一步:点击第一个点后,立即创建“动态虚线” === + if (this.drawingPoints.length === 1) { + activeCursorPosition = position; // 初始化鼠标位置 + + // 创建预览虚线(只创建这一次,之后它会自动随数据更新) + this.tempPreviewEntity = this.viewer.entities.add({ + polyline: { + // 关键:使用 CallbackProperty 动态获取位置 + positions: new Cesium.CallbackProperty(() => { + // 只有当有点且鼠标位置存在时才渲染 + if (this.drawingPoints.length > 0 && activeCursorPosition) { + // 获取最后一个已确认的点 + const lastPoint = this.drawingPoints[this.drawingPoints.length - 1]; + // 返回 [最后一个点, 当前鼠标位置] + return [lastPoint, activeCursorPosition]; + } + return []; + }, false), + width: this.defaultStyles.line.width, + // 虚线材质 + material: new Cesium.PolylineDashMaterialProperty({ + color: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), + dashLength: 16 + }), + clampToGround: true // 贴地 + } + }); + } + // === 第二步:点击后续点时,绘制/延长“固定实线” === + else { + // 移除旧的实线,重新画包含新点的实线 + if (this.tempEntity) { + this.viewer.entities.remove(this.tempEntity); + } this.tempEntity = this.viewer.entities.add({ polyline: { positions: this.drawingPoints, @@ -509,95 +564,137 @@ export default { material: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), clampToGround: true } - }) + }); } } - }, Cesium.ScreenSpaceEventType.LEFT_CLICK) + }, Cesium.ScreenSpaceEventType.LEFT_CLICK); - // 右键完成绘制 + // 3. 右键完成绘制 this.drawingHandler.setInputAction(() => { + // 完成绘制前,移除那条动态虚线 + if (this.tempPreviewEntity) { + this.viewer.entities.remove(this.tempPreviewEntity); + this.tempPreviewEntity = null; + } + if (this.drawingPoints.length > 1) { - this.finishLineDrawing() + this.finishLineDrawing(); } else { - this.cancelDrawing() + this.cancelDrawing(); } - }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) + + // 重置局部变量 + activeCursorPosition = null; + }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }, finishLineDrawing() { - const positions = [...this.drawingPoints] - const entity = this.addLineEntity(positions) - - // 计算长度 - const length = this.calculateLineLength(positions) - this.measurementResult = { - distance: length, - type: 'line' + // 将预览线段转换为最终线段 + if (this.drawingPoints.length > 1) { + // 移除预览线段 + if (this.tempPreviewEntity) { + this.viewer.entities.remove(this.tempPreviewEntity); + this.tempPreviewEntity = null; + } + + // 创建最终的实线实体 + const entity = this.addLineEntity([...this.drawingPoints]); + + // 计算长度 + const length = this.calculateLineLength([...this.drawingPoints]); + this.measurementResult = { + distance: length, + type: 'line' + }; + + this.stopDrawing(); + return entity; + } else { + this.cancelDrawing(); + return null; } - - this.stopDrawing() - return entity }, // 绘制多边形 startPolygonDrawing() { + this.drawingPoints = []; + let activeCursorPosition = null; // 存储鼠标实时位置 + + // 1. 清理旧实体 + // 移除之前可能遗留的实体,确保干净的画布 + if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); + if (this.tempPreviewEntity) this.viewer.entities.remove(this.tempPreviewEntity); + this.tempEntity = null; + this.tempPreviewEntity = null; + + // 2. 鼠标移动事件:只负责更新坐标变量,不涉及繁重的绘图逻辑 + this.drawingHandler.setInputAction((movement) => { + const newPosition = this.getClickPosition(movement.endPosition); + if (newPosition) { + activeCursorPosition = newPosition; + } + }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); + + // 3. 鼠标点击事件:添加关键点 this.drawingHandler.setInputAction((click) => { - const position = this.getClickPosition(click.position) + const position = this.getClickPosition(click.position); if (position) { - this.drawingPoints.push(position) + this.drawingPoints.push(position); - // 更新临时多边形 - if (this.tempEntity) { - this.viewer.entities.remove(this.tempEntity) - } + // === 关键逻辑:点击第一个点时,创建唯一的“动态多边形” === + if (this.drawingPoints.length === 1) { + activeCursorPosition = position; // 初始化鼠标位置 - if (this.drawingPoints.length > 2) { - // 闭合多边形 - const polygonPoints = [...this.drawingPoints, this.drawingPoints[0]] this.tempEntity = this.viewer.entities.add({ + // --- 填充面配置 --- polygon: { - hierarchy: new Cesium.PolygonHierarchy(polygonPoints), - material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color) - .withAlpha(this.defaultStyles.polygon.opacity), - outline: true, - outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color), - outlineWidth: this.defaultStyles.polygon.width - } - }) - } else if (this.drawingPoints.length === 2) { - // 只有两个点时显示线 - this.tempEntity = this.viewer.entities.add({ + // hierarchy 使用 CallbackProperty 实现动态填充 + hierarchy: new Cesium.CallbackProperty(() => { + // 组合:已确定的点 + 当前鼠标位置 + if (activeCursorPosition) { + return new Cesium.PolygonHierarchy([...this.drawingPoints, activeCursorPosition]); + } + return new Cesium.PolygonHierarchy(this.drawingPoints); + }, false), + // 使用半透明颜色,方便看到地图底图 + material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), + // 确保贴地 + perPositionHeight: false + }, + // --- 边框线配置 --- polyline: { - positions: this.drawingPoints, - width: this.defaultStyles.polygon.width, - material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color), + // positions 使用 CallbackProperty 实现动态闭合线 + positions: new Cesium.CallbackProperty(() => { + if (activeCursorPosition) { + // 闭合回路:[所有点, 鼠标位置, 回到起点] + return [...this.drawingPoints, activeCursorPosition, this.drawingPoints[0]]; + } + return this.drawingPoints; + }, false), + width: this.defaultStyles.line.width, + // 边框使用虚线,表示正在编辑中 + material: new Cesium.PolylineDashMaterialProperty({ + color: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), + dashLength: 16 + }), clampToGround: true } - }) - } else if (this.drawingPoints.length === 1) { - // 只有一个点时显示点 - this.tempEntity = this.viewer.entities.add({ - position: this.drawingPoints[0], - point: { - pixelSize: 8, - color: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color) - } - }) + }); } } - }, Cesium.ScreenSpaceEventType.LEFT_CLICK) + }, Cesium.ScreenSpaceEventType.LEFT_CLICK); - // 双击完成绘制 - this.drawingHandler.setInputAction((click) => { - if (this.drawingPoints.length > 2) { - this.finishPolygonDrawing() - } - }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK) - - // 右键取消 + // 4. 右键完成绘制 this.drawingHandler.setInputAction(() => { - this.cancelDrawing() - }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) + if (this.drawingPoints.length >= 3) { + this.finishPolygonDrawing(); // 调用原有的完成逻辑 + } else { + this.cancelDrawing(); // 点数不够则取消 + } + + // 重置状态 + activeCursorPosition = null; + }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }, finishPolygonDrawing() { @@ -615,156 +712,255 @@ export default { return entity }, - // 绘制矩形 + // 绘制矩形(优化版:两点定矩形,实时预览) startRectangleDrawing() { - let startPosition = null + this.drawingPoints = []; // 存储起点和终点 + let activeCursorPosition = null; // 实时鼠标位置 + let startPoint = null; // 记录起点 - this.drawingHandler.setInputAction((click) => { - startPosition = this.getClickPosition(click.position) - if (startPosition) { - this.drawingStartPoint = startPosition - } - }, Cesium.ScreenSpaceEventType.LEFT_DOWN) + // 1. 清理旧实体 + if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); + this.tempEntity = null; + // 2. 鼠标移动事件:更新鼠标位置 this.drawingHandler.setInputAction((movement) => { - if (startPosition) { - const endPosition = this.getClickPosition(movement.endPosition) - if (endPosition) { - // 更新临时矩形 - if (this.tempEntity) { - this.viewer.entities.remove(this.tempEntity) - } + const newPosition = this.getClickPosition(movement.endPosition); + if (newPosition) { + activeCursorPosition = newPosition; + } + }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); - const rectangle = this.calculateRectangle(startPosition, endPosition) + // 3. 鼠标点击事件 + this.drawingHandler.setInputAction((click) => { + const position = this.getClickPosition(click.position); + if (position) { + // --- 情况A:第一次点击(确定起点) --- + if (!startPoint) { + startPoint = position; + this.drawingPoints.push(startPoint); + activeCursorPosition = startPoint; // 初始化鼠标位置 + + // 创建动态预览矩形 this.tempEntity = this.viewer.entities.add({ rectangle: { - coordinates: rectangle, - material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color) - .withAlpha(this.defaultStyles.rectangle.opacity), + // 关键:使用 CallbackProperty 动态计算矩形范围 + coordinates: new Cesium.CallbackProperty(() => { + if (startPoint && activeCursorPosition) { + // 使用 Cesium 内置工具,根据两个点(对角)自动计算矩形范围 + return Cesium.Rectangle.fromCartesianArray([startPoint, activeCursorPosition]); + } + return Cesium.Rectangle.fromDegrees(0, 0, 0, 0); + }, false), + // 样式:半透明填充 + 边框 + material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), outline: true, - outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color), - outlineWidth: this.defaultStyles.rectangle.width + outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), + outlineWidth: 2, + clampToGround: true // 贴地 } - }) + }); + } + // --- 情况B:第二次点击(确定终点) --- + else { + this.drawingPoints.push(position); + // 停止监听鼠标移动,因为形状已确定 + activeCursorPosition = null; + + // 调用完成逻辑 + this.finishRectangleDrawing(); } } - }, Cesium.ScreenSpaceEventType.MOUSE_MOVE) + }, Cesium.ScreenSpaceEventType.LEFT_CLICK); + // 4. 右键取消 this.drawingHandler.setInputAction(() => { - if (startPosition && this.tempEntity) { - this.finishRectangleDrawing(startPosition) - startPosition = null - } - }, Cesium.ScreenSpaceEventType.LEFT_UP) - - // 右键取消 - this.drawingHandler.setInputAction(() => { - this.cancelDrawing() - }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) + this.cancelDrawing(); + }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }, - finishRectangleDrawing(startPosition) { - if (!this.tempEntity) return - - const rectangleCoords = this.tempEntity.rectangle.coordinates.getValue() - const entity = this.addRectangleEntity(rectangleCoords) + finishRectangleDrawing() { + // 1. 获取最终的矩形范围对象 + const rect = Cesium.Rectangle.fromCartesianArray(this.drawingPoints); + + // 2. 移除动态预览的临时实体 + if (this.tempEntity) { + this.viewer.entities.remove(this.tempEntity); + this.tempEntity = null; + } - // 计算面积 - const area = this.calculateRectangleArea(rectangleCoords) + // 3. 创建最终显示的静态实体 + const finalEntity = this.viewer.entities.add({ + id: 'rectangle-' + new Date().getTime(), // 给个唯一ID + rectangle: { + coordinates: rect, + material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), + outline: true, + outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), + outlineWidth: 2, + clampToGround: true + } + }); + + // 4. 记录到实体列表 + this.allEntities.push(finalEntity); + + // 5. 计算并显示面积 + const area = this.calculateRectangleArea(rect); this.measurementResult = { area: area, type: 'rectangle' - } + }; - this.stopDrawing() - return entity + // 6. 重置状态 + this.stopDrawing(); }, + // 计算矩形面积(辅助方法) + calculateRectangleArea(rectangle) { + // 获取地球椭球体对象 + const ellipsoid = this.viewer.scene.globe.ellipsoid; + + // 方法一:使用 Cesium 几何管道计算(更精确,但需要特定模块支持) + // const geometry = new Cesium.RectangleGeometry({ rectangle: rectangle }); + // const geometryInstance = Cesium.RectangleGeometry.createGeometry(geometry); + // ...比较复杂 + + // 方法二:使用采样估算(简单且足够精确) + // 获取矩形的四个角(弧度) + const west = rectangle.west; + const south = rectangle.south; + const east = rectangle.east; + const north = rectangle.north; + + // 计算中心点的纬度 + const centerLat = (south + north) / 2; + + // 计算宽度(东西向距离):使用余弦定理校正纬度影响 + // 地球半径约为 6378137 米 + const R = 6378137; + const width = (east - west) * R * Math.cos(centerLat); + + // 计算高度(南北向距离) + const height = (north - south) * R; + + // 面积 = 宽 * 高 + const area = Math.abs(width * height); + + return area; + }, // 绘制圆形 startCircleDrawing() { - let centerPosition = null - let radius = 0 + this.drawingPoints = []; // 存储圆心 + let activeCursorPosition = null; // 实时鼠标位置 + let centerPoint = null; // 圆心坐标 - this.drawingHandler.setInputAction((click) => { - centerPosition = this.getClickPosition(click.position) - if (centerPosition) { - this.drawingStartPoint = centerPosition - - // 创建中心点 - if (this.tempEntity) { - this.viewer.entities.remove(this.tempEntity) - } - - this.tempEntity = this.viewer.entities.add({ - position: centerPosition, - point: { - pixelSize: 8, - color: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color) - } - }) - } - }, Cesium.ScreenSpaceEventType.LEFT_DOWN) + // 1. 清理旧实体 + if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); + this.tempEntity = null; + // 2. 鼠标移动事件 this.drawingHandler.setInputAction((movement) => { - if (centerPosition) { - const currentPosition = this.getClickPosition(movement.endPosition) - if (currentPosition) { - radius = Cesium.Cartesian3.distance(centerPosition, currentPosition) + const newPosition = this.getClickPosition(movement.endPosition); + if (newPosition) { + activeCursorPosition = newPosition; + } + }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); - // 更新临时圆形 - if (this.tempEntity) { - this.viewer.entities.remove(this.tempEntity) - } + // 3. 鼠标点击事件 + this.drawingHandler.setInputAction((click) => { + const position = this.getClickPosition(click.position); + if (position) { + // --- 情况A:第一次点击(确定圆心) --- + if (!centerPoint) { + centerPoint = position; + this.drawingPoints.push(centerPoint); + activeCursorPosition = centerPoint; - // 创建圆形多边形 - const positions = this.calculateCircle(centerPosition, radius, 64) + // 创建动态预览圆形 this.tempEntity = this.viewer.entities.add({ - polygon: { - hierarchy: new Cesium.PolygonHierarchy(positions), - material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color) - .withAlpha(this.defaultStyles.circle.opacity), + position: centerPoint, // 圆心固定 + ellipse: { + // 关键:使用 CallbackProperty 动态计算半径(半长轴和半短轴) + semiMajorAxis: new Cesium.CallbackProperty(() => { + if (centerPoint && activeCursorPosition) { + return Cesium.Cartesian3.distance(centerPoint, activeCursorPosition); + } + return 0; + }, false), + semiMinorAxis: new Cesium.CallbackProperty(() => { + if (centerPoint && activeCursorPosition) { + return Cesium.Cartesian3.distance(centerPoint, activeCursorPosition); + } + return 0; + }, false), + // 样式设置 + material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), outline: true, - outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color), - outlineWidth: this.defaultStyles.circle.width + outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), + outlineWidth: 2, + // height: 0, // 如果需要贴地可开启或使用 heightReference } - }) + }); + } + // --- 情况B:第二次点击(确定边缘/半径) --- + else { + // 记录边缘点(虽然圆只需要圆心和半径,但记录下来方便后续处理) + this.drawingPoints.push(position); + activeCursorPosition = null; // 停止动态更新 + + // 传递边缘点位置去结束绘制 + this.finishCircleDrawing(position); } } - }, Cesium.ScreenSpaceEventType.MOUSE_MOVE) + }, Cesium.ScreenSpaceEventType.LEFT_CLICK); + // 4. 右键取消 this.drawingHandler.setInputAction(() => { - if (centerPosition && radius > 0) { - this.finishCircleDrawing(centerPosition, radius) - centerPosition = null - radius = 0 - } - }, Cesium.ScreenSpaceEventType.LEFT_UP) - - // 右键取消 - // this.drawingHandler.setInputAction(() => { - // this.cancelDrawing() - // }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) + this.cancelDrawing(); + }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }, - finishCircleDrawing(center, radius) { - const positions = this.calculateCircle(center, radius, 64) - const entity = this.addCircleEntity(center, radius, positions) + finishCircleDrawing(edgePosition) { + const centerPoint = this.drawingPoints[0]; + + // 1. 计算最终半径 + const radius = Cesium.Cartesian3.distance(centerPoint, edgePosition); + + // 2. 移除动态预览实体 + if (this.tempEntity) { + this.viewer.entities.remove(this.tempEntity); + this.tempEntity = null; + } - // 计算面积 - const area = Math.PI * radius * radius + // 3. 创建最终显示的静态实体 + const finalEntity = this.viewer.entities.add({ + id: 'circle-' + new Date().getTime(), + position: centerPoint, + ellipse: { + semiMajorAxis: radius, + semiMinorAxis: radius, + material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), + outline: true, + outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), + outlineWidth: 2 + } + }); + + // 4. 记录实体 + this.allEntities.push(finalEntity); + + // 5. 计算面积 (π * r²) 并显示 + // 半径单位是米,面积单位是平方米 + const area = Math.PI * Math.pow(radius, 2); + this.measurementResult = { + radius: radius, // 也可以额外显示半径 area: area, - radius: radius, type: 'circle' - } + }; - this.stopDrawing() - return entity - }, - - cancelDrawing() { - this.stopDrawing() - this.drawingMode = null + // 6. 结束绘制状态 + this.stopDrawing(); }, // ================== 实体创建方法 ================== @@ -1522,3 +1718,5 @@ export default { } } + + From 41feed779c88effa8b80f97d2f2e85b9c075521c Mon Sep 17 00:00:00 2001 From: ctw <1051735452@qq.com> Date: Mon, 19 Jan 2026 13:13:50 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=83=BD=E5=A4=9F?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E7=9F=A9=E5=BD=A2=E5=92=8C=E5=9C=86=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/src/views/cesiumMap/index.vue | 179 +++++++++++++++------------------ 1 file changed, 83 insertions(+), 96 deletions(-) diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue index 123c394..48b73c1 100644 --- a/ruoyi-ui/src/views/cesiumMap/index.vue +++ b/ruoyi-ui/src/views/cesiumMap/index.vue @@ -1092,88 +1092,53 @@ export default { }, addRectangleEntity(coordinates) { - this.entityCounter++ - const id = `rectangle_${this.entityCounter}` - - const entity = this.viewer.entities.add({ - id: id, - name: `矩形 ${this.entityCounter}`, - rectangle: { - coordinates: coordinates, - material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color) - .withAlpha(this.defaultStyles.rectangle.opacity), - outline: true, - outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color), - outlineWidth: this.defaultStyles.rectangle.width - } - }) - - const entityData = { - id, - type: 'rectangle', - coordinates: coordinates, - entity: entity, - color: this.defaultStyles.rectangle.color, - opacity: this.defaultStyles.rectangle.opacity, - width: this.defaultStyles.rectangle.width, - label: `矩形 ${this.entityCounter}` - } - - this.allEntities.push(entityData) - - entity.clickHandler = (e) => { - this.selectEntity(entityData) - e.stopPropagation() - } - - return entityData - }, - - addCircleEntity(center, radius, positions) { - this.entityCounter++ - const id = `circle_${this.entityCounter}` - - const entity = this.viewer.entities.add({ - id: id, - name: `圆形 ${this.entityCounter}`, - polygon: { - hierarchy: new Cesium.PolygonHierarchy(positions), - material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color) - .withAlpha(this.defaultStyles.circle.opacity), - outline: true, - outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color), - outlineWidth: this.defaultStyles.circle.width - }, - position: center, - point: { - pixelSize: 5, - color: Cesium.Color.RED - } - }) - - const centerLL = this.cartesianToLatLng(center) - const entityData = { - id, - type: 'circle', - center: centerLL, - radius: radius, - positions: positions, - entity: entity, - color: this.defaultStyles.circle.color, - opacity: this.defaultStyles.circle.opacity, - width: this.defaultStyles.circle.width, - label: `圆形 ${this.entityCounter}` - } - - this.allEntities.push(entityData) + this.entityCounter++ + const id = `rectangle_${this.entityCounter}` + + const entity = this.viewer.entities.add({ + id: id, + name: `矩形 ${this.entityCounter}`, + rectangle: { + coordinates: coordinates, + material: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color) + .withAlpha(this.defaultStyles.rectangle.opacity), + outline: true, + outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.rectangle.color), + outlineWidth: this.defaultStyles.rectangle.width + } + }) + + // 【重要修改】直接把 entity 推入数组,修复清除功能的 bug + this.allEntities.push(entity) + + return entity +}, + addCircleEntity(center, radius) { + this.entityCounter++ + const id = `circle_${this.entityCounter}` + + const entity = this.viewer.entities.add({ + id: id, + name: `圆形 ${this.entityCounter}`, + position: center, // 圆心位置 + + // 【优化】使用 ellipse (椭圆) 绘制圆形 + ellipse: { + semiMinorAxis: radius, // 半短轴 = 半径 + semiMajorAxis: radius, // 半长轴 = 半径 + material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color) + .withAlpha(this.defaultStyles.circle.opacity), + outline: true, + outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color), + outlineWidth: this.defaultStyles.circle.width + } + }) - entity.clickHandler = (e) => { - this.selectEntity(entityData) - e.stopPropagation() - } + // 【重要修改】直接把 entity 推入数组 + this.allEntities.push(entity) - return entityData - }, + return entity +}, // ================== 工具方法 ================== @@ -1352,25 +1317,47 @@ export default { }, clearAll() { - // 停止绘制 - this.stopDrawing() - this.drawingMode = null - - // 移除所有实体 - this.allEntities.forEach(entity => { - if (entity.entity) { - this.viewer.entities.remove(entity.entity) + // 1. 检查数组是否有内容 + if (this.allEntities && this.allEntities.length > 0) { + + // 2. 遍历每一个对象进行删除 + this.allEntities.forEach(item => { + try { + // 情况 A: 数组里存的是原生的 Cesium Entity (点、线通常是这种情况) + if (item instanceof Cesium.Entity) { + this.viewer.entities.remove(item); } - }) + // 情况 B: 数组里存的是包装对象 (你的矩形、圆可能是这种 { entity: ... }) + else if (item.entity && item.entity instanceof Cesium.Entity) { + this.viewer.entities.remove(item.entity); + } + // 情况 C: 兜底方案,尝试通过 ID 删除 + else if (item.id) { + this.viewer.entities.removeById(item.id); + } + } catch (e) { + console.warn('删除实体失败:', e); + } + }); + } - // 清空数组 - this.allEntities = [] - this.entityCounter = 0 - this.selectedEntity = null - this.measurementResult = null + // 3. 清空数组 + this.allEntities = []; - console.log('已清除所有图形') - }, + // 4. 清理可能残留的绘制过程中的临时图形 + if (this.tempEntity) { + this.viewer.entities.remove(this.tempEntity); + this.tempEntity = null; + } + if (this.tempPreviewEntity) { + this.viewer.entities.remove(this.tempPreviewEntity); + this.tempPreviewEntity = null; + } + + // 5. 重置其他状态(如测量面板、绘制状态) + this.measurementResult = null; + this.stopDrawing(); +}, // ================== 其他方法 ================== From d9ebcfbffe86647f9a5edbae49bbbe9c4e317a05 Mon Sep 17 00:00:00 2001 From: ctw <1051735452@qq.com> Date: Mon, 19 Jan 2026 16:06:02 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=BB=8F=E7=BA=AC?= =?UTF-8?q?=E5=BA=A6=E5=AE=9A=E4=BD=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/src/views/cesiumMap/index.vue | 153 ++++++- ruoyi-ui/src/views/dialogs/OnlineMembersDialog.vue | 486 +++++++++++++++++++++ ruoyi-ui/src/views/dialogs/PlatformEditDialog.vue | 295 +++++++++++++ ruoyi-ui/src/views/dialogs/RouteEditDialog.vue | 229 ++++++++++ ruoyi-ui/src/views/dialogs/WaypointEditDialog.vue | 227 ++++++++++ 5 files changed, 1367 insertions(+), 23 deletions(-) create mode 100644 ruoyi-ui/src/views/dialogs/OnlineMembersDialog.vue create mode 100644 ruoyi-ui/src/views/dialogs/PlatformEditDialog.vue create mode 100644 ruoyi-ui/src/views/dialogs/RouteEditDialog.vue create mode 100644 ruoyi-ui/src/views/dialogs/WaypointEditDialog.vue diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue index 48b73c1..309ef03 100644 --- a/ruoyi-ui/src/views/cesiumMap/index.vue +++ b/ruoyi-ui/src/views/cesiumMap/index.vue @@ -11,6 +11,26 @@ --> +