概述:
在WebGIS开发中,经常会有用户提需求,要实现卷帘功能,卷帘功能主要是实现两张图之间的对比。在前文中,讲到了openlayers3以及Arcgis for js中卷帘的实现,在本文讲述如何在openlayers2中实现卷帘功能。
结果展示:
实现代码:
在此,扩展了一个名为Swipe的Control,Swipe的代码如下:
/* * * @requires OpenLayers/Control.js */ /* The following globals are for JSLint */ /* jslint browser: true, vars: true */ /* global OpenLayers, escape */ /** api: (define) * module = OpenLayers.Control * class = Swipe * base_link = `OpenLayers.Control <http://dev.openlayers.org/apidocs/files/OpenLayers/Control-js.html>`_ */ /** api: example * Sample code to add a swipe control * * .. code-block:: javascript * * var map = new new OpenLayers.Map("mymap"); * var Swipe = new OpenLayers.Control.Swipe({map: map}); * map.addControls([swipe]); * Swipe.activate(); * */ /** api: constructor * .. class:: Swipe(options) * * :param options: ``Object`` options * * :return: ``OpenLayers.Control.Swipe`` * * Add a swipe control in the map */ OpenLayers.Control.Swipe = OpenLayers.Class(OpenLayers.Control, { /** api: config[map] * ``OpenLayers.Map`` * A `OpenLayers.Map <http://dev.openlayers.org/docs/files/OpenLayers/Map-js.html>`_ instance */ map: null, width: 32, /** api: config[swipeRatio] * ``Number`` * A number between 0 and 1 defining the position of the swipe relative to the map (from right to left) */ swipeRatio: null, swipeLayer: null, isTitleVisible: false, isDragging: false, mouseDragStart: null, /** * Property: divEvents * {<OpenLayers.Events>} */ divEvents: null, initialize: function (options) { "use strict"; OpenLayers.Control.prototype.initialize.apply( this, arguments ); // Manage position of swipe if (this.map && this.map.swipeRatio) { // Swipe ratio can be set in the map (in order to manage permalink) this.setSwipeRatio(this.map.swipeRatio); } else { if (!this.swipeRatio) { // Default swipe ratio is 0.5 this.setSwipeRatio(0.5); } else { // Swipe ratio can be set to the control this.setSwipeRatio(this.swipeRatio); } } }, /** * Method: activate * Activates the control. * * Returns: * {Boolean} The control was effectively activated. */ activate: function () { this.map.swipeActive = true; this.map.events.triggerEvent("changelayer", { layer: this.swipeLayer, property: "name" }); OpenLayers.Control.prototype.activate.apply(this, arguments); this.map.events.on({ "addlayer": this.handleAddLayer, "removelayer": this.handleRemoveLayer, "changelayer": this.handleChangeLayer, "updatesize": this.handleUpdateSize, "move": this.handleMove, "scope": this }); if (this.isLayersInLayerSwitcher()) { this.div.style.display = 'block'; this.viewBigArrow(); } this.resize(); return true; }, /** * Method: deactivate * Deactivates the control. * * Returns: * {Boolean} The control was effectively deactivated. */ deactivate: function () { this.map.swipeActive = false; this.map.events.triggerEvent("changelayer", { layer: this.swipeLayer, property: "name" }); this.map.events.un({ "addlayer": this.handleAddLayer, "removelayer": this.handleRemoveLayer, "changelayer": this.handleChangeLayer, "updatesize": this.handleUpdateSize, "move": this.handleMove, "scope": this }); this.hideBigArrow(); this.hideLayerTitle(); this.div.style.display = 'none'; if (this.swipeLayer) { if (this.swipeLayer.layers) { for (var i = this.swipeLayer.layers.length - 1; i >= 0; i--) { var layer = this.swipeLayer.layers[i]; if (layer.div) { layer.div.style.clip = 'auto'; } } } else { this.swipeLayer.div.style.clip = 'auto'; } this.swipeLayer = null; } return OpenLayers.Control.prototype.deactivate.apply( this, arguments ); }, /** * Method: destroy * Destroy control. */ destroy: function() { this.map.events.un({ "addlayer": this.handleAddLayer, "removelayer": this.handleRemoveLayer, "changelayer": this.handleChangeLayer, "updatesize": this.handleUpdateSize, "scope": this }); OpenLayers.Control.prototype.destroy.apply(this, arguments); }, /** * Method: draw * Initialize control. * * Returns: * {DOMElement} A reference to the DIV DOMElement containing the control */ draw: function() { OpenLayers.Control.prototype.draw.apply(this, arguments); this.elementLayer = document.createElement("div"); this.div.appendChild(this.elementLayer); OpenLayers.Element.addClass( this.elementLayer, 'olControlSwipeLayerHide' ); this.elementLayerSpan = document.createElement("span"); this.div.appendChild(this.elementLayerSpan); OpenLayers.Element.addClass( this.elementLayerSpan, 'olControlSwipeLayerSpan' ); this.elementLeft = document.createElement("div"); this.div.appendChild(this.elementLeft); OpenLayers.Element.addClass( this.elementLeft, 'olControlArrowLeft' ); this.elementRight = document.createElement("div"); this.div.appendChild(this.elementRight); OpenLayers.Element.addClass( this.elementRight, 'olControlArrowRight' ); OpenLayers.Control.prototype.draw.apply(this, arguments); this.divEvents = new OpenLayers.Events(this, this.div, null, true, {includeXY: true}); this.divEvents.on({ "touchstart": this.divDown, "touchmove": this.divDrag, "touchend": this.divUp, "mousedown": this.divDown, "mousemove": this.divDrag, "mouseup": this.divUp, "mouseover": this.divMouseOver, "mouseout": this.divMouseOut, scope: this }); return this.div; }, /* * Method: divMouseOver * event listener for onmouseover event * * Parameters: * evt - {<OpenLayers.Event>} */ divMouseOver: function(ev) { OpenLayers.Element.addClass( this.div, 'olControlSwipeHover' ); //this.viewLayerTitle(); }, hideBigArrow: function() { if (!this.isDragging) { this.elementLeft.style.display = "none"; this.elementRight.style.display = "none"; } }, viewBigArrow: function() { if (!this.isDragging) { this.elementLeft.style.display = "block"; this.elementRight.style.display = "block"; } }, /* * Method: divMouseOut * event listener for onmouseout event * * Parameters: * evt - {<OpenLayers.Event>} */ divMouseOut: function(ev) { OpenLayers.Element.removeClass( this.div, 'olControlSwipeHover' ); this.hideLayerTitle(); this.viewBigArrow(); }, /** * Method: passEventToDiv * This function is used to pass events that happen on the map, * through to the div, which then does its moving thing. * * Parameters: * evt - {<OpenLayers.Event>} */ passEventToDiv:function(evt) { this.divEvents.handleBrowserEvent(evt); }, /* * Method: divDown * event listener for clicks on the div * * Parameters: * evt - {<OpenLayers.Event>} */ divDown:function(evt) { if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { return; } this.map.events.on({ "touchmove": this.passEventToDiv, "mousemove": this.passEventToDiv, "mouseup": this.passEventToDiv, scope: this }); this.mouseDragStart = evt.xy.clone(); OpenLayers.Event.stop(evt); //this.viewLayerTitle(); this.hideBigArrow(); this.isDragging = true; return false; }, /* * Method: divDrag * This is what happens when a click has occurred, and the client is * dragging. Here we must ensure that the div doesn't go beyond the * bottom/top of the zoombar div, as well as moving the div to its new * visual location * * Parameters: * evt - {<OpenLayers.Event>} */ divDrag:function(evt) { if (this.mouseDragStart && this.isDragging) { var deltaX = this.mouseDragStart.x - evt.xy.x; var left = parseInt(this.div.style.left, 10); if ((left - deltaX) >= 0 && (left - deltaX) <= (this.map.size.w - this.width)) { var delta = 0; if (OpenLayers.BROWSER_NAME === "msie" || OpenLayers.BROWSER_NAME === "safari") { delta = -1; } this.setSwipeRatio((left - deltaX) / (this.map.size.w - this.width + delta)); this.moveTo(this.computePosition()); this.clipFirstLayer(); this.mouseDragStart = evt.xy.clone(); } OpenLayers.Event.stop(evt); } return false; }, /* * Method: divUp * Perform cleanup when a mouseup event is received * * Parameters: * evt - {<OpenLayers.Event>} */ divUp:function(evt) { this.map.events.un({ "touchmove": this.passEventToDiv, "mousemove": this.passEventToDiv, "mouseup": this.passEventToDiv, scope: this }); if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { return; } if (this.mouseDragStart) { this.mouseDragStart = null; } this.isDragging = false; this.viewBigArrow(); if (evt.type === "touchend") { this.hideLayerTitle(); } OpenLayers.Event.stop(evt); return false; }, /* * Method: clipFirstLayer * Clip the first layer present in the layer switcher */ clipFirstLayer: function() { var newFirstLayer = this.getFirstLayerInLayerSwitcher(); if (this.swipeLayer) { if (newFirstLayer.id !== this.swipeLayer.id) { if (this.swipeLayer.layers) { for (var i = this.swipeLayer.layers.length - 1; i >= 0; i--) { var layer = this.swipeLayer.layers[i]; if (layer.div) { layer.div.style.clip = 'auto'; } } } else { this.swipeLayer.div.style.clip = 'auto'; } } } if (newFirstLayer) { var width = this.map.getCurrentSize().w; var height = this.map.getCurrentSize().h; // slider position in pixels var s = parseInt(width * this.getSwipeRatio() * ((this.map.getCurrentSize().w - this.width) / this.map.getCurrentSize().w), 10); // cliping rectangle var top = -this.map.layerContainerOriginPx.y; var bottom = top + height; var left = -this.map.layerContainerOriginPx.x; var right = left + s + Math.ceil((this.width - 1) / 2); //Syntax for clip "rect(top,right,bottom,left)" var clip = "rect(" + top + "px " + right + "px " + bottom + "px " + left + "px)"; this.swipeLayer = newFirstLayer; if (this.swipeLayer.layers) { for (var i = this.swipeLayer.layers.length - 1; i >= 0; i--) { var layer = this.swipeLayer.layers[i]; if (layer.div) { layer.div.style.clip = clip; } } } else { this.swipeLayer.div.style.clip = clip; } } }, /* * Method: handleAddLayer * Triggered when a new layer is added * * Parameters: * object - {<OpenLayers.Event>} */ handleAddLayer: function (object) { if (this.isLayersInLayerSwitcher()) { this.div.style.display = 'block'; this.moveTo(this.computePosition()); this.clipFirstLayer(); } else { this.div.style.display = 'none'; this.swipeLayer = null; } }, viewLayerTitle: function() { if (!this.isTitleVisible && !this.isDragging) { if (this.swipeLayer) { var content = " " + this.swipeLayer.name; this.elementLayer.innerHTML = content; this.elementLayerSpan.innerHTML = content; OpenLayers.Element.addClass( this.elementLayer, 'olControlSwipeLayerView' ); OpenLayers.Element.removeClass( this.elementLayer, 'olControlSwipeLayerHide' ); var width = parseInt(this.elementLayerSpan.offsetWidth) + 5; this.elementLayer.style.width = width + "px"; this.elementLayer.style.marginLeft = "-" + width + "px"; } } this.isTitleVisible = true; }, hideLayerTitle: function() { if (!this.isDragging) { this.elementLayer.innerHTML = ''; this.isTitleVisible = false; OpenLayers.Element.addClass( this.elementLayer, 'olControlSwipeLayerHide' ); OpenLayers.Element.removeClass( this.elementLayer, 'olControlSwipeLayerView' ); } }, /* * Method: handleRemoveLayer * Triggered when a new layer is removed * * Parameters: * object - {<OpenLayers.Event>} */ handleRemoveLayer: function (object) { if (this.isLayersInLayerSwitcher()) { this.div.style.display = 'block'; this.moveTo(this.computePosition()); this.clipFirstLayer(); } else { this.div.style.display = 'none'; this.swipeLayer = null; } }, /* * Method: handleChangeLayer * Triggered when the layer order is changed * * Parameters: * object - {<OpenLayers.Event>} */ handleChangeLayer: function (object) { if (object.property === 'order') { if (this.isLayersInLayerSwitcher()) { this.div.style.display = 'block'; this.moveTo(this.computePosition()); this.clipFirstLayer(); } else { this.div.style.display = 'none'; this.swipeLayer = null; } } }, /* * Method: handleUpdateSize * Triggered when the map size changed. In this case the swipe control is updated accordingly. * * Parameters: * object - {<OpenLayers.Event>} */ handleUpdateSize: function (object) { //we have to delay this on Android devices if (navigator.userAgent.toLowerCase().indexOf("android") > 0) { var self = this; setTimeout(function() { self.resize(); }, 10); } else { this.resize(); } }, /* * Method: handleMove * Triggered when the map is moved. In this case, the clip ares has to be updated * * Parameters: * object - {<OpenLayers.Event>} */ handleMove: function (object) { this.clipFirstLayer(); }, /* * Method: resize * Resize the swipe and update the first layer clipping */ resize: function() { this.div.style.height = this.map.getCurrentSize().h + 'px'; this.div.style.width = this.width + 'px'; this.moveTo(this.computePosition()); this.clipFirstLayer(); var topPosition = (this.map.getCurrentSize().h / 2) - 32; this.elementLeft.style.marginTop = topPosition + 'px'; this.elementRight.style.marginTop = topPosition + 'px'; }, /* * Method: computePosition * Recompute the position of the swipe acording to swipeRatio and the size of the map */ computePosition: function() { var y = 0; var x = this.getSwipeRatio() * (this.map.size.w - this.width); return new OpenLayers.Pixel(x, y); }, /* * Method: getFirstLayerInLayerSwitcher * Get the first layer visible in the layer switcher */ getFirstLayerInLayerSwitcher: function() { for (var i = this.map.layers.length - 1; i >= 0; i--) { var layer = this.map.layers[i]; if (layer.displayInLayerSwitcher) { return layer; } } return null; }, /* * Method: isLayersInLayerSwitcher * Check the presence of a layer in the layer switcher */ isLayersInLayerSwitcher: function() { for (var i = 0, len = this.map.layers.length; i < len; i++) { var layer = this.map.layers[i]; if (layer.displayInLayerSwitcher) { return true; } } return false; }, setSwipeRatio: function(ratio) { this.map.events.triggerEvent("changelayer", { layer: this.swipeLayer, property: "name" }); this.map.swipeRatio = ratio; this.map.swipeActive = this.active; }, getSwipeRatio: function() { return this.map.swipeRatio; }, /* * Method: updateRatio * Update the swipeRatio and update the swipe control accordingly */ updateRatio: function(ratio) { this.setSwipeRatio(ratio); if (this.isLayersInLayerSwitcher()) { this.div.style.display = 'block'; this.moveTo(this.computePosition()); this.clipFirstLayer(); } else { this.div.style.display = 'none'; this.swipeLayer = null; } }, CLASS_NAME: "OpenLayers.Control.Swipe" });
这个js文件里面引用到了一些样式,样式文件的内容如下:
.olControlSwipe { background:url("../img/line.png") repeat; display: none; } .olControlSwipeHover { cursor: w-resize; } .olControlSwipeLayerView { background-color: white; height: 16px; width: 220px; margin-top: 23px; margin-left: -230px; display: block; font-size: 11px; font-family: Tahoma, Arial; font-weight: 700; padding-top: 2px; background-image: url("../img/bigarrow_left.png"); background-repeat: no-repeat; position: absolute; } .olControlSwipeLayerSpan { visibility: hidden; font-size: 11px; font-family: Tahoma, Arial; font-weight: 700; white-space: pre; position: absolute; } .olControlSwipeLayerHide { display: none; } .olControlArrowLeft { width: 16px; height: 32px; margin-left: -1px; background-image: url("../img/bigarrow_left.png"); background-repeat: no-repeat; position: absolute; } .olControlArrowRight { width: 16px; height: 32px; margin-left: 19px; background-image: url("../img/bigarrow_right.png"); background-repeat: no-repeat; position: absolute; }
最后,调用展示,代用代码如下:
$("#swipebutton").on("click",function(){ if(flag){ swipe.deactivate(); flag=false; } else{ swipe.activate(); flag=true; } });