网站产品图片尺寸,集团门户网站建设公司,套模板做网站教程,wordpress 网站备份概述
ZoomSlider滑块缩放控件就是Zoom缩放控件的异形体#xff0c;通过滑块的拖动或者点击滑槽#xff0c;实现地图的缩放#xff1b;另外其他方式控制地图缩放时#xff0c;也会引起滑块在滑槽中的位置改变#xff1b;即ZoomSlider滑块缩放控件会监听地图的缩放级别通过滑块的拖动或者点击滑槽实现地图的缩放另外其他方式控制地图缩放时也会引起滑块在滑槽中的位置改变即ZoomSlider滑块缩放控件会监听地图的缩放级别当级别发生改变时也会触发ZoomSlider中注册的事件从而改变滑块的相对位置。
本文主要介绍 Openlayers 中ZoomSlider滑块缩放控件的源码实现和核心逻辑分析。
源码分析
ZoomSlider源码实现
ZoomSlider类控件继承于Control类关于Control类可以参考这篇文章源码分析之Openlayers中的控件篇Control基类介绍。
ZoomSlider类的源码如下
class ZoomSlider extends Control {constructor(options) {options options ? options : {};super({target: options.target,element: document.createElement(div),render: options.render,});this.dragListenerKeys_ [];this.currentResolution_ undefined;this.direction_ Direction.VERTICAL;this.dragging_;this.heightLimit_ 0;this.widthLimit_ 0;this.startX_;this.startY_;this.thumbSize_ null;this.sliderInitialized_ false;this.duration_ options.duration ! undefined ? options.duration : 200;const className options.className ! undefined ? options.className : ol-zoomslider;const thumbElement document.createElement(button);thumbElement.setAttribute(type, button);thumbElement.className className -thumb CLASS_UNSELECTABLE;const containerElement this.element;containerElement.className className CLASS_UNSELECTABLE CLASS_CONTROL;containerElement.appendChild(thumbElement);containerElement.addEventListener(PointerEventType.POINTERDOWN,this.handleDraggerStart_.bind(this),false);containerElement.addEventListener(PointerEventType.POINTERMOVE,this.handleDraggerDrag_.bind(this),false);containerElement.addEventListener(PointerEventType.POINTERUP,this.handleDraggerEnd_.bind(this),false);containerElement.addEventListener(EventType.CLICK,this.handleContainerClick_.bind(this),false);thumbElement.addEventListener(EventType.CLICK, stopPropagation, false);}setMap(map) {super.setMap(map);if (map) {map.render();}}initSlider_() {const container this.element;let containerWidth container.offsetWidth;let containerHeight container.offsetHeight;if (containerWidth 0 containerHeight 0) {return (this.sliderInitialized_ false);}const containerStyle getComputedStyle(container);containerWidth -parseFloat(containerStyle[paddingRight]) parseFloat(containerStyle[paddingLeft]);containerHeight -parseFloat(containerStyle[paddingTop]) parseFloat(containerStyle[paddingBottom]);const thumb /** type {HTMLElement} */ (container.firstElementChild);const thumbStyle getComputedStyle(thumb);const thumbWidth thumb.offsetWidth parseFloat(thumbStyle[marginRight]) parseFloat(thumbStyle[marginLeft]);const thumbHeight thumb.offsetHeight parseFloat(thumbStyle[marginTop]) parseFloat(thumbStyle[marginBottom]);this.thumbSize_ [thumbWidth, thumbHeight];if (containerWidth containerHeight) {this.direction_ Direction.HORIZONTAL;this.widthLimit_ containerWidth - thumbWidth;} else {this.direction_ Direction.VERTICAL;this.heightLimit_ containerHeight - thumbHeight;}return (this.sliderInitialized_ true);}handleContainerClick_(event) {const view this.getMap().getView();const relativePosition this.getRelativePosition_(event.offsetX - this.thumbSize_[0] / 2,event.offsetY - this.thumbSize_[1] / 2);const resolution this.getResolutionForPosition_(relativePosition);const zoom view.getConstrainedZoom(view.getZoomForResolution(resolution));view.animateInternal({zoom: zoom,duration: this.duration_,easing: easeOut,});}handleDraggerStart_(event) {if (!this.dragging_ event.target this.element.firstElementChild) {const element /** type {HTMLElement} */ (this.element.firstElementChild);this.getMap().getView().beginInteraction();this.startX_ event.clientX - parseFloat(element.style.left);this.startY_ event.clientY - parseFloat(element.style.top);this.dragging_ true;if (this.dragListenerKeys_.length 0) {const drag this.handleDraggerDrag_;const end this.handleDraggerEnd_;const doc this.getMap().getOwnerDocument();this.dragListenerKeys_.push(listen(doc, PointerEventType.POINTERMOVE, drag, this),listen(doc, PointerEventType.POINTERUP, end, this));}}}handleDraggerDrag_(event) {if (this.dragging_) {const deltaX event.clientX - this.startX_;const deltaY event.clientY - this.startY_;const relativePosition this.getRelativePosition_(deltaX, deltaY);this.currentResolution_ this.getResolutionForPosition_(relativePosition);this.getMap().getView().setResolution(this.currentResolution_);}}handleDraggerEnd_(event) {if (this.dragging_) {const view this.getMap().getView();view.endInteraction();this.dragging_ false;this.startX_ undefined;this.startY_ undefined;this.dragListenerKeys_.forEach(unlistenByKey);this.dragListenerKeys_.length 0;}}setThumbPosition_(res) {const position this.getPositionForResolution_(res);const thumb /** type {HTMLElement} */ (this.element.firstElementChild);if (this.direction_ Direction.HORIZONTAL) {thumb.style.left this.widthLimit_ * position px;} else {thumb.style.top this.heightLimit_ * position px;}}getRelativePosition_(x, y) {let amount;if (this.direction_ Direction.HORIZONTAL) {amount x / this.widthLimit_;} else {amount y / this.heightLimit_;}return clamp(amount, 0, 1);}getResolutionForPosition_(position) {const fn this.getMap().getView().getResolutionForValueFunction();return fn(1 - position);}getPositionForResolution_(res) {const fn this.getMap().getView().getValueForResolutionFunction();return clamp(1 - fn(res), 0, 1);}render(mapEvent) {if (!mapEvent.frameState) {return;}if (!this.sliderInitialized_ !this.initSlider_()) {return;}const res mapEvent.frameState.viewState.resolution;this.currentResolution_ res;this.setThumbPosition_(res);}
}ZoomSlider构造函数
ZoomSlider构造函数接受的参数对象options除了包含常规的控件属性render、target和className外还有个属性duration,不传的话该属性值默认为200毫秒表示地图视图动画的持续时长。
ZoomSlider构造函数除了创建控件元素外还给控件元素添加了几个监听事件如下
//鼠标按键按下时触发pointerdown相当于mousedown
containerElement.addEventListener(PointerEventType.POINTERDOWN,this.handleDraggerStart_.bind(this),false
);//鼠标按键移动时触发pointermove相当于mousemove
containerElement.addEventListener(PointerEventType.POINTERMOVE,this.handleDraggerDrag_.bind(this),false
);//鼠标按键抬起时触发pointerup相当于mouseup
containerElement.addEventListener(PointerEventType.POINTERUP,this.handleDraggerEnd_.bind(this),false
);ZoomSlider主要方法 setMap方法:这个方法就是调用父类的setMap方法,然后判断,若map存在,则调用map.render,这个操作着实有点多余,因为父类中也有这个逻辑. initSlider_方法:滑动缩放控件可以是水平方向也可以是垂直方向,这个方法就是初始化滑动控件的显示,确保滑块滑动时始终在滑槽内. render方法:render方法主要用于更新滑块的位置,当地图的postrender类型触发时,会执行这个函数;获取当前地图视图状态的分辨率,调用setThumbPosition设置滑块的位置. getPositionForResolution_方法:获取给定的分辨率下,滑块的相对位置 getResolutionForPosition_方法:通过滑块的相对位置,计算出相对应的分辨率 getRelativePosition_方法:通过x和y计算出相对位置,该值在[0,1]之间 setThumbPosition_方法:该方法作用就是用于设置滑块的相对位置,通过当前地图视图的分辨率计算出滑块的相对偏移值,然后设置其left或top属性值 handleDraggerEnd_方法
在构造函数中初始化了一个全局变量this.dragging_,用来标识当前滑块是否处于拖动状态;当鼠标停止拖动抬起时,会触发该方法;该方法内部会先判断,若this.dragging_为true,则表明前一刻的鼠标是拖动状态,会先结束地图视图的交互,然后重置一些状态变量this.dragging_,this.startX_和this.startY_,最后清除一些在拖动开始时注册的监听;否则不是,不执行任何逻辑.
handleDraggerDrag_方法
handleDraggerDrag_方法会在鼠标拖动滑块时调用,同样地,会先判断,若this.dragging_为true,则计算出滑块的相对偏移值,然后根据偏移值调用this.getRelativePosition获取相对的位置偏移量,再通过this.getResolutionForPosition_得出当前得分辨率,最后调用地图视图的setResolution设置地图的分辨率,这就实现了拖动滑块时地图实时进行缩放动作的效果.
handleDraggerStart_方法
handleDraggerStart_方法就是在滑块拖动时进行一些初始化操作,设置一些状态量,以及调用beginInteraction开始交互,还会给地图容器注册一些鼠标移动和抬起的监听,这在触屏设备有用.
handleContainerClick_方法
ZoomSlider滑块缩放控件除了拖动滑块可以实现地图的缩放,还可以通过点击滑槽实现地图的缩放.后者的功能就是handleContainerClick_方法提供的.该方法内部就是先获取点击位置的坐标,然后通过该坐标计算出相对位置,再通过相对位置调用this.getResolutionForPosition计算出相对分辨率,然后调用view.getZoomForResolution获取缩放级别,最后调用view.animateInternal设置地图的缩放级别,这和滑块拖动缩放的最后调用的方法不同,这种会有动画效果.
总结
本文主要介绍了 Openlayers 中ZoomSlider滑块缩放控件的实现,主要是滑块在滑槽中的相对位置对应着当前地图的分辨率在分辨率区间的映射关系,这一关系可以基于view通过计算所得.