diff --git a/website/SliderControl.js b/website/SliderControl.js
new file mode 100644
index 0000000..c32e08b
--- /dev/null
+++ b/website/SliderControl.js
@@ -0,0 +1,193 @@
+L.Control.SliderControl = L.Control.extend({
+ options: {
+ position: 'topright',
+ layers: null,
+ timeAttribute: 'time',
+ isEpoch: false, // whether the time attribute is seconds elapsed from epoch
+ startTimeIdx: 0, // where to start looking for a timestring
+ timeStrLength: 19, // the size of yyyy-mm-dd hh:mm:ss - if millis are present this will be larger
+ maxValue: -1,
+ minValue: 0,
+ showAllOnStart: false,
+ markers: null,
+ range: false,
+ follow: false,
+ sameDate: false,
+ alwaysShowDate : false,
+ rezoom: null
+ },
+
+ initialize: function (options) {
+ L.Util.setOptions(this, options);
+ this._layer = this.options.layer;
+
+ },
+
+ extractTimestamp: function(time, options) {
+ if (options.isEpoch) {
+ time = (new Date(parseInt(time))).toString(); // this is local time
+ }
+ return time.substr(options.startTimeIdx, options.startTimeIdx + options.timeStrLength);
+ },
+
+ setPosition: function (position) {
+ var map = this._map;
+
+ if (map) {
+ map.removeControl(this);
+ }
+
+ this.options.position = position;
+
+ if (map) {
+ map.addControl(this);
+ }
+ this.startSlider();
+ return this;
+ },
+
+ onAdd: function (map) {
+ this.options.map = map;
+
+ // Create a control sliderContainer with a jquery ui slider
+ var sliderContainer = L.DomUtil.create('div', 'slider', this._container);
+ $(sliderContainer).append('
');
+ //Prevent map panning/zooming while using the slider
+ $(sliderContainer).mousedown(function () {
+ map.dragging.disable();
+ });
+ $(document).mouseup(function () {
+ map.dragging.enable();
+ //Hide the slider timestamp if not range and option alwaysShowDate is set on false
+ if (options.range || !options.alwaysShowDate) {
+ $('#slider-timestamp').html('');
+ }
+ });
+
+ var options = this.options;
+ this.options.markers = [];
+
+ //If a layer has been provided: calculate the min and max values for the slider
+ if (this._layer) {
+ var index_temp = 0;
+ this._layer.eachLayer(function (layer) {
+ options.markers[index_temp] = layer;
+ ++index_temp;
+ });
+ options.maxValue = index_temp - 1;
+ this.options = options;
+ } else {
+ console.log("Error: You have to specify a layer via new SliderControl({layer: your_layer});");
+ }
+ return sliderContainer;
+ },
+
+ onRemove: function (map) {
+ //Delete all markers which where added via the slider and remove the slider div
+ for (i = this.options.minValue; i <= this.options.maxValue; i++) {
+ map.removeLayer(this.options.markers[i]);
+ }
+ $('#leaflet-slider').remove();
+
+ // unbind listeners to prevent memory leaks
+ $(document).off("mouseup");
+ $(".slider").off("mousedown");
+ },
+
+ startSlider: function () {
+ _options = this.options;
+ _extractTimestamp = this.extractTimestamp
+ var index_start = _options.minValue;
+ if(_options.showAllOnStart){
+ index_start = _options.maxValue;
+ if(_options.range) _options.values = [_options.minValue,_options.maxValue];
+ else _options.value = _options.maxValue;
+ }
+ $("#leaflet-slider").slider({
+ range: _options.range,
+ value: _options.value,
+ values: _options.values,
+ min: _options.minValue,
+ max: _options.maxValue,
+ sameDate: _options.sameDate,
+ step: 1,
+ slide: function (e, ui) {
+ var map = _options.map;
+ var fg = L.featureGroup();
+ if(!!_options.markers[ui.value]) {
+ // If there is no time property, this line has to be removed (or exchanged with a different property)
+ if(_options.markers[ui.value].feature !== undefined) {
+ if(_options.markers[ui.value].feature.properties[_options.timeAttribute]){
+ if(_options.markers[ui.value]) $('#slider-timestamp').html(
+ _extractTimestamp(_options.markers[ui.value].feature.properties[_options.timeAttribute], _options));
+ }else {
+ console.error("Time property "+ _options.timeAttribute +" not found in data");
+ }
+ }else {
+ // set by leaflet Vector Layers
+ if(_options.markers [ui.value].options[_options.timeAttribute]){
+ if(_options.markers[ui.value]) $('#slider-timestamp').html(
+ _extractTimestamp(_options.markers[ui.value].options[_options.timeAttribute], _options));
+ }else {
+ console.error("Time property "+ _options.timeAttribute +" not found in data");
+ }
+ }
+
+ var i;
+ // clear markers
+ for (i = _options.minValue; i <= _options.maxValue; i++) {
+ if(_options.markers[i]) map.removeLayer(_options.markers[i]);
+ }
+ if(_options.range){
+ // jquery ui using range
+ for (i = ui.values[0]; i <= ui.values[1]; i++){
+ if(_options.markers[i]) {
+ map.addLayer(_options.markers[i]);
+ fg.addLayer(_options.markers[i]);
+ }
+ }
+ }else if(_options.follow){
+ for (i = ui.value - _options.follow + 1; i <= ui.value ; i++) {
+ if(_options.markers[i]) {
+ map.addLayer(_options.markers[i]);
+ fg.addLayer(_options.markers[i]);
+ }
+ }
+ }else if(_options.sameDate){
+ var currentTime;
+ if (_options.markers[ui.value].feature !== undefined) {
+ currentTime = _options.markers[ui.value].feature.properties.time;
+ } else {
+ currentTime = _options.markers[ui.value].options.time;
+ }
+ for (i = _options.minValue; i <= _options.maxValue; i++) {
+ if(_options.markers[i].options.time == currentTime) map.addLayer(_options.markers[i]);
+ }
+ }else{
+ for (i = _options.minValue; i <= ui.value ; i++) {
+ if(_options.markers[i]) {
+ map.addLayer(_options.markers[i]);
+ fg.addLayer(_options.markers[i]);
+ }
+ }
+ }
+ };
+ if(_options.rezoom) {
+ map.fitBounds(fg.getBounds(), {
+ maxZoom: _options.rezoom
+ });
+ }
+ }
+ });
+ if (!_options.range && _options.alwaysShowDate) {
+ $('#slider-timestamp').html(_extractTimeStamp(_options.markers[index_start].feature.properties[_options.timeAttribute], _options));
+ }
+ for (i = _options.minValue; i <= index_start; i++) {
+ _options.map.addLayer(_options.markers[i]);
+ }
+ }
+});
+
+L.control.sliderControl = function (options) {
+ return new L.Control.SliderControl(options);
+};