Cesium 地图覆盖物事件注册封装

Cesium 地图覆盖物事件注册封装

需求分析

Cesium中的事件监听支持的类型与前端主流的事件有差别(没有mouseover,mouseout等事件),封装一个较为通用的事件管理器

存在问题

  1. cesium的事件监听是通过创建一个Cesium.ScreenSpaceEventHandler对象,然后调用handler.setInputAction(callback,Cesium.ScreenSpaceEventType.*)来注册某个事件类型的回调,这种实现方式导致了在一个handler中同一个ScreenSpaceEventType只能注册一个回调。
  2. mouseover和mouseout事件都需要监听MOUSE_MOVE事件,而MOUSE_MOVE事件是注册在地图上的。假如我需要给某些覆盖物设置mouseover事件,如果注册多个handler MOUSE_MOVE那鼠标在地图上移动将触发所有MOUSE_MOVE回调,可能出现稍微动几个像素点触发数千次回调,极大的浪费计算资源。

实现

基于Cesium版本1.95
首先定义一个map记录前端事件与cesium事件的对应关系

static EVENT_MAP = {
        "click": Cesium.ScreenSpaceEventType.LEFT_CLICK,
        "dblclick": Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
        "rightclick": Cesium.ScreenSpaceEventType.RIGHT_CLICK,
        "mouseover": Cesium.ScreenSpaceEventType.MOUSE_MOVE,
        "mouseout": Cesium.ScreenSpaceEventType.MOUSE_MOVE,
        "leftdown": Cesium.ScreenSpaceEventType.LEFT_DOWN,
    }

一个<事件-覆盖物列表>的map,用于保存注册事件的覆盖物

 		
        //Map<事件, Map>
        this.eventEntityMap = {};
        //初始化Map<实体id, 实体>
        if (!this.eventEntityMap[event]) {
            this.eventEntityMap[event] = new Map();
        }
        this.eventEntityMap[event].set(overlay.getEntity().id, overlay);

初始化handler,由于Cesium对InputAction进行移除时无法指定移除对象,所以对一个handler只设置一次InputAction;当第一次注册事件时才去设置InputAction。

		this.handler = new Cesium.ScreenSpaceEventHandler(this.map.viewer.scene.canvas);
		if (!this.handler.getInputAction(EVENT_MAP[event])) {
            switch (event) {
                case 'mouseover':
                case 'mouseout':
                    this.handler.setInputAction(e => {
                        
                    }, EVENT_MAP[event])
                    break;
                default:
                    this.handler.setInputAction(e => {
                       
                    }, EVENT_MAP[event])
            }
        }

mouseover和mouseout事件注册同一个InputAction MOUSE_MOVE,在回调中获取鼠标指针上的覆盖物,触发mouseover事件,此时标记当前移入的覆盖物,如果下次MOUSE_MOVE事件未获取到该鼠标指针上的覆盖物,则触发mouseout事件

					var picked = this.map.viewer.scene.pick(e.endPosition);
                        if (Cesium.defined(picked) && picked.id) {
                            var pickedOverlay;
                            //存在上次选中实体
                            if (this.pickedId) {
                                //本次选中实体与上次选中实体不同,触发上次选中实体的mouseout事件
                                if (this.pickedId !== picked.id) {
                                    pickedOverlay = this.eventEntityMap['mouseout'].get(this.pickedId.id)
                                    if (pickedOverlay) {
                                        pickedOverlay._dispatchEvent('mouseout', e)
                                    }
                                } else {
                                    return;
                                }
                            }
                            //设置选中实体
                            this.pickedId = picked.id;
                            pickedOverlay = this.eventEntityMap['mouseover'].get(this.pickedId.id)
                            if (pickedOverlay) {
                                pickedOverlay._dispatchEvent('mouseover', e)
                            }
                        } else if (this.pickedId) {
                            pickedOverlay = this.eventEntityMap['mouseout'].get(this.pickedId.id)
                            if (pickedOverlay) {
                                pickedOverlay._dispatchEvent('mouseout', e)
                            }
                            this.pickedId = undefined;
                        }

完整代码

/**
 * 地图通用事件与cesium事件转换
 */
class CesiumEventManager {
    //支持事件
    static EVENT_MAP = {
        "click": Cesium.ScreenSpaceEventType.LEFT_CLICK,
        "dblclick": Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
        "rightclick": Cesium.ScreenSpaceEventType.RIGHT_CLICK,
        "mouseover": Cesium.ScreenSpaceEventType.MOUSE_MOVE,
        "mouseout": Cesium.ScreenSpaceEventType.MOUSE_MOVE,
        "leftdown": Cesium.ScreenSpaceEventType.LEFT_DOWN,
    }

    constructor(map) {
        this.map = map;
        this.handler = new Cesium.ScreenSpaceEventHandler(this.map.viewer.scene.canvas);
        //Map<事件, Map>
        this.eventEntityMap = {};
    }

    addEventOverlay(event, overlay) {
        //初始化Map<实体id, 实体>
        if (!this.eventEntityMap[event]) {
            this.eventEntityMap[event] = new Map();
        }
        this.eventEntityMap[event].set(overlay.getEntity().id, overlay);
        //初始化事件action
        if (!this.handler.getInputAction(CesiumEventManager.EVENT_MAP[event])) {
            switch (event) {
                case 'mouseover':
                case 'mouseout':
                    this.handler.setInputAction(e => {
                        var picked = this.map.viewer.scene.pick(e.endPosition);
                        if (Cesium.defined(picked) && picked.id) {
                            var pickedOverlay;
                            //存在上次选中实体
                            if (this.pickedId) {
                                //本次选中实体与上次选中实体不同,触发上次选中实体的mouseout事件
                                if (this.pickedId !== picked.id) {
                                    pickedOverlay = this.eventEntityMap['mouseout'].get(this.pickedId.id)
                                    if (pickedOverlay) {
                                        pickedOverlay._dispatchEvent('mouseout', e)
                                    }
                                } else {
                                    return;
                                }
                            }
                            //设置选中实体
                            this.pickedId = picked.id;
                            pickedOverlay = this.eventEntityMap['mouseover'].get(this.pickedId.id)
                            if (pickedOverlay) {
                                pickedOverlay._dispatchEvent('mouseover', e)
                            }
                        } else if (this.pickedId) {
                            pickedOverlay = this.eventEntityMap['mouseout'].get(this.pickedId.id)
                            if (pickedOverlay) {
                                pickedOverlay._dispatchEvent('mouseout', e)
                            }
                            this.pickedId = undefined;
                        }
                    }, CesiumEventManager.EVENT_MAP[event])
                    break;
                default:
                    this.handler.setInputAction(e => {
                        var picked = this.map.viewer.scene.pick(e.position);
                        if (Cesium.defined(picked) && picked.id) {
                            var pickedOverlay = this.eventEntityMap[event].get(picked.id.id)
                            if (pickedOverlay) {
                                pickedOverlay._dispatchEvent(event, e)
                            }
                        }
                    }, CesiumEventManager.EVENT_MAP[event])
            }
        }
    }

    removeEventOverlay(event, overlay) {
        //移除注册实体
        if (this.eventEntityMap[event]) {
            this.eventEntityMap[event].delete(overlay.getEntity().id);
        }
        //无注册实体,清除对应事件
        if (this.eventEntityMap[event].size === 0) {
            this.handler.removeInputAction(CesiumEventManager.EVENT_MAP[event])
        }
    }
}
  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值