Openlayers2卷帘功能的实现

概述:

在WebGIS开发中,经常会有用户提需求,要实现卷帘功能,卷帘功能主要是实现两张图之间的对比。在前文中,讲到了openlayers3以及Arcgis for js中卷帘的实现,在本文讲述如何在openlayers2中实现卷帘功能。


结果展示:

Openlayers2卷帘功能的实现_第1张图片


实现代码:

在此,扩展了一个名为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;
				}
			});




你可能感兴趣的:(Webgis,扩展,OpenLayers,swipe,卷帘)