Replace standard PanZoomBar control with new SimplePanZoom control
authorTom MacWright <tom@macwright.org>
Tue, 7 Aug 2012 20:50:22 +0000 (16:50 -0400)
committerTom Hughes <tom@compton.nu>
Wed, 8 Aug 2012 17:20:02 +0000 (18:20 +0100)
app/assets/javascripts/map.js.erb
app/assets/javascripts/openlayers.js.erb
app/assets/openlayers/SimplePanZoom.js [new file with mode: 0644]
app/assets/openlayers/theme/openstreetmap/SimplePanZoom.css.scss [new file with mode: 0644]
app/assets/openlayers/theme/openstreetmap/img/map_sprite.png [new file with mode: 0644]
app/assets/openlayers/theme/openstreetmap/style.css.scss
app/assets/stylesheets/small.css.scss

index 82826ebfbf5cf43e4a19cdf527bf245bd95d3868..50b0fe441e8aa0556ed243c1b68fb5ef31cc41c8 100644 (file)
@@ -14,7 +14,7 @@ function createMap(divName, options) {
          new SimpleLayerSwitcher(),
          new OpenLayers.Control.Navigation(),
          new OpenLayers.Control.Zoom(),
-         new OpenLayers.Control.PanZoomBar(),
+         new OpenLayers.Control.SimplePanZoom(),
          new OpenLayers.Control.ScaleLine({geodesic: true})
       ],
       numZoomLevels: 20,
index b493a0517c209c0c261af8a311e9ff5a6e935f9a..ebb9578a3f3b1bc709c9e8b59e2fbbc326d56f94 100644 (file)
@@ -1,6 +1,7 @@
 //= require OpenLayers
 //= require OpenStreetMap
 //= require SimpleLayerSwitcher
+//= require SimplePanZoom
 
 OpenLayers.Util.imageURLs = {
     "404.png": "<%= asset_path 'img/404.png' %>",
diff --git a/app/assets/openlayers/SimplePanZoom.js b/app/assets/openlayers/SimplePanZoom.js
new file mode 100644 (file)
index 0000000..a1a389d
--- /dev/null
@@ -0,0 +1,355 @@
+/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository 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
+ * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomBar>. 
+ * 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.PanZoom>
+ */
+OpenLayers.Control.SimplePanZoom = OpenLayers.Class(OpenLayers.Control.PanZoom, {
+
+    /** 
+     * APIProperty: zoomStopWidth
+     */
+    zoomStopWidth: 18,
+
+    /** 
+     * APIProperty: zoomStopHeight
+     */
+    zoomStopHeight: 7,
+
+    /** 
+     * Property: slider
+     */
+    slider: null,
+
+    /** 
+     * Property: sliderEvents
+     * {<OpenLayers.Events>}
+     */
+    sliderEvents: null,
+
+    /** 
+     * Property: zoombarDiv
+     * {DOMElement}
+     */
+    zoombarDiv: null,
+
+    /** 
+     * APIProperty: zoomWorldIcon
+     * {Boolean}
+     */
+    zoomWorldIcon: false,
+
+    /**
+     * APIProperty: panIcons
+     * {Boolean} Set this property to false not to display the pan icons. If
+     * false the zoom world icon is placed under the zoom bar. Defaults to
+     * true.
+     */
+    panIcons: true,
+
+    /**
+     * APIProperty: forceFixedZoomLevel
+     * {Boolean} Force a fixed zoom level even though the map has 
+     *     fractionalZoom
+     */
+    forceFixedZoomLevel: false,
+
+    /**
+     * Property: mouseDragStart
+     * {<OpenLayers.Pixel>}
+     */
+    mouseDragStart: null,
+
+    /**
+     * Property: deltaY
+     * {Number} The cumulative vertical pixel offset during a zoom bar drag.
+     */
+    deltaY: null,
+
+    /**
+     * Property: zoomStart
+     * {<OpenLayers.Pixel>}
+     */
+    zoomStart: null,
+
+    /**
+     * Constructor: OpenLayers.Control.PanZoomBar
+     */ 
+    buttons: null,
+
+    /**
+     * APIMethod: destroy
+     */
+    destroy: function() {
+
+        this._removeZoomBar();
+
+        this.map.events.un({
+            "changebaselayer": this.redraw,
+            "updatesize": this.redraw,
+            scope: this
+        });
+
+        OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments);
+
+        delete this.mouseDragStart;
+        delete this.zoomStart;
+    },
+    
+    /**
+     * Method: setMap
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {
+        OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments);
+        this.map.events.on({
+            "changebaselayer": this.redraw,
+            "updatesize": this.redraw,
+            scope: this
+        });
+    },
+
+    /** 
+     * Method: redraw
+     * clear the div and start over.
+     */
+    redraw: function() {
+        if (this.div !== null) {
+            this.removeButtons();
+            this._removeZoomBar();
+        }  
+        this.draw();
+    },
+    
+    /**
+    * Method: draw 
+    *
+    * Parameters:
+    * px - {<OpenLayers.Pixel>} 
+    */
+    draw: function(px) {
+        // initialize our internal div
+        OpenLayers.Control.prototype.draw.apply(this, arguments);
+        px = this.position.clone();
+
+        // place the controls
+        this.buttons = [];
+        var ids = ['panup', 'panleft', 'panright', 'pandown', 'zoomout', 'zoomin'];
+
+        for (var i = 0; i < ids.length; i++) {
+            var b = document.createElement('div');
+            b.id = ids[i];
+            b.action = ids[i];
+            b.className = 'button olButton';
+            this.div.appendChild(b);
+            this.buttons.push(b);
+        }
+
+        this._addZoomBar();
+        return this.div;
+    },
+
+    /** 
+    * Method: _addZoomBar
+    * 
+    * Parameters:
+    * centered - {<OpenLayers.Pixel>} where zoombar drawing is to start.
+    */
+    _addZoomBar:function() {
+        var id = this.id + "_" + this.map.id;
+        var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom();
+        var slider = document.createElement('div');
+        slider.id = 'slider';
+        slider.className = 'button';
+        slider.style.cursor = 'move';
+        this.slider = slider;
+        
+        this.sliderEvents = new OpenLayers.Events(this, slider, null, true,
+            { includeXY: true });
+        this.sliderEvents.on({
+            "touchstart": this.zoomBarDown,
+            "touchmove": this.zoomBarDrag,
+            "touchend": this.zoomBarUp,
+            "mousedown": this.zoomBarDown,
+            "mousemove": this.zoomBarDrag,
+            "mouseup": this.zoomBarUp
+        });
+        
+        var height = this.zoomStopHeight * (this.map.getNumZoomLevels());
+        
+        // this is the background image
+        var div = document.createElement('div');
+        div.className = 'button olButton';
+        div.id = 'zoombar';
+        this.zoombarDiv = div;
+        
+        this.div.appendChild(div);
+        this.startTop = 75;
+        this.div.appendChild(slider);
+
+        this.map.events.register("zoomend", this, this.moveZoomBar);
+    },
+    
+    /**
+     * Method: _removeZoomBar
+     */
+    _removeZoomBar: function() {
+        this.sliderEvents.un({
+            "touchstart": this.zoomBarDown,
+            "touchmove": this.zoomBarDrag,
+            "touchend": this.zoomBarUp,
+            "mousedown": this.zoomBarDown,
+            "mousemove": this.zoomBarDrag,
+            "mouseup": this.zoomBarUp
+        });
+        this.sliderEvents.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: onButtonClick
+     *
+     * Parameters:
+     * evt - {Event}
+     */
+    onButtonClick: function(evt) {
+        OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments);
+        if (evt.buttonElement === this.zoombarDiv) {
+            var levels = evt.buttonXY.y / 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);
+        }
+    },
+    
+    /**
+     * 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 - {<OpenLayers.Event>} 
+     */
+    passEventToSlider:function(evt) {
+        this.sliderEvents.handleBrowserEvent(evt);
+    },
+    
+    /*
+     * Method: zoomBarDown
+     * event listener for clicks on the slider
+     *
+     * Parameters:
+     * evt - {<OpenLayers.Event>} 
+     */
+    zoomBarDown:function(evt) {
+        if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) {
+            return;
+        }
+        this.map.events.on({
+            "touchmove": this.passEventToSlider,
+            "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 - {<OpenLayers.Event>}
+     */
+    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]) < 140) {
+                var newTop = parseInt(this.slider.style.top, 10) - deltaY;
+                this.slider.style.top = newTop + "px";
+                this.mouseDragStart = evt.xy.clone();
+            }
+            // set cumulative displacement
+            this.deltaY = this.zoomStart.y - evt.xy.y;
+            OpenLayers.Event.stop(evt);
+        }
+    },
+
+    /*
+     * Method: zoomBarUp
+     * Perform cleanup when a mouseup event is received -- discover new zoom
+     * level and switch to it.
+     *
+     * Parameters:
+     * evt - {<OpenLayers.Event>}
+     */
+    zoomBarUp: function(evt) {
+        if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") {
+            return;
+        }
+        if (this.mouseDragStart) {
+            this.div.style.cursor = "";
+            this.map.events.un({
+                "touchmove": this.passEventToSlider,
+                "mouseup": this.passEventToSlider,
+                "mousemove": this.passEventToSlider,
+                scope: this
+            });
+            var zoomLevel = this.map.zoom;
+            zoomLevel += this.deltaY/this.zoomStopHeight;
+            zoomLevel = Math.max(Math.round(zoomLevel), 0);
+            this.map.zoomTo(zoomLevel);
+            this.mouseDragStart = null;
+            this.zoomStart = null;
+            this.deltaY = 0;
+            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;
+        this.slider.style.top = newTop + "px";
+    },
+    CLASS_NAME: "OpenLayers.Control.SimplePanZoom"
+});
diff --git a/app/assets/openlayers/theme/openstreetmap/SimplePanZoom.css.scss b/app/assets/openlayers/theme/openstreetmap/SimplePanZoom.css.scss
new file mode 100644 (file)
index 0000000..898640c
--- /dev/null
@@ -0,0 +1,76 @@
+.olControlSimplePanZoom {
+  top: 10px;
+  right: 10px;
+}
+
+.olControlSimplePanZoom .button {
+  background-image: image-url("theme/openstreetmap/img/map_sprite.png");
+  position: absolute;
+  background-repeat: no-repeat;
+  cursor: hand;
+  cursor: pointer;
+}
+
+.olControlSimplePanZoom #panup {
+  left: 10px;
+  width: 25px;
+  height: 13px;
+  background-position: -15px -5px;
+}
+
+.olControlSimplePanZoom #pandown {
+  left: 10px;
+  top: 36px;
+  width: 25px;
+  height: 15px;
+  background-position: -15px -40px;
+}
+
+.olControlSimplePanZoom #panleft {
+  top: 13px;
+  width: 25px;
+  height: 24px;
+  background-position: -5px -17px;
+}
+
+.olControlSimplePanZoom #panright {
+  top: 13px;
+  width: 25px;
+  height: 24px;
+  left: 25px;
+  background-position: -30px -17px;
+}
+
+.olControlSimplePanZoom #zoomin {
+  top: 50px;
+  width: 26px;
+  height: 20px;
+  left: 10px;
+  background-position: -15px -61px;
+}
+
+.olControlSimplePanZoom #zoomout {
+  top: 210px;
+  width: 26px;
+  height: 20px;
+  left: 10px;
+  background-position: -15px -220px;
+}
+
+.olControlSimplePanZoom #slider {
+  top: 75px;
+  width: 25px;
+  height: 10px;
+  left: 10px;
+  -webkit-transition: top 100ms linear;
+  background-position: -77px -58px;
+  pointer: move;
+  cursor: move;
+}
+.olControlSimplePanZoom #zoombar {
+  top: 70px;
+  width: 26px;
+  height: 140px;
+  left: 10px;
+  background-position: -15px -80px;
+}
diff --git a/app/assets/openlayers/theme/openstreetmap/img/map_sprite.png b/app/assets/openlayers/theme/openstreetmap/img/map_sprite.png
new file mode 100644 (file)
index 0000000..99734b1
Binary files /dev/null and b/app/assets/openlayers/theme/openstreetmap/img/map_sprite.png differ
index 6c6cf3cd3e9efbfd76e715d2c3e6027689049e88..b082c99337be168120fc72045876bb89ff7fce95 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *= require theme/default/style
  *= require theme/openstreetmap/SimpleLayerSwitcher
+ *= require theme/openstreetmap/SimplePanZoom
  */
 
 .olControlOverviewMapExtentRectangle {
index b5adaa79497ba7010545c8961c0f5d3ab4743f62..66cc68655248eca537553a4875b79c53cc6028ac 100644 (file)
@@ -91,7 +91,7 @@ h1 {
   border: 0;
 }
 
-.olControlPanZoomBar {
+.olControlSimplePanZoom {
   display: none;
 }