优雅永不过时 基于Cesium搭建的sdk 1: 事件管理

Ceisum是一个庞大的三维js库, 为了项目可以快速开发, 我们可以把项目封装成sdk. 可以让项目在公司易于迭代, Cesium上手有一定的难度, 团队并不是每个成员都会cesium. 所以我们要对cesium 进行功能封装.

首先我们看看事件管理器工具 EventDispatcher

/**
 * https://github.com/mrdoob/eventdispatcher.js/
 */

function EventDispatcher () {}

Object.assign(EventDispatcher.prototype, {

    /**
	 * 添加监听器
	 * @param type{string} 监听器类型
	 * @param listener{function} 方法
	 * @param mutexStatus{boolean} 互斥开关
	 */
    addEventListener: function (type, listener, mutexStatus = false) {
        if (this._listeners === undefined) this._listeners = {}
        this._mutex = this._mutex || {}
        const mutex = this._mutex
        var listeners = this._listeners

        if (listeners[type] === undefined) {
            listeners[type] = []
        }

        if (listeners[type].indexOf(listener) === -1) {
            // 如果启用功能互斥
            if (mutexStatus) {
                mutex[type] = listener
            }
            listeners[type].push(listener)
        }
    },

    hasEventListener: function (type, listener) {
        if (this._listeners === undefined) return false

        var listeners = this._listeners

        return listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1
    },

    removeEventListener: function (type, listener) {
        if (this._listeners === undefined) return

        var listeners = this._listeners
        var listenerArray = listeners[type]

        // 移除指定的功能互斥
        if (this._mutex[type] === listener) {
            this._mutex[type] = null
        }

        if (listenerArray !== undefined) {
            var index = listenerArray.indexOf(listener)

            if (index !== -1) {
                listenerArray.splice(index, 1)
            }
        }
    },

    /**
	 * 派发事件
	 * @param event{{type: string, message?: *}}
	 */
    dispatchEvent: function (event) {
        if (this._listeners === undefined) return

        var listeners = this._listeners
        var listenerArray = listeners[event.type]

        if (listenerArray !== undefined) {
            event.target = this

            // Make a copy, in case listeners are removed while iterating.
            var array = listenerArray.slice(0)
            if (this._mutex[event.type]){
                const find = array.find(item => item === this._mutex[event.type])
                find.call(this, event)
                console.log(' 事件互斥已启动')
                return
            }
            for (var i = 0, l = array.length; i < l; i++) {
                array[i].call(this, event)
            }
        }
    },

    removeAllListener () {
        this._mutex = {}
        for (const key in this._listeners) {
            this._listeners[key] = []
        }
    }

})

export { EventDispatcher }

这个类较为简单, 是three上带的, 我拿过来用了, 做了个小小的更改 addEventListener时, 我增加了一个事件独占,
独占时, 事件不会派发到其他地方. 我们在单击事件, 需要单独执行, 不希望触发其他点击事件时,
可以设置这个属性为true.这样就不会触发其他事件了.

事件管理器

import { EventDispatcher } from '../message/EventDispatcher.js'
import EventConstant from '../constant/EventConstant.js'

export default class EventManager extends EventDispatcher {
    /**
     * 视图对象
     * @type {Viewer}
     */
    viewer = null

    /**
     * 事件处理器
     * @type{Cesium.ScreenSpaceEventHandler}
     */
    handler = null

    /**
     * 按下左键
     * @type {boolean}
     */
    press = false

    /**
     * 创建事件管理工具
     * @param viewer
     */
    constructor (viewer) {
        super()
        this.viewer = viewer

        // 创建事件管理器
        this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.baseViewer.scene.canvas)

        // 派发左键单击事件
        this.handler.setInputAction((e) => {
            this.dispatchEvent({
                type: EventConstant.CLICK,
                message: e
            })
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

        // 左键按下事件
        this.handler.setInputAction((e) => {
            this.press = true
            this.dispatchEvent({
                type: EventConstant.LEFT_DOWN,
                message: e
            })
        }, Cesium.ScreenSpaceEventType.LEFT_DOWN)

        // 右键按下事件
        this.handler.setInputAction((e) => {
            this.press = false
            this.dispatchEvent({
                type: EventConstant.LEFT_UP,
                message: e
            })
        }, Cesium.ScreenSpaceEventType.LEFT_UP)

        // 派发右键单击事件
        this.handler.setInputAction((e) => {
            this.dispatchEvent({
                type: EventConstant.RIGHT_CLICK,
                message: e
            })
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)

        // 鼠标移动事件
        this.handler.setInputAction((e) => {
            // 左键按下移动事件
            if(this.press) {
                this.dispatchEvent({
                    type: EventConstant.LEFT_DOWN_MOUSE_MOVE,
                    message: e
                })
            }
            this.dispatchEvent({
                type: EventConstant.MOUSE_MOVE,
                message: e
            })
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

        // 派发渲染事件
        this.viewer.baseViewer.scene.postRender.addEventListener((e, time) => {
            TWEEN && TWEEN.update()
            this.viewer.stats && this.viewer.stats.update()
            this.dispatchEvent({
                type: EventConstant.RENDER,
                message: {
                    scene: e,
                    time: time
                }
            })
        })

        // 键盘抬起事件
        document.addEventListener(EventConstant.KEYUP, (e) => {
            this.dispatchEvent({
                type: EventConstant.KEYUP,
                message: {
                    e: e
                }
            })
        })

        // 键盘按下事件
        document.addEventListener(EventConstant.KEYDOWN, (e) => {
            this.dispatchEvent({
                type: EventConstant.KEYDOWN,
                message: {
                    e: e
                }
            })
        })
    }

    /**
     * 添加相机位置监听方法
     * @param fn{Function} 监听方法
     */
    addCameraMoveListener (fn) {
        this.viewer.baseViewer.camera.changed.addEventListener(fn)
    }

    /**
     * 移除相机位置监听
     * @param fn{Function} 监听方法
     */
    removeCameraMoveListener (fn) {
        this.viewer.baseViewer.camera.changed.removeEventListener(fn)
    }
}

我们用创建的事件管理器集成EventDispatcher, 把常见的事件封装在功能里. 这样我们可以方便的做很多针对项目的处理, 比如press属性. 就是左键按下时的. 依托于这个属性, 还有一个 左键按下移动事件, 这样我们做拖拽功能就很轻松了, 当然 我们要把事件 单独创建一个对象, EventConstant, 不为其他, 只为优雅.
使用:

this.viewer.eventManager.addEventListener(EventConstant.LEFT_DOWN, this._clickListener, true)
this.viewer.eventManager.removeEventListener(EventConstant.LEFT_DOWN, this._clickListener)

中间我们有一个viewer的对象, 我在cesium的viewer的基础上, 套了一层里面会有一些我们设计的其他基础组件, 可以方便一些组件的功能交互. 比如事件管理, 我们就通过viewer进行交互.

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值