美文网首页开源
OpenLayers的Interaction交互及事件机制解析

OpenLayers的Interaction交互及事件机制解析

作者: jadefan | 来源:发表于2020-11-04 16:28 被阅读0次

    interaction

    OpenLayers中表达交互功能的基类是interaction,它是一个虚基类,不负责实例化,交互功能都继承该基类,实现它的子类包括:

    • DoubleClickZoom 双击放大交互功能;
    • DragAndDrop 以“拖文件到地图中”的交互添加图层;
    • DragBox 拉框,用于划定一个矩形范围,常用于放大地图;
    • DragPan 拖拽平移地图;
    • DragRotate 拖拽方式旋转地图;
    • DragRotateAndZoom 拖拽方式进行缩放和旋转地图;
    • DragZoom 拖拽方式缩放地图;
    • Draw 绘制地理要素功能;
    • Extent 单击并拖动地图来绘制矢量框,并可编辑
    • KeyboardPan 键盘方式平移地图;
    • KeyboardZoom 键盘方式缩放地图;
    • Modify 更改要素;
    • MouseWheelZoom 鼠标滚轮缩放功能;
    • PinchRotate 手指旋转地图,针对触摸屏;
    • PinchZoom 手指进行缩放,针对触摸屏;
    • Pointer 鼠标的用户自定义事件基类;
    • Select 选择要素功能;
    • Snap 鼠标捕捉,当鼠标距离某个要素一定距离之内,自动吸附到要素。
    • Translate 拖拽移动选中的要素(新增)
    用法
    // 先实例化
    var select = new Select(); 
    var translate = new Translate({
      features: select.getFeatures(),
    });
    // 可以初始化时添加
    var map = new Map({
      interactions: defaultInteractions().extend([select, translate]),
      layers: [raster, vector],
      target: 'map',
      view: new View({
        center: [0, 0],
        zoom: 2,
      }),
    });
    // 也可以后续追加
      map.addInteraction(select );
      map.addInteraction(translate );
    
    

    默认交互

    地图初始化时,如果没有设置交互类型,就会默认绑定一些预设的交互,包括:

    • DragRotate 拖拽旋转
    • DoubleClickZoom 双击放大
    • DragPan 拖拽平移
    • PinchRotate 手指旋转
    • PinchZoom 手指缩放
    • KeyboardPan 键盘平移
    • KeyboardZoom 键盘缩放
    • MouseWheelZoom 滚轮缩放
    • DragZoom 拖拽缩放

    事件机制解析

    看下ol的事件绑定和触发,入口 Map.js

    function Map(options) {
             // ...
            if (!options.interactions) {
                options.interactions = defaultInteractions({  // 没有指定就加载默认交互
                    onFocusOnly: true,
                });
            }
           // ...
        }
    

    Map的父类 PluggableMap.js

    // 构造函数
    function PluggableMap(options) {
            var _this = _super.call(this) || this;
            var optionsInternal = createOptionsInternal(options);  // 属性初始化
            _this.viewport_ = document.createElement('div');  // 地图容器内的主div
            // 监听各属性更新事件
            _this.addEventListener(getChangeEventType(MapProperty.LAYERGROUP), _this.handleLayerGroupChanged_);
            _this.addEventListener(getChangeEventType(MapProperty.VIEW), _this.handleViewChanged_);
            _this.addEventListener(getChangeEventType(MapProperty.SIZE), _this.handleSizeChanged_);
            _this.addEventListener(getChangeEventType(MapProperty.TARGET), _this.handleTargetChanged_);
            // 通过setProperties更新属性,触发上面监听事件
            // 这个方法
            _this.setProperties(optionsInternal.values);
    }
    
    // 地图容器更新触发的方法
    PluggableMap.prototype.handleTargetChanged_ = function () {
            var targetElement = this.getTargetElement();  // 获取到地图容器
            targetElement.appendChild(this.viewport_);
            // 实例化一个浏览器事件处理类
            this.mapBrowserEventHandler_ = new MapBrowserEventHandler(this, this.moveTolerance_);
            for (var key in MapBrowserEventType) {  
                    // 循环所有支持的浏览器事件类型,逐一绑定,触发方法内循环遍历绑定的interaction
                    this.mapBrowserEventHandler_.addEventListener(MapBrowserEventType[key], this.handleMapBrowserEvent.bind(this));
            }
            // 绑定右击事件
            this.viewport_.addEventListener(EventType.CONTEXTMENU, this.boundHandleBrowserEvent_, false);
            // 绑定滚轮事件
            this.viewport_.addEventListener(EventType.WHEEL, this.boundHandleBrowserEvent_, PASSIVE_EVENT_LISTENERS ? { passive: false } : false);
            // 绑定键盘事件
            this.keyHandlerKeys_ = [
                    listen(keyboardEventTarget, EventType.KEYDOWN, this.handleBrowserEvent, this),
                    listen(keyboardEventTarget, EventType.KEYPRESS, this.handleBrowserEvent, this),
            ];
            // 绑定resize事件
            if (!this.handleResize_) {
                    this.handleResize_ = this.updateSize.bind(this);
                    window.addEventListener(EventType.RESIZE, this.handleResize_, false);
            }
    }
    
    // 各交互事件触发的方法
    PluggableMap.prototype.handleMapBrowserEvent = function (mapBrowserEvent) {
            var interactionsArray = this.getInteractions().getArray();  // 取出所有绑定的 Interactions
            if (this.dispatchEvent(mapBrowserEvent) !== false) {
                for (var i = interactionsArray.length - 1; i >= 0; i--) {
                    var interaction = interactionsArray[i];
                    if (!interaction.getActive()) {  //判断是否处于激活状态
                        continue;
                    }
                    //调用执行各Interactions子类的处理方法
                    var cont = interaction.handleEvent(mapBrowserEvent);  
                    if (!cont) {
                        break;
                    }
                }
            }
    }
    

    Interactions的子类DoubleClickZoom为例,看事件响应部分

        DoubleClickZoom.prototype.handleEvent = function (mapBrowserEvent) {
            var stopEvent = false;
            // 判断下是否触发的是自己,再响应
            if (mapBrowserEvent.type == MapBrowserEventType.DBLCLICK) { 
                var browserEvent =  (mapBrowserEvent.originalEvent);
                var map = mapBrowserEvent.map;
                var anchor = mapBrowserEvent.coordinate;
                var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_;
                var view = map.getView();
                zoomByDelta(view, delta, anchor, this.duration_);
                mapBrowserEvent.preventDefault();
                stopEvent = true;
            }
            return !stopEvent;
        };
    

    可以看到 ol 的事件基本都是在viewporttarget上绑着,并没有直接绑定在canvas上

    相关文章

      网友评论

        本文标题:OpenLayers的Interaction交互及事件机制解析

        本文链接:https://www.haomeiwen.com/subject/qcegvktx.html