Update Leaflet.zoomslider
authorTom Hughes <tom@compton.nu>
Wed, 26 Jun 2013 16:28:46 +0000 (17:28 +0100)
committerTom Hughes <tom@compton.nu>
Wed, 26 Jun 2013 17:20:06 +0000 (18:20 +0100)
app/assets/stylesheets/leaflet.zoom.css.scss
vendor/assets/leaflet/leaflet.zoom.js

index f920b2f..66f464a 100644 (file)
@@ -1,53 +1,57 @@
-.leaflet-control-zoomslider-in,
-.leaflet-control-zoomslider-out,
-.leaflet-control-zoomslider-slider,
-.leaflet-control-zoomslider-slider-knob {
-  background-image: image-url("map_sprite.png");
-  position: absolute;
-  background-repeat: no-repeat;
-  cursor: hand;
-  cursor: pointer;
-}
+.leaflet-control-zoomslider {
+  .leaflet-control-zoomslider-in,
+  .leaflet-control-zoomslider-out,
+  .leaflet-control-zoomslider-slider,
+  .leaflet-control-zoomslider-slider-knob {
+    background-image: image-url("map_sprite.png");
+    position: absolute;
+    background-repeat: no-repeat;
+    cursor: hand;
+    cursor: pointer;
+  }
 
-.leaflet-control-zoomslider-in,
-.leaflet-control-zoomslider-out {
-  text-indent: 26px;
-  overflow: hidden;
-  outline-style: none;
-}
+  .leaflet-control-zoomslider-in,
+  .leaflet-control-zoomslider-out {
+    text-indent: 26px;
+    overflow: hidden;
+    outline-style: none;
+    border: 0;
+    background-color: transparent;
+  }
 
-.leaflet-control-zoomslider-in {
-  top: 50px;
-  width: 26px;
-  height: 20px;
-  left: 10px;
-  background-position: -15px -61px;
-}
+  .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-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 {
+    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;
+  .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;
+  }
 }
index fe7e2f5..0d105f9 100644 (file)
-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
-               L.DomEvent.disableClickPropagation(container);\r
-\r
-               this._map = map;\r
-\r
-               this._zoomInButton = this._createButton('Zoom in', className + '-in'\r
-                                                                                               , container, this._zoomIn , this);\r
-               this._createSlider(className + '-slider', container, map);\r
-               this._zoomOutButton = this._createButton('Zoom out', className + '-out'\r
-                                                                                                , container, this._zoomOut, this);\r
-\r
-               map.on('layeradd layerremove', this._refresh, this);\r
-\r
-               map.whenReady(function(){\r
-                       this._snapToSliderValue();\r
-                       map.on('zoomend', this._snapToSliderValue, this);\r
-               }, this);\r
-\r
-               return container;\r
-       },\r
-\r
-       onRemove: function(map){\r
-               map.off('zoomend', this._snapToSliderValue);\r
-               map.off('layeradd layerremove', this._refresh);\r
-       },\r
-\r
-       _refresh: function(){\r
-               this._map\r
-                       .removeControl(this)\r
-                       .addControl(this);\r
-       },\r
-\r
-       _createSlider: function (className, container, map) {\r
-               var zoomLevels = map.getMaxZoom() - map.getMinZoom();\r
-               // This means we have no tilelayers (or that they are setup in a strange way).\r
-               // Either way we don't want to add a slider here.\r
-               if(zoomLevels == Infinity){\r
-                       return undefined;\r
-               }\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.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.preventDefault)\r
-                   .on(link, 'click', fn, context);\r
-\r
-               return link;\r
-       },\r
-\r
-       _createDraggable: function() {\r
-               L.DomUtil.setPosition(this._knob, L.point(0, 0));\r
-               L.DomEvent.disableClickPropagation(this._knob);\r
-\r
-               var bounds = new L.Bounds(\r
-                       L.point(0, 0),\r
-                       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
-               this._updateDisabled();\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, 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
-       _updateDisabled: function () {\r
-               var map = this._map,\r
-                       className = 'leaflet-control-zoomslider-disabled';\r
-\r
-               L.DomUtil.removeClass(this._zoomInButton, className);\r
-               L.DomUtil.removeClass(this._zoomOutButton, className);\r
-\r
-               if (map.getZoom() === map.getMinZoom()) {\r
-                       L.DomUtil.addClass(this._zoomOutButton, className);\r
-               }\r
-               if (map.getZoom() === map.getMaxZoom()) {\r
-                       L.DomUtil.addClass(this._zoomInButton, className);\r
-               }\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
-               L.control.zoomslider().addTo(this);\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 = 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
+L.Control.Zoomslider = (function () {
+
+       var Knob = L.Draggable.extend({
+               initialize: function (element, stepHeight, knobHeight) {
+                       L.Draggable.prototype.initialize.call(this, element, element);
+                       this._element = element;
+
+                       this._stepHeight = stepHeight;
+                       this._knobHeight = knobHeight;
+
+                       this.on('predrag', function () {
+                               this._newPos.x = 0;
+                               this._newPos.y = this._adjust(this._newPos.y);
+                       }, this);
+               },
+
+               _adjust: function (y) {
+                       var value = Math.round(this._toValue(y));
+                       value = Math.max(0, Math.min(this._maxValue, value));
+                       return this._toY(value);
+               },
+
+               // y = k*v + m
+               _toY: function (value) {
+                       return this._k * value + this._m;
+               },
+               // v = (y - m) / k
+               _toValue: function (y) {
+                       return (y - this._m) / this._k;
+               },
+
+               setSteps: function (steps) {
+                       var sliderHeight = steps * this._stepHeight;
+                       this._maxValue = steps - 1;
+
+                       // conversion parameters
+                       // the conversion is just a common linear function.
+                       this._k = -this._stepHeight;
+                       this._m = sliderHeight - (this._stepHeight + this._knobHeight) / 2;
+               },
+
+               setPosition: function (y) {
+                       L.DomUtil.setPosition(this._element,
+                                                                 L.point(0, this._adjust(y)));
+               },
+
+               setValue: function (v) {
+                       this.setPosition(this._toY(v));
+               },
+
+               getValue: function () {
+                       return this._toValue(L.DomUtil.getPosition(this._element).y);
+               }
+       });
+
+       var Zoomslider = L.Control.extend({
+               options: {
+                       position: 'topleft',
+                       // Height of zoom-slider.png in px
+                       stepHeight: 9,
+                       // Height of the knob div in px
+                       knobHeight: 5,
+                       styleNS: 'leaflet-control-zoomslider'
+               },
+
+               onAdd: function (map) {
+                       var container = L.DomUtil.create('div', this.options.styleNS + ' leaflet-bar');
+
+                       L.DomEvent.disableClickPropagation(container);
+
+                       this._map = map;
+
+                       this._zoomInButton = this._createZoomButton(
+                               'in', 'top', container, this._zoomIn);
+
+                       this._sliderElem = L.DomUtil.create(
+                               'div',
+                               this.options.styleNS + "-slider leaflet-bar-part",
+                               container);
+
+                       this._zoomOutButton = this._createZoomButton(
+                               'out', 'bottom', container, this._zoomOut);
+
+                       map .on('zoomlevelschange', this._refresh, this)
+                               .on("zoomend", this._updateKnob, this)
+                               .on("zoomend", this._updateDisabled, this)
+                               .whenReady(this._createSlider, this)
+                               .whenReady(this._createKnob, this)
+                               .whenReady(this._refresh, this);
+
+                       return container;
+               },
+
+               onRemove: function (map) {
+                       map .off("zoomend", this._updateKnob)
+                               .off("zoomend", this._updateDisabled)
+                               .off('zoomlevelschange', this._refresh);
+               },
+
+               _refresh: function () {
+                       var zoomLevels = this._zoomLevels();
+                       if (zoomLevels < Infinity  && this._knob  && this._sliderBody) {
+                               this._setSteps(zoomLevels);
+                               this._updateKnob();
+                               this._updateDisabled();
+                       }
+               },
+               _zoomLevels: function () {
+                       return this._map.getMaxZoom() - this._map.getMinZoom() + 1;
+               },
+
+               _createSlider: function () {
+                       this._sliderBody = L.DomUtil.create('div',
+                                                                                               this.options.styleNS + '-slider-body',
+                                                                                               this._sliderElem);
+                       L.DomEvent.on(this._sliderBody, 'click', this._onSliderClick, this);
+               },
+
+               _createKnob: function () {
+                       var knobElem = L.DomUtil.create('div', this.options.styleNS + '-slider-knob',
+                                                                                       this._sliderBody);
+                       L.DomEvent.disableClickPropagation(knobElem);
+
+                       this._knob = new Knob(knobElem,
+                                                                 this.options.stepHeight,
+                                                                 this.options.knobHeight)
+                               .on('dragend', this._updateZoom, this);
+                       this._knob.enable();
+               },
+
+               _onSliderClick: function (e) {
+                       var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e);
+                       var y = L.DomEvent.getMousePosition(first).y
+                                       - L.DomUtil.getViewportOffset(this._sliderBody).y; // Cache this?
+                       this._knob.setPosition(y);
+                       this._updateZoom();
+               },
+
+               _zoomIn: function (e) {
+                       this._map.zoomIn(e.shiftKey ? 3 : 1);
+               },
+               _zoomOut: function (e) {
+                       this._map.zoomOut(e.shiftKey ? 3 : 1);
+               },
+
+               _createZoomButton: function (zoomDir, end, container, fn) {
+                       var barPart = 'leaflet-bar-part',
+                               classDef = this.options.styleNS + '-' + zoomDir
+                                       + ' ' + barPart
+                                       + ' ' + barPart + '-' + end,
+                               title = 'Zoom ' + zoomDir,
+                               link = L.DomUtil.create('a', classDef, container);
+                       link.href = '#';
+                       link.title = title;
+
+                       L.DomEvent
+                               .on(link, 'click', L.DomEvent.preventDefault)
+                               .on(link, 'click', fn, this);
+
+                       return link;
+               },
+               _toZoomLevel: function (value) {
+                       return value + this._map.getMinZoom();
+               },
+               _toValue: function (zoomLevel) {
+                       return zoomLevel - this._map.getMinZoom();
+               },
+               _setSteps: function (zoomLevels) {
+                       this._sliderBody.style.height 
+                               = (this.options.stepHeight * zoomLevels) + "px";
+                       this._knob.setSteps(zoomLevels);
+               },
+               _updateZoom: function () {
+                       this._map.setZoom(this._toZoomLevel(this._knob.getValue()));
+               },
+               _updateKnob: function () {
+                       if (this._knob) {
+                               this._knob.setValue(this._toValue(this._map.getZoom()));
+                       }
+               },
+               _updateDisabled: function () {
+                       var map = this._map,
+                               className = this.options.styleNS + '-disabled';
+
+                       L.DomUtil.removeClass(this._zoomInButton, className);
+                       L.DomUtil.removeClass(this._zoomOutButton, className);
+
+                       if (map.getZoom() === map.getMinZoom()) {
+                               L.DomUtil.addClass(this._zoomOutButton, className);
+                       }
+                       if (map.getZoom() === map.getMaxZoom()) {
+                               L.DomUtil.addClass(this._zoomInButton, className);
+                       }
+               }
+       });
+       return Zoomslider;
+})();
+
+L.Map.mergeOptions({
+    zoomControl: false,
+    zoomsliderControl: true
+});
+
+L.Map.addInitHook(function () {
+    if (this.options.zoomsliderControl) {
+               this.zoomsliderControl = new L.Control.Zoomslider();
+               this.addControl(this.zoomsliderControl);
+       }
+});
+
+L.control.zoomslider = function (options) {
+    return new L.Control.Zoomslider(options);
+};