leaflet-timedimension
Version:
Add time dimension capabilities on a Leaflet map
313 lines (277 loc) • 9.57 kB
JavaScript
L.TimeDimension.Layer.ImageOverlay = L.TimeDimension.Layer.extend({
initialize: function(layer, options) {
L.TimeDimension.Layer.prototype.initialize.call(this, layer, options);
this._layers = {};
this._defaultTime = 0;
this._timeCacheBackward = this.options.cacheBackward || this.options.cache || 0;
this._timeCacheForward = this.options.cacheForward || this.options.cache || 0;
this._getUrlFunction = this.options.getUrlFunction;
this._baseLayer.on('load', (function() {
this._baseLayer.setLoaded(true);
this.fire('timeload', {
time: this._defaultTime
});
}).bind(this));
},
eachLayer: function(method, context) {
for (var prop in this._layers) {
if (this._layers.hasOwnProperty(prop)) {
method.call(context, this._layers[prop]);
}
}
return L.TimeDimension.Layer.prototype.eachLayer.call(this, method, context);
},
_onNewTimeLoading: function(ev) {
var layer = this._getLayerForTime(ev.time);
if (!this._map.hasLayer(layer)) {
this._map.addLayer(layer);
}
},
isReady: function(time) {
var layer = this._getLayerForTime(time);
return layer.isLoaded();
},
_update: function() {
if (!this._map)
return;
var time = map.timeDimension.getCurrentTime();
var layer = this._getLayerForTime(time);
if (this._currentLayer == null) {
this._currentLayer = layer;
}
if (!this._map.hasLayer(layer)) {
this._map.addLayer(layer);
} else {
this._showLayer(layer, time);
}
},
_showLayer: function(layer, time) {
if (this._currentLayer && this._currentLayer !== layer) {
this._currentLayer.hide();
this._map.removeLayer(this._currentLayer);
}
layer.show();
if (this._currentLayer && this._currentLayer === layer) {
return;
}
this._currentLayer = layer;
// Cache management
var times = this._getLoadedTimes();
var strTime = String(time);
var index = times.indexOf(strTime);
var remove = [];
// remove times before current time
if (this._timeCacheBackward > -1) {
var objectsToRemove = index - this._timeCacheBackward;
if (objectsToRemove > 0) {
remove = times.splice(0, objectsToRemove);
this._removeLayers(remove);
}
}
if (this._timeCacheForward > -1) {
index = times.indexOf(strTime);
var objectsToRemove = times.length - index - this._timeCacheForward - 1;
if (objectsToRemove > 0) {
remove = times.splice(index + this._timeCacheForward + 1, objectsToRemove);
this._removeLayers(remove);
}
}
},
_getLayerForTime: function(time) {
if (time == 0 || time == this._defaultTime) {
return this._baseLayer;
}
if (this._layers.hasOwnProperty(time)) {
return this._layers[time];
}
var url = this._getUrlFunction(this._baseLayer.getURL(), time);
imageBounds = this._baseLayer._bounds;
var newLayer = L.imageOverlay(url, imageBounds, this._baseLayer.options);
this._layers[time] = newLayer;
newLayer.on('load', (function(layer, time) {
layer.setLoaded(true);
if (map.timeDimension && time == map.timeDimension.getCurrentTime() && !map.timeDimension.isLoading()) {
this._showLayer(layer, time);
}
this.fire('timeload', {
time: time
});
}).bind(this, newLayer, time));
// Hack to hide the layer when added to the map.
// It will be shown when timeload event is fired from the map (after all layers are loaded)
newLayer.onAdd = (function(map) {
Object.getPrototypeOf(this).onAdd.call(this, map);
this.hide();
}).bind(newLayer);
return newLayer;
},
_getLoadedTimes: function() {
var result = [];
for (var prop in this._layers) {
if (this._layers.hasOwnProperty(prop)) {
result.push(prop);
}
}
return result.sort();
},
_removeLayers: function(times) {
for (var i = 0, l = times.length; i < l; i++) {
this._map.removeLayer(this._layers[times[i]]);
delete this._layers[times[i]];
}
},
});
L.timeDimension.layer.imageOverlay = function(layer, options) {
return new L.TimeDimension.Layer.ImageOverlay(layer, options);
};
L.ImageOverlay.include({
_visible: true,
_loaded: false,
_originalUpdate: L.imageOverlay.prototype._update,
_update: function() {
if (!this._visible && this._loaded) {
return;
}
this._originalUpdate();
},
setLoaded: function(loaded) {
this._loaded = loaded;
},
isLoaded: function() {
return this._loaded;
},
hide: function() {
this._visible = false;
if (this._image && this._image.style)
this._image.style.display = 'none';
},
show: function() {
this._visible = true;
if (this._image && this._image.style)
this._image.style.display = 'block';
},
getURL: function() {
return this._url;
},
});
var map = L.map('map', {
zoom: 15,
timeDimension: true,
timeDimensionOptions: {
timeInterval: "2014-01-01/2014-12-31",
period: "PT1H",
validTimeRange: "06:00/15:00",
currentTime: Date.parse("2014-08-01T12:00:00Z")
},
timeDimensionControl: false,
timeDimensionControlOptions: {
autoPlay: false,
playerOptions: {
buffer: 10,
transitionTime: 500,
loop: true,
}
},
center: [38.70, 1.15],
});
// Add image layer
var imageUrl = 'http://www.socib.es/users/mobims/imageArchive/clm/sirena/clm/c04/2014/01/11/clm_s_04_2014-01-01-12-00.png',
imageBounds = [
[38.69, 1.1675],
[38.71, 1.1325]
];
var imageLayer = L.imageOverlay(imageUrl, imageBounds, {
opacity: 0.5
});
Date.prototype.format = function (mask, utc) {
return dateFormat(this, mask, utc);
};
var getSirenaImageUrl = function(baseUrl, time) {
var beginUrl = baseUrl.substring(0, baseUrl.lastIndexOf("/") - 10);
beginUrl = beginUrl + new Date(time).format('yyyy/mm/dd');
var strTime = new Date(time).format('yyyy-mm-dd-HH-MM');
var initFileUrl = baseUrl.substring(baseUrl.lastIndexOf("/"), baseUrl.length - 20);
url = beginUrl + initFileUrl + strTime + '.png';
return url;
};
var testImageTimeLayer = L.timeDimension.layer.imageOverlay(imageLayer, {
getUrlFunction: getSirenaImageUrl
});
testImageTimeLayer.addTo(map);
// Create wind chart
$.getJSON('js/example10-data.json', function(data) {
// Create the chart
$('#chart').highcharts('StockChart', {
rangeSelector: {
selected: 2
},
title: {
text: 'Wind average at Cala Millor'
},
tooltip: {
formatter: function() {
var s = '<b>' + Highcharts.dateFormat('%A %b %e, %Y', this.x) + '</b>';
$.each(this.points, function(i, point) {
s += '<br/><strong>Wind</strong>: ' + point.y.toFixed(2) + ' m/s';
});
return s;
},
shared: true
},
series: [{
name: 'WIND',
data: data,
}],
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function(event) {
var day = new Date(event.point.x);
day.setUTCHours(12, 0, 0);
map.timeDimension.setCurrentTime(day.getTime());
}
}
}
}
}
});
});
// basic custom control
var controlContainer = $("#mapcontrol");
map.timeDimension.on('timeload', function(data) {
var date = new Date(map.timeDimension.getCurrentTime());
controlContainer.find('span.date').html(date.format("dd/mm/yyyy", true));
controlContainer.find('span.time').html(date.format("HH:MM", true));
if (data.time == map.timeDimension.getCurrentTime()) {
$('#map').removeClass('map-loading');
}
});
map.timeDimension.on('timeloading', function(data) {
if (data.time == map.timeDimension.getCurrentTime()) {
$('#map').addClass('map-loading');
}
});
controlContainer.find('.btn-prev').click(function() {
map.timeDimension.previousTime();
});
controlContainer.find('.btn-next').click(function() {
map.timeDimension.nextTime();
});
var player = new L.TimeDimension.Player({}, map.timeDimension);
controlContainer.find('.btn-play').click(function() {
var btn = $(this);
if (player.isPlaying()) {
btn.removeClass("btn-pause");
btn.addClass("btn-play");
btn.html("Play");
player.stop();
} else {
btn.removeClass("btn-play");
btn.addClass("btn-pause");
btn.html("Pause");
player.start();
}
});
map.timeDimension.setCurrentTime(new Date(2014, 0, 1, 13, 00).getTime());