Pan/zoom controls that look like the OL ones
authorJohn Firebaugh <john.firebaugh@gmail.com>
Fri, 19 Oct 2012 22:42:21 +0000 (15:42 -0700)
committerJohn Firebaugh <john.firebaugh@gmail.com>
Fri, 9 Nov 2012 20:59:28 +0000 (12:59 -0800)
12 files changed:
app/assets/javascripts/application.js
app/assets/javascripts/browse.js
app/assets/javascripts/map.js.erb
app/assets/javascripts/user.js
app/assets/openlayers/SimplePanZoom.js [deleted file]
app/assets/openlayers/theme/openstreetmap/SimplePanZoom.css.scss [deleted file]
app/views/layouts/_head.html.erb
vendor/assets/leaflet/img/map_sprite.png [moved from app/assets/openlayers/theme/openstreetmap/img/map_sprite.png with 100% similarity]
vendor/assets/leaflet/leaflet.pan.js [new file with mode: 0644]
vendor/assets/leaflet/leaflet.pan.scss [new file with mode: 0644]
vendor/assets/leaflet/leaflet.zoom.js [new file with mode: 0644]
vendor/assets/leaflet/leaflet.zoom.scss [new file with mode: 0644]

index 4fa2b56cca377c34afb57c61f8aa7f2fbe00f012..8d6c13503095b9d3282446ade0e19637116a9b4a 100644 (file)
@@ -7,6 +7,8 @@
 //= require leaflet
 //= require leaflet.osm
 //= require leaflet.locationfilter
+//= require leaflet.pan
+//= require leaflet.zoom
 //= require i18n/translations
 //= require osm
 //= require piwik
index 0a37627273a82067e41b55bfdf8e03a4f8ec1806..b2efe4fd595ad72a2f2ed5983c7a63b7831fba18 100644 (file)
@@ -23,7 +23,7 @@ $(document).ready(function () {
 
   var map = createMap("small_map", {
     layerControl: false,
-    zoomControl: false,
+    panZoomControl: false,
     attributionControl: false
   });
 
index b8e53d5e0854b9aa0a81695aef8665c43b2e4c3e..e0570336b6309e83939c1e9010fb02326a0dab11 100644 (file)
@@ -76,15 +76,22 @@ var layers = [
 ];
 
 function createMap(divName, options) {
-  map = L.map(divName, options);
+  options = $.extend({zoomControl: false, panZoomControl: true, layerControl: true}, options);
+
+  map = L.map(divName, $.extend({}, options, {panControl: false, zoomsliderControl: false, maxZoom: 18}));
 
   if (map.attributionControl) {
     map.attributionControl.setPrefix(''); // For tmcw
   }
 
+  if (options.panZoomControl) {
+    new L.Control.Pan().addTo(map);
+    new L.Control.Zoomslider({stepHeight: 7}).addTo(map);
+  }
+
   var layersControl = L.control.layers();
 
-  if (!options || options.layerControl !== false) {
+  if (options.layerControl) {
     layersControl.addTo(map);
   }
 
index 95137bd120012df3cdf35f380920253689b61951..e5620b0a30dc6048b6009f26dd8657639266c573 100644 (file)
@@ -1,5 +1,8 @@
 $(document).ready(function () {
-  var map = createMap("map");
+  var map = createMap("map", {
+    zoomControl: true,
+    panZoomControl: false
+  });
 
   if (OSM.home) {
     map.setView([OSM.home.lat, OSM.home.lon], 12);
diff --git a/app/assets/openlayers/SimplePanZoom.js b/app/assets/openlayers/SimplePanZoom.js
deleted file mode 100644 (file)
index 83f6b9d..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/* 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();
-        this.moveZoomBar();
-    },
-    
-    /**
-    * 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
deleted file mode 100644 (file)
index ad6a632..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-.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;
-  -moz-transition: top 100ms linear;
-  -o-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;
-}
index 5688c9ebdf18ed4a76a51243f7d81d6fec219e60..17c58c792c1c33f05597d19d5259c98504e44185 100644 (file)
@@ -7,6 +7,7 @@
   <%= stylesheet_link_tag "print-#{dir}", :media => "print" %>
   <%= stylesheet_link_tag "leaflet" %>
   <%= stylesheet_link_tag "leaflet.locationfilter" %>
+  <%= stylesheet_link_tag "leaflet.pan", "leaflet.zoom" %>
   <!--[if IE]>
     <%= stylesheet_link_tag "leaflet.ie" %>
     <%= stylesheet_link_tag "large-#{dir}", :media => "screen" %>
diff --git a/vendor/assets/leaflet/leaflet.pan.js b/vendor/assets/leaflet/leaflet.pan.js
new file mode 100644 (file)
index 0000000..5fa3a91
--- /dev/null
@@ -0,0 +1,52 @@
+L.Control.Pan = L.Control.extend({
+       options: {
+               position: 'topleft',
+               panOffset: 500
+       },
+
+       onAdd: function (map) {
+               var className = 'leaflet-control-pan',
+                       container = L.DomUtil.create('div', className),
+                       off = this.options.panOffset;
+
+               this._panButton('Up'   , className + '-up'   
+                                               , container, map, new L.Point(    0 , -off));
+               this._panButton('Left' , className + '-left' 
+                                               , container, map, new L.Point( -off ,  0));
+               this._panButton('Right', className + '-right'
+                                               , container, map, new L.Point(  off ,  0));
+               this._panButton('Down' , className + '-down'
+                                               , container, map, new L.Point(    0 ,  off));
+               
+               return container;
+       },
+
+       _panButton: function (title, className, container, map, offset, text) {
+               var wrapper = L.DomUtil.create('div', className + "-wrap", container);
+               var link = L.DomUtil.create('a', className, wrapper);
+               link.href = '#';
+               link.title = title;
+               L.DomEvent
+                       .on(link, 'click', L.DomEvent.stopPropagation)
+                       .on(link, 'click', L.DomEvent.preventDefault)
+                       .on(link, 'click', function(){ map.panBy(offset); }, map)
+                       .on(link, 'dblclick', L.DomEvent.stopPropagation)
+
+               return link;
+       }
+});
+
+L.Map.mergeOptions({
+    panControl: true
+});
+
+L.Map.addInitHook(function () {
+    if (this.options.panControl) {
+               this.panControl = new L.Control.Pan();
+               this.addControl(this.panControl);
+       }
+});
+
+L.control.pan = function (options) {
+    return new L.Control.Pan(options);
+};
diff --git a/vendor/assets/leaflet/leaflet.pan.scss b/vendor/assets/leaflet/leaflet.pan.scss
new file mode 100644 (file)
index 0000000..c9807b1
--- /dev/null
@@ -0,0 +1,40 @@
+.leaflet-control-pan-up,
+.leaflet-control-pan-down,
+.leaflet-control-pan-left,
+.leaflet-control-pan-right {
+  background-image: image-url("img/map_sprite.png");
+  position: absolute;
+  background-repeat: no-repeat;
+  cursor: hand;
+  cursor: pointer;
+}
+
+.leaflet-control-pan-up {
+  left: 10px;
+  width: 25px;
+  height: 13px;
+  background-position: -15px -5px;
+}
+
+.leaflet-control-pan-down {
+  left: 10px;
+  top: 36px;
+  width: 25px;
+  height: 15px;
+  background-position: -15px -40px;
+}
+
+.leaflet-control-pan-left {
+  top: 13px;
+  width: 25px;
+  height: 24px;
+  background-position: -5px -17px;
+}
+
+.leaflet-control-pan-right {
+  top: 13px;
+  width: 25px;
+  height: 24px;
+  left: 25px;
+  background-position: -30px -17px;
+}
diff --git a/vendor/assets/leaflet/leaflet.zoom.js b/vendor/assets/leaflet/leaflet.zoom.js
new file mode 100644 (file)
index 0000000..de63404
--- /dev/null
@@ -0,0 +1,176 @@
+L.Control.Zoomslider = L.Control.extend({\r
+       options: {\r
+               position: 'topleft',\r
+               // height in px of zoom-slider.png\r
+               stepHeight: 9\r
+       },\r
+\r
+       onAdd: function (map) {\r
+               var className = 'leaflet-control-zoomslider',\r
+                       container = L.DomUtil.create('div', className);\r
+               \r
+        this._map = map;\r
+\r
+               this._createButton('Zoom in', className + '-in'\r
+                                                  , container, this._zoomIn , this);\r
+               this._createSlider(className + '-slider', container, map);\r
+               this._createButton('Zoom out', className + '-out'\r
+                                                  , container, this._zoomOut, this);\r
+\r
+               \r
+               \r
+               this._map.on('zoomend', this._snapToSliderValue, this);\r
+\r
+               this._snapToSliderValue();\r
+               return container;\r
+       },\r
+\r
+       onRemove: function(map){\r
+               map.off('zoomend', this._snapToSliderValue);\r
+       },\r
+       \r
+       _createSlider: function (className, container, map) {\r
+               var zoomLevels = map.getMaxZoom() - map.getMinZoom();\r
+               this._sliderHeight = this.options.stepHeight * zoomLevels;\r
+\r
+               var wrapper =  L.DomUtil.create('div', className + '-wrap', container);\r
+               wrapper.style.height = (this._sliderHeight + 5) + "px";\r
+               var slider = L.DomUtil.create('div', className, wrapper);\r
+               this._knob = L.DomUtil.create('div', className + '-knob', slider);\r
+\r
+               this._draggable = this._createDraggable();\r
+               this._draggable.enable();\r
+               \r
+               L.DomEvent\r
+                       .on(slider, 'click', L.DomEvent.stopPropagation)\r
+                       .on(slider, 'click', L.DomEvent.preventDefault)\r
+                       .on(slider, 'click', this._onSliderClick, this);\r
+\r
+               return slider;\r
+       },\r
+\r
+       _zoomIn: function (e) {\r
+           this._map.zoomIn(e.shiftKey ? 3 : 1);\r
+       },\r
+\r
+       _zoomOut: function (e) {\r
+           this._map.zoomOut(e.shiftKey ? 3 : 1);\r
+       },\r
+\r
+       _createButton: function (title, className, container, fn, context) {\r
+               var link = L.DomUtil.create('a', className, container);\r
+               link.href = '#';\r
+               link.title = title;\r
+\r
+               L.DomEvent\r
+                       .on(link, 'click', L.DomEvent.stopPropagation)\r
+                       .on(link, 'click', L.DomEvent.preventDefault)\r
+                       .on(link, 'click', fn, context);\r
+               \r
+               return link;\r
+       },\r
+\r
+       _createDraggable: function() {\r
+               L.DomUtil.setPosition(this._knob, new L.Point(0, 0));\r
+               L.DomEvent\r
+                       .on(this._knob\r
+                               , L.Draggable.START\r
+                               , L.DomEvent.stopPropagation)\r
+                       .on(this._knob, 'click', L.DomEvent.stopPropagation);\r
+\r
+               var bounds = new L.Bounds(\r
+                       new L.Point(0, 0), \r
+                       new L.Point(0, this._sliderHeight)\r
+               );\r
+               var draggable = new L.BoundedDraggable(this._knob, \r
+                                                                                          this._knob, \r
+                                                                                          bounds)\r
+                       .on('drag', this._snap, this)\r
+                       .on('dragend', this._setZoom, this);\r
+               \r
+               return draggable;\r
+       },\r
+\r
+       _snap : function(){\r
+               this._snapToSliderValue(this._posToSliderValue());\r
+       },\r
+       _setZoom: function() {\r
+               this._map.setZoom(this._toZoomLevel(this._posToSliderValue()));\r
+       },\r
+\r
+       _onSliderClick: function(e){\r
+               var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e);\r
+           var offset = first.offsetY \r
+                       ? first.offsetY\r
+                       : L.DomEvent.getMousePosition(first).y \r
+                       - L.DomUtil.getViewportOffset(this._knob).y;\r
+               var value = this._posToSliderValue(offset - this._knob.offsetHeight / 2);\r
+               this._snapToSliderValue(value);\r
+               this._map.setZoom(this._toZoomLevel(value));\r
+       },\r
+\r
+       _posToSliderValue: function(pos) {\r
+               pos = isNaN(pos) \r
+                       ? L.DomUtil.getPosition(this._knob).y\r
+                       : pos\r
+               return Math.round( (this._sliderHeight - pos) / this.options.stepHeight);\r
+       },\r
+\r
+       _snapToSliderValue: function(sliderValue) {\r
+               if(this._knob) {\r
+                       sliderValue = isNaN(sliderValue) \r
+                               ? this._getSliderValue()\r
+                               : sliderValue;\r
+                       var y = this._sliderHeight \r
+                               - (sliderValue * this.options.stepHeight);\r
+                       L.DomUtil.setPosition(this._knob, new L.Point(0, y));\r
+               }\r
+       },\r
+       _toZoomLevel: function(sliderValue) {\r
+               return sliderValue + this._map.getMinZoom();\r
+       },\r
+       _toSliderValue: function(zoomLevel) {\r
+               return zoomLevel - this._map.getMinZoom();\r
+       },\r
+       _getSliderValue: function(){\r
+               return this._toSliderValue(this._map.getZoom());\r
+       }\r
+});\r
+\r
+L.Map.mergeOptions({\r
+    zoomControl: false,\r
+    zoomsliderControl: true\r
+});\r
+\r
+L.Map.addInitHook(function () {\r
+    if (this.options.zoomsliderControl) {\r
+               this.zoomsliderControl = new L.Control.Zoomslider();\r
+               this.addControl(this.zoomsliderControl);\r
+       }\r
+});\r
+\r
+L.control.zoomslider = function (options) {\r
+    return new L.Control.Zoomslider(options);\r
+};\r
+\r
+\r
+L.BoundedDraggable = L.Draggable.extend({\r
+       initialize: function(element, dragStartTarget, bounds) {\r
+               L.Draggable.prototype.initialize.call(this, element, dragStartTarget);\r
+               this._bounds = bounds;\r
+               this.on('predrag', function() {\r
+                       if(!this._bounds.contains(this._newPos)){\r
+                               this._newPos = this._fitPoint(this._newPos);\r
+                       }\r
+               }, this);\r
+       }, \r
+       _fitPoint: function(point){\r
+               var closest = new L.Point(\r
+                       Math.min(point.x, this._bounds.max.x),\r
+                       Math.min(point.y, this._bounds.max.y)\r
+               );\r
+               closest.x = Math.max(closest.x, this._bounds.min.x);\r
+               closest.y = Math.max(closest.y, this._bounds.min.y);\r
+               return closest;\r
+       }\r
+});\r
diff --git a/vendor/assets/leaflet/leaflet.zoom.scss b/vendor/assets/leaflet/leaflet.zoom.scss
new file mode 100644 (file)
index 0000000..35da2fe
--- /dev/null
@@ -0,0 +1,46 @@
+.leaflet-control-zoomslider-in,
+.leaflet-control-zoomslider-out,
+.leaflet-control-zoomslider-slider,
+.leaflet-control-zoomslider-slider-knob {
+  background-image: image-url("img/map_sprite.png");
+  position: absolute;
+  background-repeat: no-repeat;
+  cursor: hand;
+  cursor: pointer;
+}
+
+.leaflet-control-zoomslider-in {
+  top: 50px;
+  width: 26px;
+  height: 20px;
+  left: 10px;
+  background-position: -15px -61px;
+}
+
+.leaflet-control-zoomslider-out {
+  top: 202px;
+  width: 26px;
+  height: 20px;
+  left: 10px;
+  background-position: -15px -220px;
+}
+
+.leaflet-control-zoomslider-slider {
+  top: 70px;
+  width: 26px;
+  height: 132px;
+  left: 10px;
+  background-position: -15px -84px;
+}
+
+.leaflet-control-zoomslider-slider-knob {
+  top: 0px;
+  width: 25px;
+  height: 10px;
+  -webkit-transition: top 100ms linear;
+  -moz-transition: top 100ms linear;
+  -o-transition: top 100ms linear;
+  background-position: -77px -58px;
+  pointer: move;
+  cursor: move;
+}