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进行交互.