Map类可以说是所有前端地图库的核心,是地图开发中最基本的类。包括常用地图框架入口都是它:
- Leaflet:L.Map
- MapboxGL: mapboxgl.Map
- ArcGIS JS API: esri/Map & esri/MapView
- Openlayers: ol.Map
不同的框架Map的用途会有不同特色,但都和地图DOM挂载初始化,图层操作,地图视图操作,地图事件相关。
回到Openlayers,分析它的Map的有哪些内容: Map
从 API上可以看到,ol.Map 主要是几大功能:
- 挂载地图容器Dom节点,获取Dom节点,设置Dom节点。
- view,layers,control,interaction,overlay相关设置或移除。
- 渲染方法。
- 地图的事件。
Map的继承关系
ol 7 的继承链是 Map => BaseObject => Observable => EventTarget,对比 ol6 已将 PluggableMap类合并到Map类中。
之前也提过,继承自EventTarget,就比较方便对地图的事件进行处理和暴露了。
Map的构造函数做了啥
在 进行 new Map()的时候,主要做了以下事情:
- 事件处理程序初始化,on、once、un
- 一些私有属性
- 创建切片的队列类
- viewport、overlayContainer dom节点创建
- 构造时传入的Options关键参数处理:主要是createOptionsInternal 函数的执行,返回了如下内容:
const values = {};
values[MapProperty.LAYERGROUP] = layerGroup;
values[MapProperty.TARGET] = options.target;
values[MapProperty.VIEW] = options.view instanceof View ? options.view : new View();
......
return {
controls: controls,
interactions: interactions,
keyboardEventTarget: keyboardEventTarget,
overlays: overlays,
values: values,
};
把主要的layerGroup、interactions、controls、overlays、view对象和collection对象创建。
- layerGroup, view, size, target的change事件注册
this.addChangeListener(MapProperty.LAYERGROUP,this.handleLayerGroupChanged_);
this.addChangeListener(MapProperty.VIEW, this.handleViewChanged_);
this.addChangeListener(MapProperty.SIZE, this.handleSizeChanged_);
this.addChangeListener(MapProperty.TARGET, this.handleTargetChanged_);
- controls, interactions, overlays 集合的 add、remove事件注册
- controls,interactions, overlays 挂载map对象(setMap调用)
Map的渲染触发和流程
考虑到Map 继承自 BaseObject,在构造函数中,进行setProperties操作,会触发之前注册的Layer, view, size, target change方法。
- 首先看handleLayerGroupChanged_,此回调函数除了会初始化layergroup 的 add, remove事件注册。最后调用了this.render()
- render方法会判断this.renderer_是否存在,若存在,判断animationDelayKey_(下一帧动画回调函数标识)是否未定义,则创建一个重绘前的回调。则但此时this.renderer_是不存在的,于是函数退出。
- 接着是handleTargetChanged_回调函数,往目标的dom挂载地图容器的viewport_ dom节点,并开始创建地图渲染器类的实例(CompositeMapRenderer)给this.renderer_,调用updateSize()方法,触发setSize()。
- 接着触发handleViewChanged_回调函数,调用render方法,创建一个重绘前的回调函数:animationDelay_()。
- animationDelay_()回调函数内:传入当前时间戳执行renderFrame_()
- 最后是handleViewChanged_回调函数,同样调用this.render(),此时animationDelayKey_已存在,跳出函数。
总体来说,渲染触发流程如上步骤所述,重点在于 CompositeMapRender 和 renderFrame_,后面再重点研究这块。
Map的事件
地图的事件包括浏览器事件,渲染的事件,属性变化的事件等,这里以地图浏览器事件的处理为例,涉及到MapBrowserEventHandler,MapBrowserEvent类。MapBrowserEventHandler的作用是dom事件和地图结合的处理中心,创建dom事件的监听,经过MapBrowserEvent类的包装,最后通过dispatch进行事件的派发操作。
如下图,简单描述了map.on,map.once去使用地图的浏览器事件的一个机制
其他
layerGroup、interactions、controls、overlays 在构造函数中已创建相应的collection对象实例,其实可以看到相应的get方法实际上是返回相应的collection对象。 如:
同理,add方法是往相应的collection().push() 同类型的实例。remove的方法是往相应的collection().remove()同类型的实例