本文主要实现最基础的绘制多边形,并且可以拖动多边形的顶点实时更新多边形的形状。
实现效果:
(1)单击鼠标左键绘制多边形、选中多边形;
(2)单击鼠标右键结束绘制、结束更新多边形(此时不会显示多边形的顶点);
(3)长按鼠标左键拖动多边形的顶点,实时更新多边形的形状;
(4)抬起鼠标左键停止拖动多边形的顶点。
1. components / CesiumViewer / hooks / drawPolygon.ts
import * as Cesium from "cesium";
import {
disableDefaultScreenSpaceEventHandlers,
enableDefaultScreenSpaceEventHandlers
} from "@/components/CesiumViewer/hooks/utils";
export const drawPolygon = () => {
const handler = new Cesium.ScreenSpaceEventHandler(window.viewer.scene.canvas)
let isDrawing = true // 是否处于绘制状态
let positions: any[] = [] // 当前绘制的多边形上的点的坐标
let points: any[] = [] // 当前绘制的多边形的点的实体
let polygonPositions: any[] = [] // 选中的多边形的位置
let pickedPolygon: any = null // 选中的多边形
let polygonPoints: any[] = [] // 选中的多边形的点实体
// 单击左键 —— 绘制多边形
handler.setInputAction((event: any) => {
const pickedObject = window.viewer.scene.pick(event.position) // 拾取实体
if (Cesium.defined(pickedObject) && pickedObject.id && pickedObject.id.polygon && !isDrawing) { // 选中多边形
pickedPolygon = pickedObject.id.polygon
polygonPositions = pickedObject.id.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions /* 获取多边形实体的位置 */
polygonPositions.forEach((item: any) => {
const polygonPoint = window.viewer.entities.add({
position: item,
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
}
})
polygonPoints.push(polygonPoint) // 暂存选中的多边形的点实体
})
} 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 > 2) { // 最少三点成面
window.viewer.entities.add({
polygon: {
hierarchy: new Cesium.CallbackProperty(() => {
return new Cesium.PolygonHierarchy(positions)
}, false),
material: Cesium.Color.fromCssColorString('#ff0000').withAlpha(0.5), /* 颜色 && 透明度 */
}
})
}
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 单击右键 —— 结束绘制 / 结束更新多边形
handler.setInputAction(() => {
isDrawing = false // 结束绘制
points.forEach((item: any) => {
window.viewer.entities.remove(item) // 移除刚刚绘制的多边形上的点
})
if (polygonPoints.length > 1) {
polygonPoints.forEach((item: any) => {
window.viewer.entities.remove(item) // 移除选中的多边形的顶点
})
polygonPoints = []
}
}, 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 = polygonPositions.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)
polygonPositions[index] = newPosition
pickedPolygon.hierarchy = new Cesium.CallbackProperty(() => { // 动态更新多边形
return new Cesium.PolygonHierarchy(polygonPositions)
}, 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
}