|
|
|
@ -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 |
|
|
|
|