Update Leaflet.zoomslider

This commit is contained in:
Tom Hughes 2013-06-26 17:28:46 +01:00
parent cec2253b82
commit 15423c2130
2 changed files with 264 additions and 246 deletions

View file

@ -1,199 +1,213 @@
L.Control.Zoomslider = L.Control.extend({
options: {
position: 'topleft',
// height in px of zoom-slider.png
stepHeight: 9
},
onAdd: function (map) {
var className = 'leaflet-control-zoomslider',
container = L.DomUtil.create('div', className);
L.DomEvent.disableClickPropagation(container);
this._map = map;
this._zoomInButton = this._createButton('Zoom in', className + '-in'
, container, this._zoomIn , this);
this._createSlider(className + '-slider', container, map);
this._zoomOutButton = this._createButton('Zoom out', className + '-out'
, container, this._zoomOut, this);
map.on('layeradd layerremove', this._refresh, this);
map.whenReady(function(){
this._snapToSliderValue();
map.on('zoomend', this._snapToSliderValue, this);
}, this);
return container;
},
onRemove: function(map){
map.off('zoomend', this._snapToSliderValue);
map.off('layeradd layerremove', this._refresh);
},
_refresh: function(){
this._map
.removeControl(this)
.addControl(this);
},
_createSlider: function (className, container, map) {
var zoomLevels = map.getMaxZoom() - map.getMinZoom();
// This means we have no tilelayers (or that they are setup in a strange way).
// Either way we don't want to add a slider here.
if(zoomLevels == Infinity){
return undefined;
}
this._sliderHeight = this.options.stepHeight * zoomLevels;
var wrapper = L.DomUtil.create('div', className + '-wrap', container);
wrapper.style.height = (this._sliderHeight + 5) + "px";
var slider = L.DomUtil.create('div', className, wrapper);
this._knob = L.DomUtil.create('div', className + '-knob', slider);
this._draggable = this._createDraggable();
this._draggable.enable();
L.DomEvent.on(slider, 'click', this._onSliderClick, this);
return slider;
},
_zoomIn: function (e) {
this._map.zoomIn(e.shiftKey ? 3 : 1);
},
_zoomOut: function (e) {
this._map.zoomOut(e.shiftKey ? 3 : 1);
},
_createButton: function (title, className, container, fn, context) {
var link = L.DomUtil.create('a', className, container);
link.href = '#';
link.title = title;
L.DomEvent
.on(link, 'click', L.DomEvent.preventDefault)
.on(link, 'click', fn, context);
return link;
},
_createDraggable: function() {
L.DomUtil.setPosition(this._knob, L.point(0, 0));
L.DomEvent.disableClickPropagation(this._knob);
var bounds = new L.Bounds(
L.point(0, 0),
L.point(0, this._sliderHeight)
);
var draggable = new L.BoundedDraggable(this._knob,
this._knob,
bounds)
.on('drag', this._snap, this)
.on('dragend', this._setZoom, this);
return draggable;
},
_snap : function(){
this._snapToSliderValue(this._posToSliderValue());
},
_setZoom: function() {
this._map.setZoom(this._toZoomLevel(this._posToSliderValue()));
},
_onSliderClick: function(e){
var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e);
var offset = first.offsetY
? first.offsetY
: L.DomEvent.getMousePosition(first).y
- L.DomUtil.getViewportOffset(this._knob).y;
var value = this._posToSliderValue(offset - this._knob.offsetHeight / 2);
this._snapToSliderValue(value);
this._map.setZoom(this._toZoomLevel(value));
},
_posToSliderValue: function(pos) {
pos = isNaN(pos)
? L.DomUtil.getPosition(this._knob).y
: pos;
return Math.round( (this._sliderHeight - pos) / this.options.stepHeight);
},
_snapToSliderValue: function(sliderValue) {
this._updateDisabled();
if(this._knob) {
sliderValue = isNaN(sliderValue)
? this._getSliderValue()
: sliderValue;
var y = this._sliderHeight
- (sliderValue * this.options.stepHeight);
L.DomUtil.setPosition(this._knob, L.point(0, y));
}
},
_toZoomLevel: function(sliderValue) {
return sliderValue + this._map.getMinZoom();
},
_toSliderValue: function(zoomLevel) {
return zoomLevel - this._map.getMinZoom();
},
_getSliderValue: function(){
return this._toSliderValue(this._map.getZoom());
},
_updateDisabled: function () {
var map = this._map,
className = 'leaflet-control-zoomslider-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);
}
}
});
L.Map.mergeOptions({
zoomControl: false,
zoomsliderControl: true
});
L.Map.addInitHook(function () {
if (this.options.zoomsliderControl) {
L.control.zoomslider().addTo(this);
}
});
L.control.zoomslider = function (options) {
return new L.Control.Zoomslider(options);
};
L.BoundedDraggable = L.Draggable.extend({
initialize: function(element, dragStartTarget, bounds) {
L.Draggable.prototype.initialize.call(this, element, dragStartTarget);
this._bounds = bounds;
this.on('predrag', function() {
if(!this._bounds.contains(this._newPos)){
this._newPos = this._fitPoint(this._newPos);
}
}, this);
},
_fitPoint: function(point){
var closest = L.point(
Math.min(point.x, this._bounds.max.x),
Math.min(point.y, this._bounds.max.y)
);
closest.x = Math.max(closest.x, this._bounds.min.x);
closest.y = Math.max(closest.y, this._bounds.min.y);
return closest;
}
});
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);
};