diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue index 0f69877..6087fa6 100644 --- a/ruoyi-ui/src/views/cesiumMap/index.vue +++ b/ruoyi-ui/src/views/cesiumMap/index.vue @@ -67,6 +67,7 @@ export default { tempEntity: null, // 最终实体 tempPreviewEntity: null, // 预览实体(新增) drawingPoints: [], + drawingPointEntities: [], // 存储线绘制时的点实体 drawingStartPoint: null, isDrawing: false, activeCursorPosition: null, // 实时鼠标位置 @@ -162,6 +163,8 @@ export default { }) this.initScaleBar() + this.initPointMovement() + this.initRightClickHandler() console.log('Cesium离线二维地图已加载') } catch (error) { @@ -170,6 +173,52 @@ export default { this.showErrorMessage(); } }, + + initRightClickHandler() { + // 创建屏幕空间事件处理器 + this.rightClickHandler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas) + + // 右键点击事件:删除单个实体 + this.rightClickHandler.setInputAction((click) => { + // 如果正在绘制,不处理删除操作 + if (this.isDrawing) { + return; + } + + const pickedObject = this.viewer.scene.pick(click.position) + + if (Cesium.defined(pickedObject) && pickedObject.id) { + const pickedEntity = pickedObject.id + + // 查找对应的实体数据 + let entityData = this.allEntities.find(e => e.entity === pickedEntity || e === pickedEntity) + + // 特殊处理:如果点击的是线段上的点,找到对应的线实体 + if (!entityData) { + // 检查是否是线段上的点 + for (const lineEntity of this.allEntities) { + if (lineEntity.type === 'line' && lineEntity.pointEntities) { + if (lineEntity.pointEntities.includes(pickedEntity)) { + entityData = lineEntity + break + } + } + } + } + + if (entityData) { + // 显示确认对话框 + if (confirm('确定要删除这个对象吗?')) { + if (entityData.id) { + this.removeEntity(entityData.id) + } else if (entityData.entity && entityData.entity.id) { + this.removeEntity(entityData.entity.id) + } + } + } + } + }, Cesium.ScreenSpaceEventType.RIGHT_CLICK) + }, showErrorMessage() { const container = document.getElementById('cesiumViewer'); if (container) { @@ -347,13 +396,49 @@ export default { this.tempPreviewEntity = null; } + // 清理点实体 + if (this.drawingPointEntities) { + this.drawingPointEntities.forEach(pointEntity => { + this.viewer.entities.remove(pointEntity); + }); + this.drawingPointEntities = []; + } + this.drawingPoints = []; this.drawingStartPoint = null; this.isDrawing = false; this.activeCursorPosition = null; + // 重新初始化右键点击删除处理器 + if (!this.rightClickHandler) { + this.initRightClickHandler(); + } + this.viewer.scene.canvas.style.cursor = 'default'; }, + + cancelDrawing() { + // 取消绘制,清理临时实体和状态 + if (this.tempEntity) { + this.viewer.entities.remove(this.tempEntity); + this.tempEntity = null; + } + + if (this.tempPreviewEntity) { + this.viewer.entities.remove(this.tempPreviewEntity); + this.tempPreviewEntity = null; + } + + if (this.drawingPointEntities) { + this.drawingPointEntities.forEach(pointEntity => { + this.viewer.entities.remove(pointEntity); + }); + this.drawingPointEntities = []; + } + + this.drawingPoints = []; + this.activeCursorPosition = null; + }, // ******************************************************************** // 绘制点 startPointDrawing() { @@ -367,9 +452,9 @@ export default { }, // 绘制线 - // 绘制线 startLineDrawing() { this.drawingPoints = []; + this.drawingPointEntities = []; // 存储点实体 // 清除可能存在的旧实体 if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); @@ -377,7 +462,7 @@ export default { this.tempEntity = null; this.tempPreviewEntity = null; - // 1. 鼠标移动事件:仅更新坐标变量,不操作实体 + // 1. 鼠标移动事件:更新坐标变量 this.drawingHandler.setInputAction((movement) => { const newPosition = this.getClickPosition(movement.endPosition); if (newPosition) { @@ -391,37 +476,29 @@ export default { if (position) { this.drawingPoints.push(position); - // === 第一步:点击第一个点后,立即创建“动态虚线” === - if (this.drawingPoints.length === 1) { - this.activeCursorPosition = position; // 初始化鼠标位置 + // 创建点实体并添加到场景中 + this.entityCounter++; + const pointId = `point_${this.entityCounter}`; + const pointEntity = this.viewer.entities.add({ + id: pointId, + position: position, + point: { + pixelSize: this.defaultStyles.point.size, + color: Cesium.Color.fromCssColorString(this.defaultStyles.point.color), + outlineColor: Cesium.Color.WHITE, + outlineWidth: 2 + } + }); + this.drawingPointEntities.push(pointEntity); - // 创建预览虚线(只创建这一次,之后它会自动随数据更新) - this.tempPreviewEntity = this.viewer.entities.add({ - polyline: { - // 关键:使用 CallbackProperty 动态获取位置 - positions: new Cesium.CallbackProperty(() => { - // 只有当有点且鼠标位置存在时才渲染 - if (this.drawingPoints.length > 0 && this.activeCursorPosition) { - // 获取最后一个已确认的点 - const lastPoint = this.drawingPoints[this.drawingPoints.length - 1]; - // 返回 [最后一个点, 当前鼠标位置] - return [lastPoint, this.activeCursorPosition]; - } - return []; - }, false), - width: this.defaultStyles.line.width, - // 虚线材质 - material: new Cesium.PolylineDashMaterialProperty({ - color: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), - dashLength: 16 - }), - clampToGround: true // 贴地 - } - }); + // 移除旧的预览虚线 + if (this.tempPreviewEntity) { + this.viewer.entities.remove(this.tempPreviewEntity); + this.tempPreviewEntity = null; } - // === 第二步:点击后续点时,绘制/延长“固定实线” === - else { - // 移除旧的实线,重新画包含新点的实线 + + // 创建或更新实线 + if (this.drawingPoints.length > 1) { if (this.tempEntity) { this.viewer.entities.remove(this.tempEntity); } @@ -434,20 +511,47 @@ export default { } }); } + + // 创建新的预览虚线(使用 CallbackProperty 实现实时更新) + this.tempPreviewEntity = this.viewer.entities.add({ + polyline: { + positions: new Cesium.CallbackProperty(() => { + if (this.activeCursorPosition) { + return [this.drawingPoints[this.drawingPoints.length - 1], this.activeCursorPosition]; + } + return [this.drawingPoints[this.drawingPoints.length - 1]]; + }, false), + width: this.defaultStyles.line.width, + material: new Cesium.PolylineDashMaterialProperty({ + color: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), + dashLength: 16 + }), + clampToGround: true + } + }); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); // 3. 右键完成绘制 this.drawingHandler.setInputAction(() => { - // 完成绘制前,移除那条动态虚线 + // 移除临时实体 if (this.tempPreviewEntity) { this.viewer.entities.remove(this.tempPreviewEntity); this.tempPreviewEntity = null; } + if (this.tempEntity) { + this.viewer.entities.remove(this.tempEntity); + this.tempEntity = null; + } if (this.drawingPoints.length > 1) { this.finishLineDrawing(); } else { + // 取消绘制时,移除所有点实体 + this.drawingPointEntities.forEach(pointEntity => { + this.viewer.entities.remove(pointEntity); + }); + this.drawingPointEntities = []; this.cancelDrawing(); } @@ -466,7 +570,7 @@ export default { } // 创建最终的实线实体 - const entity = this.addLineEntity([...this.drawingPoints]); + const entity = this.addLineEntity([...this.drawingPoints], [...this.drawingPointEntities]); // 计算长度 const length = this.calculateLineLength([...this.drawingPoints]); @@ -475,11 +579,19 @@ export default { type: 'line' }; + + // 重置绘制点数组,保持绘制状态以继续绘制 this.drawingPoints = []; + this.drawingPointEntities = []; this.tempEntity = null; return entity; } else { + // 取消绘制时,移除所有点实体 + this.drawingPointEntities.forEach(pointEntity => { + this.viewer.entities.remove(pointEntity); + }); + this.drawingPointEntities = []; this.cancelDrawing(); return null; } @@ -1548,7 +1660,7 @@ export default { return entityData }, - addLineEntity(positions) { + addLineEntity(positions, pointEntities = []) { this.entityCounter++ const id = `line_${this.entityCounter}` @@ -1569,6 +1681,7 @@ export default { points: positions.map(p => this.cartesianToLatLng(p)), positions: positions, entity: entity, + pointEntities: pointEntities, // 存储点实体 color: this.defaultStyles.line.color, width: this.defaultStyles.line.width, label: `线 ${this.entityCounter}` @@ -1823,20 +1936,39 @@ export default { }, removeEntity(id) { - const index = this.allEntities.findIndex(e => e.id === id) + // 查找对应的实体数据 + const index = this.allEntities.findIndex(e => + e.id === id || + (e.entity && e.entity.id === id) || + (e.type === 'line' && e.pointEntities && e.pointEntities.some(p => p.id === id)) + ) + if (index > -1) { const entity = this.allEntities[index] // 从地图中移除 - if (entity.entity) { + if (entity instanceof Cesium.Entity) { + // 情况 A: 直接是 Cesium Entity 对象 + this.viewer.entities.remove(entity) + } else if (entity.entity) { + // 情况 B: 包装对象,包含 entity 属性 this.viewer.entities.remove(entity.entity) } + // 移除线实体相关的点实体 + if (entity.type === 'line' && entity.pointEntities) { + entity.pointEntities.forEach(pointEntity => { + this.viewer.entities.remove(pointEntity) + }) + } + + + // 从数组中移除 this.allEntities.splice(index, 1) // 如果删除的是选中的实体,清空选中状态 - if (this.selectedEntity && this.selectedEntity.id === id) { + if (this.selectedEntity && (this.selectedEntity.id === id || (this.selectedEntity.entity && this.selectedEntity.entity.id === id))) { this.selectedEntity = null } } @@ -1861,6 +1993,13 @@ export default { else if (item.id) { this.viewer.entities.removeById(item.id); } + + // 移除线实体相关的点实体 + if (item.type === 'line' && item.pointEntities) { + item.pointEntities.forEach(pointEntity => { + this.viewer.entities.remove(pointEntity); + }); + } } catch (e) { console.warn('删除实体失败:', e); } @@ -2179,6 +2318,121 @@ export default { // ... 原有的比例尺代码保持不变 }, + initPointMovement() { + // 创建屏幕空间事件处理器 + this.pointMovementHandler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas) + + let selectedPoint = null + let selectedLineEntity = null + let pointIndex = -1 + let originalCameraController = null + let isMoving = false + + // 鼠标按下事件:选择点 + this.pointMovementHandler.setInputAction((click) => { + const pickedObject = this.viewer.scene.pick(click.position) + + if (Cesium.defined(pickedObject) && pickedObject.id) { + const pickedEntity = pickedObject.id + + // 检查是否点击了点实体 + if (pickedEntity.point) { + // 查找包含该点的线实体 + for (const lineEntity of this.allEntities) { + if (lineEntity.type === 'line' && lineEntity.pointEntities) { + const index = lineEntity.pointEntities.indexOf(pickedEntity) + if (index !== -1) { + selectedPoint = pickedEntity + selectedLineEntity = lineEntity + pointIndex = index + isMoving = true + + // 禁用相机控制器,使地图固定 + originalCameraController = this.viewer.scene.screenSpaceCameraController.enableInputs + this.viewer.scene.screenSpaceCameraController.enableInputs = false + break + } + } + } + } + } + }, Cesium.ScreenSpaceEventType.LEFT_DOWN) + + // 鼠标移动事件:移动点 + this.pointMovementHandler.setInputAction((movement) => { + if (isMoving && selectedPoint && selectedLineEntity) { + const newPosition = this.getClickPosition(movement.endPosition) + if (newPosition) { + // 更新点的位置 + selectedPoint.position = newPosition + + // 创建新的位置数组,确保 Cesium 能够检测到变化 + const newPositions = [...selectedLineEntity.positions] + newPositions[pointIndex] = newPosition + + // 移除旧的线段实体 + this.viewer.entities.remove(selectedLineEntity.entity) + + // 清除所有可能存在的重复线段 + const entitiesToRemove = [] + this.viewer.entities.values.forEach(e => { + if (e.id && e.id === selectedLineEntity.id) { + entitiesToRemove.push(e) + } + }) + entitiesToRemove.forEach(e => { + this.viewer.entities.remove(e) + }) + + // 创建新的线段实体 + const newEntity = this.viewer.entities.add({ + id: selectedLineEntity.id, + name: selectedLineEntity.label, + polyline: { + positions: newPositions, + width: selectedLineEntity.width, + material: Cesium.Color.fromCssColorString(selectedLineEntity.color), + clampToGround: true + } + }) + + // 更新线实体的引用和位置数组 + selectedLineEntity.entity = newEntity + selectedLineEntity.positions = newPositions + + // 更新点数据 + selectedLineEntity.points[pointIndex] = this.cartesianToLatLng(newPosition) + + // 重新计算距离 + const length = this.calculateLineLength(selectedLineEntity.positions) + this.measurementResult = { + distance: length, + type: 'line' + } + + // 强制刷新地图渲染 + this.viewer.scene.requestRender() + } + } + }, Cesium.ScreenSpaceEventType.MOUSE_MOVE) + + // 鼠标释放事件:结束移动 + this.pointMovementHandler.setInputAction(() => { + // 恢复相机控制器 + if (originalCameraController !== null) { + this.viewer.scene.screenSpaceCameraController.enableInputs = originalCameraController + originalCameraController = null + } + + + + isMoving = false + selectedPoint = null + selectedLineEntity = null + pointIndex = -1 + }, Cesium.ScreenSpaceEventType.LEFT_UP) + }, + updateScaleBar() { // ... 原有的比例尺更新代码保持不变 }, @@ -2187,6 +2441,16 @@ export default { this.stopDrawing() this.clearAll() + if (this.pointMovementHandler) { + this.pointMovementHandler.destroy() + this.pointMovementHandler = null + } + + if (this.rightClickHandler) { + this.rightClickHandler.destroy() + this.rightClickHandler = null + } + if (this.viewer) { this.viewer.destroy() this.viewer = null