Flyer slider by year
I am using the leaflet slider - https://github.com/dwilhelm89/LeafletSlider - but I cannot get the desired result, even if it seems possible from the plugin description.
I have a set of functions, the geometry type is a polygon, where I inserted the "time" property as requested by the plugin. I tried a bot with "time": "2014" and "time": "2014-01-01 00:00:00" with no difference. I have 30 functions, 10 for 2012, 10 for 2013 and 10 for 2014.
What I'm trying to achieve is to show the entire polygon of 2012, then 2013 and 2014 by moving the slider, which should have 3 steps, one step every year.
Instead, I always get one polygon every time I move the slider. In the beginning I also get all polygons (30) created on top of each other, even if I specify "showAllOnStart: false"
here is my js code:
var geojson;
$(document).ready(function () {
$.getJSON("urlWhereIretrieveTheJson", function (geoJson) {
geojson = L.geoJson(geoJson, { style: style, onEachFeature: onEachFeature }).addTo(map);
var sliderControl = L.control.sliderControl({
position: "bottomleft",
layer: geojson,
range: false,
showAllOnStart: false
});
map.addControl(sliderControl);
sliderControl.startSlider();
;
});
});
json schema looks like this:
{"type": "FeatureCollection",
"features": [
{"type":"Feature",
"properties": {"name": "Thies","bl": 6,"**time**": "**2013-01-01 00:00:00+00**"},
"geometry":{"type":"Polygon","coordinates":[....]}
},{....}
]}
Here is a jsFiddle with complete code and data source: http://jsfiddle.net/brainsengineering/nboo4ksg/
source to share
The answer to one thing:
I get also all polygons (30) created on top of each other even if I specify "showAllOnStart: false"
is that you add geojson
this way
geojson = L.geoJson(geoJson, { style: style, onEachFeature: onEachFeature }).addTo(map);
don't add addTo(map)
to the end, just do it
geojson = L.geoJson(geoJson, { style: style, onEachFeature: onEachFeature });
Another thing is that you want to group your data based on the same values , that is, the group data for 2013, 2014 and 2015. For this we need to modify the plugin a bit, because currently the plugin does not process group data based on the same values. So here is the code
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: -1,
showAllOnStart: false,
markers: null,
range: false,
follow: 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('<div id="leaflet-slider" style="width:200px"><div class="ui-slider-handle"></div><div id="slider-timestamp" style="width:200px; margin-top:13px; background-color:#FFFFFF; text-align:center; border-radius:5px;"></div></div>');
//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 = [];
this.options.unique_time_values = [];
//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) {
//console.log(layer);
options.markers[index_temp] = layer;
++index_temp;
});
options.maxValue = index_temp - 1;
this.options = options;*/
var flags = [], unique_values = [],len;
this._layer.eachLayer(function (layer) {
if( flags[layer.feature.properties.time]) return;
flags[layer.feature.properties.time] = true;
unique_values.push(layer.feature.properties.time);
++len;
});
//console.log(unique_values);
var all_features = [];
for (var i=0;i<unique_values.length;i++){
all_features[i] = [];
}
//console.log(all_features);
//console.log(this._layer.getLayers().length)
var layers = this._layer.getLayers()
for(var i=0;i<layers.length;i++){
//console.log(layers[i].feature.properties.time);
var index = unique_values.indexOf(layers[i].feature.properties.time)
//console.log(index);
all_features[index].push(layers[i]);
}
//console.log(all_features);
for (var i=0;i<all_features.length;i++){
options.markers[i] = L.featureGroup(all_features[i]);
}
options.maxValue = all_features.length - 1;
this.options = options;
this.options.unique_time_values = unique_values
} 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();
},
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.minValue,
values: _options.values,
min: _options.minValue,
max: _options.maxValue,
step: 1,
slide: function (e, ui) {
var map = _options.map;
var fg = L.featureGroup();
if(!!_options.markers[ui.value]) {
//console.log('inside');
// 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.unique_values[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.unique_time_values[ui.value]){
if(_options.markers[ui.value]) $('#slider-timestamp').html(
_extractTimestamp(_options.unique_time_values[ui.value], _options));
}else {
console.error("Time property "+ _options.timeAttribute +" not found in data");
}
}
var i;
// clear markers
for (i = _options.minValue+1; 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{
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);
};
Just remove the link to the current plugin source and use the above code instead of the plugin file and it will work. Tell me if you run into any problems, so I'll create one for you as well fiddle
.
Note. Since I changed the code for your specific case, it may not work in other scenarios
source to share