本文主要实现最基础的绘制折线,并且可以拖动线上的点实时更新线条。
实现效果:
(1)单击鼠标左键绘制折线、选中线条;
(2)单击鼠标右键结束绘制折线、结束更新线条(此时不会显示线上的点);
(3)长按鼠标左键拖动线上的点,实时更新线条;
(4)抬起鼠标左键停止拖动线上的点。
1. components / CesiumViewer / hooks / drawPolyline.ts
import * as Cesium from "cesium";
import {
disableDefaultScreenSpaceEventHandlers,
enableDefaultScreenSpaceEventHandlers
} from "@/components/CesiumViewer/hooks/utils";
export const drawPolyline = () => {
const handler = new Cesium.ScreenSpaceEventHandler(window.viewer.scene.canvas)
let isDrawing = true // 是否处于绘制状态
let positions: any[] = [] // 当前绘制的线上的点的坐标
let points: any[] = [] // 当前绘制的线上的点的实体
let polylinePositions: any[] = [] // 选中的线条的位置
let pickedPolyline: any = null // 选中的线条
let polylinePoints: any[] = [] // 选中的线条的点实体
// 单击左键 —— 绘制线 / 选中线
handler.setInputAction((event: any) => {
const pickedObject = window.viewer.scene.pick(event.position) // 拾取实体
if (Cesium.defined(pickedObject) && pickedObject.id && pickedObject.id.polyline && !isDrawing) { // 选中线
pickedPolyline = pickedObject.id.polyline
polylinePositions = pickedObject.id.polyline.positions.getValue(Cesium.JulianDate.now()) // 获取线条实体的位置
polylinePositions.forEach((position: any) => { // 显示线上的点
const polylinePoint = window.viewer.entities.add({
position: position,
point: {
pixelSize: 10, /* 点的大小 */
color: Cesium.Color.fromCssColorString('#ffff00'), /* 点的颜色 */
/* 根据视角远近控制点的比例 */
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 8.0e6, 0.0),
heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND
}
})
polylinePoints.push(polylinePoint) // 暂存选中的线的点实体
})
} else { // 绘制线
const cartesian = window.viewer.camera.pickEllipsoid(event.position, window.viewer.scene.globe.ellipsoid) // 拾取坐标
if (Cesium.defined(cartesian) && isDrawing) {
const point = window.viewer.entities.add({ // 添加线上的点
position: cartesian,
point: {
pixelSize: 10, /* 点的大小 */
color: Cesium.Color.fromCssColorString('#ffff00'), /* 点的颜色 */
/* 根据视角远近控制点的比例 */
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 8.0e6, 0.0),
heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND
}
})
positions.push(cartesian) // 暂存点坐标
points.push(point) // 暂存点实体
if (positions.length > 1) {
window.viewer.entities.add({
polyline: {
positions: new Cesium.CallbackProperty(() => {
return positions
}, false),
width: 5, /* 线的宽度 */
// 普通实线
material: Cesium.Color.fromCssColorString('#ff0000'), /* 线的颜色 */
/*// 虚线
material: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.fromCssColorString('#ff0000'),
// gapColor: Cesium.Color.TRANSPARENT, /!* 间隔颜色 *!/
dashLength: 20 /!* 短划线长度 *!/
}),*/
/*// 发光线条
material: new Cesium.PolylineGlowMaterialProperty({
glowPower: 0.3,
color: Cesium.Color.fromCssColorString('#ff0000')
}),*/
clampToGround: true, /* 贴地 */
}
})
}
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 单击右键 —— 结束绘制 / 结束更新线条
handler.setInputAction(() => {
isDrawing = false // 结束绘制
points.forEach((point: any) => {
window.viewer.entities.remove(point) // 移除线上的点
})
if (polylinePoints.length > 0) {
polylinePoints.forEach((item: any) => {
window.viewer.entities.remove(item) // 结束更新线条,移除线上的点
})
polylinePoints = []
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
// 长按左键 —— 拖动线上的点
handler.setInputAction((event: any) => {
const pickedObject = window.viewer.scene.pick(event.position)
if (Cesium.defined(pickedObject) && pickedObject.id && pickedObject.id.point) {
const pickedPointPosition = pickedObject.id.position.getValue(Cesium.JulianDate.now()) // 被选择拖动的点的位置
// 当前更新的线上的点的位置的索引
const index = polylinePositions.findIndex((item: any) => item.x === pickedPointPosition.x && item.y === pickedPointPosition.y && item.z === pickedPointPosition.z)
disableDefaultScreenSpaceEventHandlers() // 拖动点时禁止屏幕移动
handler.setInputAction((movement: any) => {
const newPosition = window.viewer.camera.pickEllipsoid(movement.endPosition, window.viewer.scene.globe.ellipsoid)
if (Cesium.defined(newPosition)) {
pickedObject.id.position = new Cesium.CallbackProperty(() => {
return newPosition
}, false)
polylinePositions[index] = newPosition // 更新线上这个点的位置
pickedPolyline.positions = new Cesium.CallbackProperty(() => { // 动态更新线的位置
return polylinePositions
}, false)
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
// 抬起左键 —— 停止拖动点
handler.setInputAction(() => {
handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE) // 清除鼠标移动事件,停止拖动点
enableDefaultScreenSpaceEventHandlers() // 拖动完成,允许屏幕移动
}, Cesium.ScreenSpaceEventType.LEFT_UP)
}
2. components / CesiumViewer / hooks / utils.ts
// 保持地球不动
export function disableDefaultScreenSpaceEventHandlers() {
window.viewer.scene.screenSpaceCameraController.enableRotate = false // 禁止旋转
window.viewer.scene.screenSpaceCameraController.enableTranslate = false // 禁止平移
window.viewer.scene.screenSpaceCameraController.enableZoom = false // 禁止缩放
window.viewer.scene.screenSpaceCameraController.enableTilt = false // 禁止倾斜
window.viewer.scene.screenSpaceCameraController.enableLook = false // 禁止观察(自由视角查看)
}
// 允许地球移动
export function enableDefaultScreenSpaceEventHandlers() {
window.viewer.scene.screenSpaceCameraController.enableRotate = true
window.viewer.scene.screenSpaceCameraController.enableTranslate = true
window.viewer.scene.screenSpaceCameraController.enableZoom = true
window.viewer.scene.screenSpaceCameraController.enableTilt = true
window.viewer.scene.screenSpaceCameraController.enableLook = true
}