Skip to content

Latest commit

 

History

History
178 lines (159 loc) · 6.02 KB

09-02.md

File metadata and controls

178 lines (159 loc) · 6.02 KB

实现原理

不管是上一节中的哪一种交互方式,本质上都是通过监听事件,来处理相应的业务的,在ol.Map的实现代码中,有下面的代码:

	/**
   * @private
   * @type {ol.MapBrowserEventHandler}
   */
  this.mapBrowserEventHandler_ = new ol.MapBrowserEventHandler(this);
  for (var key in ol.MapBrowserEvent.EventType) {	// 遍历所有的事件类型
    ol.events.listen(this.mapBrowserEventHandler_, ol.MapBrowserEvent.EventType[key],
        this.handleMapBrowserEvent, this);	// 监听事件,函数handleMapBrowserEvent为事件响应函数
  }

  ......

  /**
	 * @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle.
	 */
	ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) {
	  if (!this.frameState_) {
	    // With no view defined, we cannot translate pixels into geographical
	    // coordinates so interactions cannot be used.
	    return;
	  }
	  this.focus_ = mapBrowserEvent.coordinate;
	  mapBrowserEvent.frameState = this.frameState_;
	  var interactions = this.getInteractions();
	  goog.asserts.assert(interactions !== undefined,
	      'interactions should be defined');
	  var interactionsArray = interactions.getArray();
	  var i;
	  if (this.dispatchEvent(mapBrowserEvent) !== false) {	// 注意:如果事件处理返回false,交互类就不起作用了
	    for (i = interactionsArray.length - 1; i >= 0; i--) {	// 遍历所有的交互方式
	      var interaction = interactionsArray[i];
	      if (!interaction.getActive()) {
	        continue;
	      }
	      var cont = interaction.handleEvent(mapBrowserEvent);	// 让各个交互类处理响应的事件
	      if (!cont) {
	        break;
	      }
	    }
	  }
	};

至于每一个交互类如何处理,就和业务相关了,再此之前,先看一下具体有哪些事件:

	/**
	 * Constants for event names.
	 * @enum {string}
	 */
	ol.MapBrowserEvent.EventType = {

	  /**
	   * A true single click with no dragging and no double click. Note that this
	   * event is delayed by 250 ms to ensure that it is not a double click.
	   * @event ol.MapBrowserEvent#singleclick
	   * @api stable
	   */
	  SINGLECLICK: 'singleclick',

	  /**
	   * A click with no dragging. A double click will fire two of this.
	   * @event ol.MapBrowserEvent#click
	   * @api stable
	   */
	  CLICK: ol.events.EventType.CLICK,

	  /**
	   * A true double click, with no dragging.
	   * @event ol.MapBrowserEvent#dblclick
	   * @api stable
	   */
	  DBLCLICK: ol.events.EventType.DBLCLICK,

	  /**
	   * Triggered when a pointer is dragged.
	   * @event ol.MapBrowserEvent#pointerdrag
	   * @api
	   */
	  POINTERDRAG: 'pointerdrag',

	  /**
	   * Triggered when a pointer is moved. Note that on touch devices this is
	   * triggered when the map is panned, so is not the same as mousemove.
	   * @event ol.MapBrowserEvent#pointermove
	   * @api stable
	   */
	  POINTERMOVE: 'pointermove',

	  POINTERDOWN: 'pointerdown',
	  POINTERUP: 'pointerup',
	  POINTEROVER: 'pointerover',
	  POINTEROUT: 'pointerout',
	  POINTERENTER: 'pointerenter',
	  POINTERLEAVE: 'pointerleave',
	  POINTERCANCEL: 'pointercancel'
	};

这些事件在ol.Map的API文档里面,有些是能看到的,就是注释里面有@api的部分,其他的是暂时内部使用的。 按照这个逻辑,我们也可以实现自己的交互方式。 但有一点需要注意,ol.Map处理事件是有先后顺序的,注意看最前面的那段代码的注释,ol.Map会先派发事件给自己的监听器,然后才会把事件给interaction类处理。 如果前面的事件监听器返回false,那么后面的交互类就不会起作用。 比如像下面这样,用鼠标左键双击地图,并不能放大地图:

<script type="text/javascript" src="../src/ol3.13.1/ol.js" charset="utf-8"></script>
<script type="text/javascript"> var map = new ol.Map({ layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ], target: 'map', view: new ol.View({ center: ol.proj.transform( [104, 30], 'EPSG:4326', 'EPSG:3857'), zoom: 10 }) });
map.on('dblclick', function(event){
	return false;
});
</script>

为什么? 注意看代码:

<div id="map" style="width: 100%"></div>
<script type="text/javascript">
	var map = new ol.Map({
		layers: [
		  new ol.layer.Tile({
		    source: new ol.source.OSM()
		  })
		],
		target: 'map',
		view: new ol.View({
		  center: ol.proj.transform(
		      [104, 30], 'EPSG:4326', 'EPSG:3857'),
		  zoom: 10
		})
	});

	// 监听了dblclick事件,并返回了false
	map.on('dblclick', function(event){
		return false;
	});
</script>

这样做了后,后果非常的严重,出问题后,可能还不知道为什么? 所以建议不要轻易在MapBrowserEvent事件的监听器里面返回false

到此,我们可以进一步分析一下ol.interaction相关交互类的内部实现了,以ol.interaction.DoubleClickZoom为例,其核心必然是处理事件:

	ol.interaction.DoubleClickZoom.handleEvent = function(mapBrowserEvent) {
	  var stopEvent = false;
	  var browserEvent = mapBrowserEvent.originalEvent;
	  if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK) {	// 事件类型过滤
	    var map = mapBrowserEvent.map;
	    var anchor = mapBrowserEvent.coordinate;
	    var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_;	// 按住shift键,就缩小,否则就放大
	    var view = map.getView();
	    goog.asserts.assert(view, 'map must have a view');
	    ol.interaction.Interaction.zoomByDelta(
	        map, view, delta, anchor, this.duration_);		// 调用 ol.interaction.Interaction.zoomByDelta函数实现放大缩小
	    mapBrowserEvent.preventDefault();
	    stopEvent = true;
	  }
	  return !stopEvent;
	};

代码其实很简单,如果要自己实现一种交互方式,对照ol.interaction.DoubleClickZoom这个学习,再加以应用就可以了。