const drawActive = ref(false)
interface CesiumDrawGetData {
degrees: number[];
index: number;
}
const pointData = ref<Array<CesiumDrawGetData>>([]); //存储坐标数据
const index = ref<number>(0); //当前点的索引
const pickEntity = shallowRef<Cesium.Entity>(); //当前点击的实体
const polylinePositions = ref<Array<Cesium.Cartesian3>>([]) // 存储线的位置
const points = ref<Array<Cesium.Entity>>([]) // 存储点的实体
const polylines = ref<Array<Cesium.Entity>>([]) // 存储线的实体
const isDrawing = ref(false) // 是否处于绘制状态
// 在组件作用域定义 handler 引用
let handler: Cesium.ScreenSpaceEventHandler | null = null;
// 保持地球不动
function disableDefaultScreenSpaceEventHandlers() {
viewer.value.scene.screenSpaceCameraController.enableRotate = false // 禁止旋转
viewer.value.scene.screenSpaceCameraController.enableTranslate = false // 禁止平移
viewer.value.scene.screenSpaceCameraController.enableZoom = false // 禁止缩放
viewer.value.scene.screenSpaceCameraController.enableTilt = false // 禁止倾斜
viewer.value.scene.screenSpaceCameraController.enableLook = false // 禁止观察(自由视角查看)
}
// 允许地球移动
function enableDefaultScreenSpaceEventHandlers() {
viewer.value.scene.screenSpaceCameraController.enableRotate = true
viewer.value.scene.screenSpaceCameraController.enableTranslate = true
viewer.value.scene.screenSpaceCameraController.enableZoom = true
viewer.value.scene.screenSpaceCameraController.enableTilt = true
viewer.value.scene.screenSpaceCameraController.enableLook = true
}
// 创建点
function createPoint(dataItem: CesiumDrawGetData) {
const point = viewer.value!.entities.add({
id: String(dataItem.index),
name: "point",
pointData: pointData.value,
position: Cesium.Cartesian3.fromDegrees(dataItem.degrees[0], dataItem.degrees[1], dataItem.degrees[2]),
point: {
pixelSize: 5,
color: Cesium.Color.fromCssColorString('#ffff00'),
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 8.0e6, 0.0),
heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND
}
});
points.value.push(point);
return point;
}
// 创建线
function createPolyline(dataItem: CesiumDrawGetData) {
const polyline = viewer.value!.entities.add({
id: String(dataItem.index + 10),
polyline: {
positions: new Cesium.CallbackProperty(() => polylinePositions.value, false),
width: 5,
material: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.fromCssColorString('#4cd70e'),
dashLength: 20
}),
clampToGround: true
}
});
polylines.value.push(polyline);
return polyline;
}
const drawPolyline = () => {
// 如果已经激活,关闭绘制
if (drawActive.value && !pointStore.editingObject) {
drawActive.value = false;
if (handler && !handler.isDestroyed()) {
handler.destroy(); // 彻底销毁旧处理器
handler = null;
}
enableDefaultScreenSpaceEventHandlers();
return;
}
//再次点击按钮,清除之前的线和点
pointData.value = []
polylinePositions.value = []
points.value = []
index.value = 0
viewer.value.entities.removeAll()
viewer.value.scene.requestRender()
handler = new Cesium.ScreenSpaceEventHandler(viewer.value.scene.canvas);
isDrawing.value = true // 是否处于绘制状态
drawActive.value = true
// 单击左键 —— 绘制线 / 选中线
handler.setInputAction(
(click: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
const pick = viewer.value?.scene.pick(click.position);
if ((!pick || pick.id.isStatic) && isDrawing) {
// 获取点击位置笛卡尔坐标
const cartesian = viewer.value?.camera.pickEllipsoid(
click.position,
viewer.value?.scene.globe.ellipsoid
);
// 获取点击位置的经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian(cartesian!);
const longitude = Number(
Cesium.Math.toDegrees(cartographic.longitude).toFixed(6)
);
const latitude = Number(
Cesium.Math.toDegrees(cartographic.latitude).toFixed(6)
);
// 画点
pointData.value.push({
degrees: [longitude, latitude, 10],
index: index.value,
});
const pointEnt = {
degrees: [longitude, latitude, 10],
index: index.value,
}
createPoint(pointEnt)
// 画线
polylinePositions.value.push(cartesian!.clone());
createPolyline(pointEnt)
index.value += 1;
}
},
Cesium.ScreenSpaceEventType.LEFT_CLICK
);
// 单击右键 —— 结束绘制 / 结束更新线条
handler.setInputAction(() => {
isDrawing.value = false // 结束绘制
drawActive.value = false // 停止绘制
points.value.forEach((point) => {
viewer.value.entities.remove(point) // 移除线上的点
})
// 鼠标抬起重新渲染 非常重要
viewer.value?.scene.requestRender();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
// 长按左键 —— 拖动线上的点
handler.setInputAction((event: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
const pickedObject = viewer.value?.scene.pick(event.position);
if (
pickedObject &&
pickedObject.id &&
pickedObject.id.name !== "polygon" &&
pickedObject.id.name !== "polyline" &&
pickedObject.id.name !== "areaLine" &&
pickedObject.id.name !== "area" &&
pickedObject.id.name !== undefined
) {
// 点击点
pickEntity.value = pickedObject.id;
disableDefaultScreenSpaceEventHandlers()
} else {
pickEntity.value = undefined;
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
// 抬起左键 —— 停止拖动点
handler.setInputAction(() => {
pickEntity.value = undefined;
// handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE) // 清除鼠标移动事件,停止拖动点
enableDefaultScreenSpaceEventHandlers() // 拖动完成,允许屏幕移动
viewer.value?.scene.requestRender();
}, Cesium.ScreenSpaceEventType.LEFT_UP)
// 鼠标移入事件
handler.setInputAction((event: Cesium.ScreenSpaceEventHandler.MotionEvent) => {
// 获取地图上的点位实体(entity)坐标
const pickedObject = viewer.value?.scene.pick(event.endPosition);
if (
pickedObject &&
pickedObject.id &&
pickedObject.id.name !== "polygon" &&
pickedObject.id.name !== "polyline" &&
pickedObject.id.name !== "areaLine" &&
pickedObject.id.name !== "area" &&
pickedObject.id.name !== undefined
) {
viewer.value._container.style.cursor = "pointer";
} else {
// 移除弹框
viewer.value._container.style.cursor = "default";
const tipsEl = document.getElementById("cesium-tips") as HTMLElement;
if (tipsEl) {
tipsEl.style.display = "none";
}
if (pickEntity.value) {
// 获取点位实体的坐标
const index = Number(pickEntity.value.id);
const cartesian = getCartesian(event.endPosition);
const degrees = getDegreesFromCartesian3(cartesian!);
// 修改坐标
pointData.value[index].degrees = [...degrees, 10];
// 更新点位置
const point = viewer.value!.entities.getById(String(index))!;
point.position = getCartesian3FromDegrees(degrees, 10);
// 更新线的位置
polylinePositions.value[index] = cartesian!;
// 鼠标抬起重新渲染 非常重要
viewer.value?.scene.requestRender();
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
/**
* @description 获取笛卡尔坐标
*/
const getCartesian = (position: Cesium.Cartesian2) => {
const cartesian = viewer.value!.camera.pickEllipsoid(
position,
viewer.value!.scene.globe.ellipsoid
);
return cartesian;
};
/**
* @description 根据笛卡尔坐标获取经纬度
* @param {Cesium.Cartesian3} cartesian
* @return {*}
*/
const getDegreesFromCartesian3 = (cartesian: Cesium.Cartesian3) => {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Number(
Cesium.Math.toDegrees(cartographic.longitude).toFixed(6)
);
const latitude = Number(
Cesium.Math.toDegrees(cartographic.latitude).toFixed(6)
);
return [longitude, latitude];
};
const getCartesian3FromDegrees = (
degrees: number[],
height?: number
) => {
const cartesian = Cesium.Cartesian3.fromDegrees(
degrees[0],
degrees[1],
height
);
return cartesian;
};
const clearPolyline = () => {
// 清除所有之前创建的临时线和点
viewer.value.entities.removeAll()
pointData.value = [];
index.value = 0;
// 清除屏幕空间事件处理器
if (handler && !handler.isDestroyed()) {
handler.destroy(); // 彻底销毁旧处理器
handler = null;
}
// 允许屏幕移动
enableDefaultScreenSpaceEventHandlers();
drawActive.value = false
}
//通过将数据渲染至表格进行修改线
watch(() => pointData.value, () => {
if (pointStore.editingObject) {
drawActive.value = false;
handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 使用Map优化查找性能
const pointMap = new Map(points.value.map(p => [p.id, p]));
const polylineMap = new Map(polylines.value.map(p => [p.id, p]));
// 预计算需要删除的实体
const pointsToDelete = points.value.filter(p =>
!pointData.value.some(d => String(d.index) === p.id)
);
const polylinesToDelete = polylines.value.filter(p =>
!pointData.value.some(d => String(d.index + 10) === p.id)
);
// 批量处理删除操作
pointsToDelete.forEach(p => {
viewer.value!.entities.remove(p);
points.value.splice(points.value.indexOf(p), 1);
});
polylinesToDelete.forEach(p => {
viewer.value!.entities.remove(p);
polylines.value.splice(polylines.value.indexOf(p), 1);
});
// 重构坐标更新逻辑
const newPolylinePositions: Array<Cesium.Cartesian3> = [];
pointData.value.forEach((dataItem, index) => {
// 更新点位置
const point = pointMap.get(String(dataItem.index)) || createPoint(dataItem);
point.position = getCartesian3FromDegrees(dataItem.degrees, dataItem.degrees[2]);
// 更新线位置
const polyline = polylineMap.get(String(dataItem.index + 10)) || createPolyline(dataItem);
newPolylinePositions[index] = getCartesian3FromDegrees(dataItem.degrees, dataItem.degrees[2]);
});
// 整体更新折线位置数组
polylinePositions.value = newPolylinePositions;
viewer.value?.scene.requestRender();
}
}, { deep: true });
05-29
998

02-12
1226

04-03
4202

09-17
627

09-17
04-08
330

01-04
4633
