概述
Openlayers 中默认的三类控件是Zoom
、Rotate
和Attribution
源码分析
defaults
方法
Openlayers 默认控件的集成封装在defaults
方法中,该方法会返回一个Collection
的实例,Collection
是一个基于数组封装了一些方法,主要涉及到数组项的添加会注册触发一些事件。关于Collection
类可以参考源码分析之 Openlayers 中的 Collection 类
defaults
方法实现如下:
export function defaults(options) {
options = options ? options : {};
const controls = new Collection();
const zoomControl = options.zoom !== undefined ? options.zoom : true;
if (zoomControl) {
controls.push(new Zoom(options.zoomOptions));
}
const rotateControl = options.rotate !== undefined ? options.rotate : true;
if (rotateControl) {
controls.push(new Rotate(options.rotateOptions));
}
const attributionControl =
options.attribution !== undefined ? options.attribution : true;
if (attributionControl) {
controls.push(new Attribution(options.attributionOptions));
}
return controls;
}
默认控件的渲染
Openlayers 中的默认控件机制和默认键盘事件机制大同小异,关于 Openlayers 中的默认键盘事件可以参考源码分析之 Openlayers 中默认键盘事件触发机制
赋值
在Map.js
中方法中有如下代码:
class Map extends BaseObject {
constructor(options) {
const optionsInternal = createOptionsInternal(options);
this.controls = optionsInternal.controls || defaultControls();
}
}
function createOptionsInternal(options) {
let controls;
if (options.controls !== undefined) {
if (Array.isArray(options.controls)) {
controls = new Collection(options.controls.slice());
} else {
assert(
typeof (/** @type {?} */ (options.controls).getArray) === "function",
"Expected `controls` to be an array or an `ol/Collection.js`"
);
controls = options.controls;
}
}
return {
controls: controls,
};
}
同Interactions
一样,在createOptionsInternal
方法中会判断参数options
中是否配置了控件,若配置了控件,则判断其类型是否是一个数组,若是数组,则将其转为Collection
实例,否则判断其是否存在getArray
方法,默认情况下,createOptionsInternal
方法的返回值中controls
为undefined
;因此在Map
类中this.controls
的值为defaultControls()
方法的返回值,即包含Zoom
、Rotate
和Attribution
控件的Collection
实例。
注册监听、初始化
默认控件的注册、监听、移除 、添加方法都是在Map
类中实现的,首先看下代码
class Map extends BaseObject {
constructor(options) {
this.controls.addEventListener(CollectionEventType.ADD, (event) => {
event.element.setMap(this);
});
this.controls.addEventListener(CollectionEventType.REMOVE, (event) => {
event.element.setMap(null);
});
}
this.controls.forEach(
(control) => {
control.setMap(this);
},
);
//获取this.controls
getControls() {
return this.controls;
}
//添加controls
addControl(control) {
this.getControls().push(control);
}
//移除controls
removeControl(control) {
return this.getControls().remove(control);
}
}
- 监听和触发
在Map
类的构造函数中注册了this.controls
的添加和移除的监听事件。通过前面,我们知道this.controls
是一个Collection
类的实例,而Collection
类是继承于BaseObject
类,因此this.controls
可以通过addEventListener
注册监听事件;而调用Collection
实例的remove
方法会dispatchEvent(new CollectionEvent('remove'))
派发remove
类型的监听事件;调用Collection
实例的push
方法会dispatchEvent(new CollectionEvent('add'))
派发add
类型的监听事件。也就是说addControls
方法会执行(event) => {event.element.setMap(this);};
,removeControls
方法会执行(event) => {event.element.setMap(null);}
- 初始化渲染
在Map
类的构造函数中会调用this.controls.forEach
方法,该方法会遍历默认控件的实例,此时就会进行控件的实例化将控件元素添加到DOM
中,然后调用执行控件的setMap
,在Collection
类的介绍中提过,因为 Openlayers 中控件都是基于Control
类实现,而Control
类中的setMap
就是设置this.map_
,如此控件的交互对象也就有了。
总结
本文介绍了 Openlayers 中默认控件的原理,可以加深对 Openlayers 中注册监听和派发事件核心机制的理解。