概述
放大或缩小是地图中最基本的功能,本文主要介绍分析 Openlayers 中Zoom
缩放控件的源码实现。
源码分析
Zoom
控件继承Control
类,关于Control
类,可以参考这篇文章源码分析之Openlayers中的控件篇Control基类介绍
如果直接实例化Zoom
类,页面上显示的是 Openlayers 中原生的样式,无论是控件的标签页还是样式,我们都可以通过传参进行定制。本文只讨论默认情况,不传参的情况。
源码如下:
class Zoom extends Control {constructor(options) {options = options ? options : {};super({element: document.createElement("div"),target: options.target,});const className =options.className !== undefined ? options.className : "ol-zoom";const delta = options.delta !== undefined ? options.delta : 1;const zoomInClassName =options.zoomInClassName !== undefined? options.zoomInClassName: className + "-in";const zoomOutClassName =options.zoomOutClassName !== undefined? options.zoomOutClassName: className + "-out";const zoomInLabel =options.zoomInLabel !== undefined ? options.zoomInLabel : "+";const zoomOutLabel =options.zoomOutLabel !== undefined ? options.zoomOutLabel : "\u2013";const zoomInTipLabel =options.zoomInTipLabel !== undefined ? options.zoomInTipLabel : "Zoom in";const zoomOutTipLabel =options.zoomOutTipLabel !== undefined? options.zoomOutTipLabel: "Zoom out";const inElement = document.createElement("button");inElement.className = zoomInClassName;inElement.setAttribute("type", "button");inElement.title = zoomInTipLabel;inElement.appendChild(typeof zoomInLabel === "string"? document.createTextNode(zoomInLabel): zoomInLabel);inElement.addEventListener(EventType.CLICK,this.handleClick_.bind(this, delta),false);const outElement = document.createElement("button");outElement.className = zoomOutClassName;outElement.setAttribute("type", "button");outElement.title = zoomOutTipLabel;outElement.appendChild(typeof zoomOutLabel === "string"? document.createTextNode(zoomOutLabel): zoomOutLabel);outElement.addEventListener(EventType.CLICK,this.handleClick_.bind(this, -delta),false);const cssClasses =className + " " + CLASS_UNSELECTABLE + " " + CLASS_CONTROL;const element = this.element;element.className = cssClasses;element.appendChild(inElement);element.appendChild(outElement);this.duration_ = options.duration !== undefined ? options.duration : 250;}handleClick_(delta, event) {event.preventDefault();this.zoomByDelta_(delta);}zoomByDelta_(delta) {}
}
Zoom
控件参数
Zoom
类中的构造函数接受一个参数options
,若它为空或者不传,则 Openlayers 将采用默认样式。options
对象可以有如下属性:
className
:Zoom
类名,默认为ol-zoom
delta
:缩放地图的变化量,默认为1
zoomInClassName
:放大控件的类名,默认为ol-zoom-in
zoomOutClassName
:缩小控件的类名,默认为ol-zoom-out
zoomInLabel
:放大控件图标,默认为+
zoomOutLabel
:缩小控件图标,默认为\u2013
(即-
)zoomInTipLabel
:放大控件hover
时的提示,默认为Zoom in
zoomOutTipLabel
:缩小控件hover
时的提示,默认为Zoom out
Zoom
类构造函数
Zoom
类的构造函数除了根据参数options
定义上述变量外,还调用super({element:document.createElement('div'),target:options.target})
将element
和target
传给父类Control
,默认情况下options.target
为undefined
,因此这个传值就是设置了this.element=document.createElement('div')
;然后就是创建放大和缩小控件的DOM
元素,设置属性,并将它们插入到this.element
。期间还会注册放大按钮和缩小按钮的两个事件,事件名为handleClick
,不同的是delta
传参不同。最后设置了this.duration_
,若参数options
中定义了duration
属性和值,则赋给this.duration_
,否则默认为250
,表示是250 毫秒
Zoom
类方法介绍
Zoom
类中定义了两个方法handleClick_
和zoomByDelta_
,handleClick_
就是后者的一个调用,核心方法就是zoomByDelta_
。
zoomByDelta_
方法
zoomByDelta
方法如下
zoomByDelta_(delta) {const map = this.getMap();const view = map.getView();if (!view) {return;}const currentZoom = view.getZoom();if (currentZoom !== undefined) {const newZoom = view.getConstrainedZoom(currentZoom + delta); //返回被限制的级别,不超出范围if (this.duration_ > 0) {if (view.getAnimating()) { // 若有动画正在进行,则取消动画view.cancelAnimations();}view.animate({zoom: newZoom,duration: this.duration_,easing: easeOut,});} else {view.setZoom(newZoom);}}
}
在上面代码中this.getMap()
实际上就是调用父类Control
的getMap
方法中,在Map
类中实例化时,会遍历this.controls
,调用setMap
方法;或者在const map=new Map(...)
后,用map.addControl
添加控件时,会触发this.controls.addEventListener(CollectionEventType.ADD,(event) => {event.element.setMap(this);},);
同样地会设置setMap
,因此Zoom
缩放控件被点击时触发zoomByDelta_
,调用this.getMap
是可以取到map
对象,然后通过map.getView
获取当前视图view
,继而获取当前地图的级别currentZoom
,进行边界判断,然后放大调用view.animate
,缩小调用view.setZoom
总结
本文主要介绍了Openlayers中Zoom
缩放控件的源码实现,讲解了缩放的核心知识。