--- a/labs/openlayers/lib/OpenLayers/Control/PanZoomBar.js +++ b/labs/openlayers/lib/OpenLayers/Control/PanZoomBar.js @@ -1,1 +1,397 @@ - +/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the Clear BSD license. + * See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Control/PanZoom.js + */ + +/** + * Class: OpenLayers.Control.PanZoomBar + * The PanZoomBar is a visible control composed of a + * and a . + * By default it is displayed in the upper left corner of the map as 4 + * directional arrows above a vertical slider. + * + * Inherits from: + * - + */ +OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, { + + /** + * APIProperty: zoomStopWidth + */ + zoomStopWidth: 18, + + /** + * APIProperty: zoomStopHeight + */ + zoomStopHeight: 11, + + /** + * Property: slider + */ + slider: null, + + /** + * Property: sliderEvents + * {} + */ + sliderEvents: null, + + /** + * Property: zoombarDiv + * {DOMElement} + */ + zoombarDiv: null, + + /** + * Property: divEvents + * {} + */ + divEvents: null, + + /** + * APIProperty: zoomWorldIcon + * {Boolean} + */ + zoomWorldIcon: false, + + /** + * APIProperty: forceFixedZoomLevel + * {Boolean} Force a fixed zoom level even though the map has + * fractionalZoom + */ + forceFixedZoomLevel: false, + + /** + * Property: mouseDragStart + * {} + */ + mouseDragStart: null, + + /** + * Property: zoomStart + * {} + */ + zoomStart: null, + + /** + * Constructor: OpenLayers.Control.PanZoomBar + */ + initialize: function() { + OpenLayers.Control.PanZoom.prototype.initialize.apply(this, arguments); + }, + + /** + * APIMethod: destroy + */ + destroy: function() { + + this._removeZoomBar(); + + this.map.events.un({ + "changebaselayer": this.redraw, + scope: this + }); + + OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments); + + delete this.mouseDragStart; + delete this.zoomStart; + }, + + /** + * Method: setMap + * + * Parameters: + * map - {} + */ + setMap: function(map) { + OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); + this.map.events.register("changebaselayer", this, this.redraw); + }, + + /** + * Method: redraw + * clear the div and start over. + */ + redraw: function() { + if (this.div != null) { + this.removeButtons(); + this._removeZoomBar(); + } + this.draw(); + }, + + /** + * Method: draw + * + * Parameters: + * px - {} + */ + draw: function(px) { + // initialize our internal div + OpenLayers.Control.prototype.draw.apply(this, arguments); + px = this.position.clone(); + + // place the controls + this.buttons = []; + + var sz = new OpenLayers.Size(18,18); + var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y); + var wposition = sz.w; + + if (this.zoomWorldIcon) { + centered = new OpenLayers.Pixel(px.x+sz.w, px.y); + } + + this._addButton("panup", "north-mini.png", centered, sz); + px.y = centered.y+sz.h; + this._addButton("panleft", "west-mini.png", px, sz); + if (this.zoomWorldIcon) { + this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz); + + wposition *= 2; + } + this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz); + this._addButton("pandown", "south-mini.png", centered.add(0, sz.h*2), sz); + this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h*3+5), sz); + centered = this._addZoomBar(centered.add(0, sz.h*4 + 5)); + this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); + return this.div; + }, + + /** + * Method: _addZoomBar + * + * Parameters: + * location - {} where zoombar drawing is to start. + */ + _addZoomBar:function(centered) { + var imgLocation = OpenLayers.Util.getImagesLocation(); + + var id = this.id + "_" + this.map.id; + var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom(); + var slider = OpenLayers.Util.createAlphaImageDiv(id, + centered.add(-1, zoomsToEnd * this.zoomStopHeight), + new OpenLayers.Size(20,9), + imgLocation+"slider.png", + "absolute"); + this.slider = slider; + + this.sliderEvents = new OpenLayers.Events(this, slider, null, true, + {includeXY: true}); + this.sliderEvents.on({ + "mousedown": this.zoomBarDown, + "mousemove": this.zoomBarDrag, + "mouseup": this.zoomBarUp, + "dblclick": this.doubleClick, + "click": this.doubleClick + }); + + var sz = new OpenLayers.Size(); + sz.h = this.zoomStopHeight * this.map.getNumZoomLevels(); + sz.w = this.zoomStopWidth; + var div = null; + + if (OpenLayers.Util.alphaHack()) { + var id = this.id + "_" + this.map.id; + div = OpenLayers.Util.createAlphaImageDiv(id, centered, + new OpenLayers.Size(sz.w, + this.zoomStopHeight), + imgLocation + "zoombar.png", + "absolute", null, "crop"); + div.style.height = sz.h + "px"; + } else { + div = OpenLayers.Util.createDiv( + 'OpenLayers_Control_PanZoomBar_Zoombar' + this.map.id, + centered, + sz, + imgLocation+"zoombar.png"); + } + + this.zoombarDiv = div; + + this.divEvents = new OpenLayers.Events(this, div, null, true, + {includeXY: true}); + this.divEvents.on({ + "mousedown": this.divClick, + "mousemove": this.passEventToSlider, + "dblclick": this.doubleClick, + "click": this.doubleClick + }); + + this.div.appendChild(div); + + this.startTop = parseInt(div.style.top); + this.div.appendChild(slider); + + this.map.events.register("zoomend", this, this.moveZoomBar); + + centered = centered.add(0, + this.zoomStopHeight * this.map.getNumZoomLevels()); + return centered; + }, + + /** + * Method: _removeZoomBar + */ + _removeZoomBar: function() { + this.sliderEvents.un({ + "mousedown": this.zoomBarDown, + "mousemove": this.zoomBarDrag, + "mouseup": this.zoomBarUp, + "dblclick": this.doubleClick, + "click": this.doubleClick + }); + this.sliderEvents.destroy(); + + this.divEvents.un({ + "mousedown": this.divClick, + "mousemove": this.passEventToSlider, + "dblclick": this.doubleClick, + "click": this.doubleClick + }); + this.divEvents.destroy(); + + this.div.removeChild(this.zoombarDiv); + this.zoombarDiv = null; + this.div.removeChild(this.slider); + this.slider = null; + + this.map.events.unregister("zoomend", this, this.moveZoomBar); + }, + + /** + * Method: passEventToSlider + * This function is used to pass events that happen on the div, or the map, + * through to the slider, which then does its moving thing. + * + * Parameters: + * evt - {} + */ + passEventToSlider:function(evt) { + this.sliderEvents.handleBrowserEvent(evt); + }, + + /** + * Method: divClick + * Picks up on clicks directly on the zoombar div + * and sets the zoom level appropriately. + */ + divClick: function (evt) { + if (!OpenLayers.Event.isLeftClick(evt)) { + return; + } + var y = evt.xy.y; + var top = OpenLayers.Util.pagePosition(evt.object)[1]; + var levels = (y - top)/this.zoomStopHeight; + if(this.forceFixedZoomLevel || !this.map.fractionalZoom) { + levels = Math.floor(levels); + } + var zoom = (this.map.getNumZoomLevels() - 1) - levels; + zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1); + this.map.zoomTo(zoom); + OpenLayers.Event.stop(evt); + }, + + /* + * Method: zoomBarDown + * event listener for clicks on the slider + * + * Parameters: + * evt - {} + */ + zoomBarDown:function(evt) { + if (!OpenLayers.Event.isLeftClick(evt)) { + return; + } + this.map.events.on({ + "mousemove": this.passEventToSlider, + "mouseup": this.passEventToSlider, + scope: this + }); + this.mouseDragStart = evt.xy.clone(); + this.zoomStart = evt.xy.clone(); + this.div.style.cursor = "move"; + // reset the div offsets just in case the div moved + this.zoombarDiv.offsets = null; + OpenLayers.Event.stop(evt); + }, + + /* + * Method: zoomBarDrag + * This is what happens when a click has occurred, and the client is + * dragging. Here we must ensure that the slider doesn't go beyond the + * bottom/top of the zoombar div, as well as moving the slider to its new + * visual location + * + * Parameters: + * evt - {} + */ + zoomBarDrag:function(evt) { + if (this.mouseDragStart != null) { + var deltaY = this.mouseDragStart.y - evt.xy.y; + var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv); + if ((evt.clientY - offsets[1]) > 0 && + (evt.clientY - offsets[1]) < parseInt(this.zoombarDiv.style.height) - 2) { + var newTop = parseInt(this.slider.style.top) - deltaY; + this.slider.style.top = newTop+"px"; + this.mouseDragStart = evt.xy.clone(); + } + OpenLayers.Event.stop(evt); + } + }, + + /* + * Method: zoomBarUp + * Perform cleanup when a mouseup event is received -- discover new zoom + * level and switch to it. + * + * Parameters: + * evt - {} + */ + zoomBarUp:function(evt) { + if (!OpenLayers.Event.isLeftClick(evt)) { + return; + } + if (this.mouseDragStart) { + this.div.style.cursor=""; + this.map.events.un({ + "mouseup": this.passEventToSlider, + "mousemove": this.passEventToSlider, + scope: this + }); + var deltaY = this.zoomStart.y - evt.xy.y; + var zoomLevel = this.map.zoom; + if (!this.forceFixedZoomLevel && this.map.fractionalZoom) { + zoomLevel += deltaY/this.zoomStopHeight; + zoomLevel = Math.min(Math.max(zoomLevel, 0), + this.map.getNumZoomLevels() - 1); + } else { + zoomLevel += Math.round(deltaY/this.zoomStopHeight); + } + this.map.zoomTo(zoomLevel); + this.mouseDragStart = null; + this.zoomStart = null; + OpenLayers.Event.stop(evt); + } + }, + + /* + * Method: moveZoomBar + * Change the location of the slider to match the current zoom level. + */ + moveZoomBar:function() { + var newTop = + ((this.map.getNumZoomLevels()-1) - this.map.getZoom()) * + this.zoomStopHeight + this.startTop + 1; + this.slider.style.top = newTop + "px"; + }, + + CLASS_NAME: "OpenLayers.Control.PanZoomBar" +}); +