Cesium+Vue3学习教程系列(7)---使用事件派发器编写实时显示鼠标三维坐标数据、相机姿态数据功能

  • 时间:2025-11-08 22:25 作者: 来源: 阅读:0
  • 扫一扫,手机访问
摘要:本学习系列将以Cesium + Vue3 + Vite +Typescript+elementplus作为主要技术栈展开,后续会循序渐进,持续探索Cesium的高级功能,相关源码全部免费公开。 请关注文中图片右下角gzh,关注后私信“Cesium学习系列源码”,即可看到全部代码。 上篇文章里说到,在Cesium里一个 ScreenSpaceEventHandler 上同一个 ScreenSpace

本学习系列将以Cesium + Vue3 + Vite +Typescript+elementplus作为主要技术栈展开,后续会循序渐进,持续探索Cesium的高级功能,相关源码全部免费公开。 请关注文中图片右下角gzh,关注后私信“Cesium学习系列源码”,即可看到全部代码。

上篇文章里说到,在Cesium里一个 ScreenSpaceEventHandler 上同一个 ScreenSpaceEventType 只能同时挂一个回调。实时获取鼠标三维坐标数据会与上标绘、测量等功能的MouseMove事件可能会有冲突,本篇采用事件派发器统一管理Cesium事件,实时显示鼠标三维坐标数据、实时显示相机姿态数据。

1、编写EventDispatcher类

import { DrawEventType } from "../Common/enums";
/**
 * 事件总线管理,事件派发器:负责管理画笔/编辑相关事件的订阅、撤销与派发。
 */
export default class EventDispatcher {
    /** 监听器池,按事件类型存储多个回调函数 */
    listeners: Map<DrawEventType, Set<EventListener>>;
    constructor() {
        // 初始化时,预置所有支持的事件类型,避免运行时动态添加
        this.listeners = new Map([
            [ DRAWSTART , new Set()],
            [ DRAWUPDATE , new Set()],
            [ DRAWEND ,   new Set()],
            [ EDITSTART , new Set()],
            [ EDITEND ,   new Set()],
            [ MOUSEMOVE ,  new Set()],
            [ WHEEL ,  new Set()],
        ]);
    }
    /**
     * 注册事件监听器
     * @param event   事件类型,必须是预置的 DrawEventType 之一
     * @param listener 回调函数,事件触发时会收到 eventData
     */
    on(event: DrawEventType, listener: EventListener) {
        if (!this.listeners.has(event)) {
            console.warn("事件类型必须是 DRAWSTART ,  DRAWUPDATE ,  DRAWEND ,  EDITSTART ,  EDITEND ,  MOUSEMOVE ,  WHEEL 之一");
            return;
        }
        this.listeners.get(event)?.add(listener);
    }
    /**
     * 移除事件监听器
     * @param event   事件类型
     * @param listener 之前注册过的回调函数引用
     */
    off(event: DrawEventType, listener: EventListener) {
        if (this.listeners.has(event)) {
            this.listeners.get(event)?.delete(listener);
        }
    }
    /**
     * 派发(触发)指定事件
     * @param event     事件类型
     * @param eventData 随事件携带的任意数据,会透传给所有监听器
     */
    dispatchEvent(event: DrawEventType, eventData?: any) {
        if (this.listeners.has(event)) {
            this.listeners.get(event)?.forEach((listener) => {
                listener(eventData);
            });
        }
    }
     /** 一次性监听 */
    once(event: DrawEventType, listener: EventListener) {
        const wrap: EventListener = (data) => {
            this.off(event, wrap);
            listener(data);
        };
        this.on(event, wrap);
    }
    /** 清空某类事件 */
    clear(event: DrawEventType) {
        this.listeners.get(event)?.clear();
    }
}

2、新建MouseInfoPickerInViewer,用于绑定事件派发的鼠标动作,并拿到回调的数据。

import EventDispatcher from "@/system/EventDispatcher/EventDispatcher";
import { Cartographic, ScreenSpaceEventHandler, ScreenSpaceEventType, Viewer } from "cesium";
export default class MouseInfoPickerInViewer {
    private handler: ScreenSpaceEventHandler;
    private dispatcher = new EventDispatcher();
    private viewer: Viewer;
    constructor(viewer: Viewer) {
        this.viewer = viewer;
        this.handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
        this.bindMouseMove();
        this.bindWheel();
    }
    /** 外部订阅:鼠标移动 */
    onMouseMove(cb: (coords: Cartographic) => void) {
        // Wrap the callback to match EventListener signature
        const wrapper = (evt: any) => cb(evt as Cartographic);
        this.dispatcher.on( MOUSEMOVE , wrapper);        
        // Return a function to remove the wrapper
        return () => this.dispatcher.off( MOUSEMOVE , wrapper); // 返回撤销函数
    }
    onMouseWheel(cb: (h: number) => void) {
        // Wrap the callback to match EventListener signature
        const wrapper = (evt: any) => cb(evt as number);
        this.dispatcher.on( WHEEL , wrapper);        
        // Return a function to remove the wrapper
        return () => this.dispatcher.off( WHEEL , wrapper); // 返回撤销函数
    }
    private bindMouseMove() {
        this.handler.setInputAction((movement: any) => {
            // 获取鼠标在屏幕上的位置
            const screenPosition = movement.endPosition
            // 将屏幕位置转换为经纬度
            const cartesian = this.viewer.scene.globe.pick(this.viewer.camera.getPickRay(screenPosition)!, this.viewer.scene)
            // const cartesian = viewer.camera.pickEllipsoid(movement.endPosition,CesiumViewer.ellipsoid)
            if (cartesian) {
                const cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian)
                this.dispatcher.dispatchEvent( MOUSEMOVE , cartographic)
            }
        }, ScreenSpaceEventType.MOUSE_MOVE);
    }
    private bindWheel() {
        this.handler.setInputAction(() => {
            this.dispatcher.dispatchEvent( WHEEL , this.viewer.camera.positionCartographic.height)
        }, ScreenSpaceEventType.WHEEL);
    }
    destroy() {
        this.handler.destroy()
        this.dispatcher.clear( MOUSEMOVE )
        this.dispatcher.clear( WHEEL )
    }
}

3、然后调用MouseInfoPickerInViewer里的onMouseMove和onMouseWheel即可

 
const picker = new MouseInfoPickerInViewer(viewer);
        picker.onMouseMove((cartographic) => {
             //鼠标位置
            MouseStatusInViewer.longtitude.value = Cesium.Math.toDegrees(cartographic?.longitude ?? 0)
            MouseStatusInViewer.latitude.value = Cesium.Math.toDegrees(cartographic?.latitude ?? 0)
            MouseStatusInViewer.altitude.value = viewer.scene.globe.getHeight(cartographic) ?? 0
            //相机信息
            MouseStatusInViewer.heading.value = Cesium.Math.toDegrees(viewer.camera.heading ?? 0)
            MouseStatusInViewer.pitch.value = Cesium.Math.toDegrees(viewer.camera.pitch ?? 0)
            MouseStatusInViewer.roll.value = Cesium.Math.toDegrees(viewer.camera.roll ?? 0)
            
        });
        picker.onMouseWheel((h) => {
            MouseStatusInViewer.cameraHeight.value = h
        })

4、实现效果


Cesium+Vue3学习教程系列(7)---使用事件派发器编写实时显示鼠标三维坐标数据、相机姿态数据功能

  • 全部评论(0)
手机二维码手机访问领取大礼包
返回顶部