vue3 + ts + cesium:绘制、更新折线 polyline

本文主要实现最基础的绘制折线,并且可以拖动线上的点实时更新线条。

实现效果:

    (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
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值