mirror of
https://github.com/medialab-prado/poblados-colonizacion-colonias-penitenciarias.git
synced 2024-12-27 04:51:22 +01:00
378 lines
12 KiB
JavaScript
378 lines
12 KiB
JavaScript
|
/*jshint indent: 4, browser:true*/
|
||
|
/*global L*/
|
||
|
/*
|
||
|
* L.TimeDimension: TimeDimension object manages the time component of a layer.
|
||
|
* It can be shared among different layers and it can be added to a map, and become
|
||
|
* the default timedimension component for any layer added to the map.
|
||
|
*/
|
||
|
|
||
|
L.TimeDimension = (L.Layer || L.Class).extend({
|
||
|
|
||
|
includes: L.Mixin.Events,
|
||
|
|
||
|
initialize: function (options) {
|
||
|
L.setOptions(this, options);
|
||
|
// _availableTimes is an array with all the available times in ms.
|
||
|
this._availableTimes = this._generateAvailableTimes();
|
||
|
this._currentTimeIndex = -1;
|
||
|
this._loadingTimeIndex = -1;
|
||
|
this._loadingTimeout = this.options.loadingTimeout || 3000;
|
||
|
this._syncedLayers = [];
|
||
|
if (this._availableTimes.length > 0) {
|
||
|
this.setCurrentTime(this.options.currentTime || this._getDefaultCurrentTime());
|
||
|
}
|
||
|
if (this.options.lowerLimitTime) {
|
||
|
this.setLowerLimit(this.options.lowerLimitTime);
|
||
|
}
|
||
|
if (this.options.upperLimitTime) {
|
||
|
this.setUpperLimit(this.options.upperLimitTime);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getAvailableTimes: function () {
|
||
|
return this._availableTimes;
|
||
|
},
|
||
|
|
||
|
getCurrentTimeIndex: function () {
|
||
|
if (this._currentTimeIndex === -1) {
|
||
|
return this._availableTimes.length - 1;
|
||
|
}
|
||
|
return this._currentTimeIndex;
|
||
|
},
|
||
|
|
||
|
getCurrentTime: function () {
|
||
|
var index = -1;
|
||
|
if (this._loadingTimeIndex !== -1) {
|
||
|
index = this._loadingTimeIndex;
|
||
|
} else {
|
||
|
index = this.getCurrentTimeIndex();
|
||
|
}
|
||
|
if (index >= 0) {
|
||
|
return this._availableTimes[index];
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
isLoading: function () {
|
||
|
return (this._loadingTimeIndex !== -1);
|
||
|
},
|
||
|
|
||
|
setCurrentTimeIndex: function (newIndex) {
|
||
|
var upperLimit = this._upperLimit || this._availableTimes.length - 1;
|
||
|
var lowerLimit = this._lowerLimit || 0;
|
||
|
//clamp the value
|
||
|
newIndex = Math.min(Math.max(lowerLimit, newIndex), upperLimit);
|
||
|
if (newIndex < 0) {
|
||
|
return;
|
||
|
}
|
||
|
this._loadingTimeIndex = newIndex;
|
||
|
var newTime = this._availableTimes[newIndex];
|
||
|
console.log('INIT -- Current time: ' + new Date(newTime).toISOString());
|
||
|
if (this._checkSyncedLayersReady(this._availableTimes[this._loadingTimeIndex])) {
|
||
|
this._newTimeIndexLoaded();
|
||
|
} else {
|
||
|
this.fire('timeloading', {
|
||
|
time: newTime
|
||
|
});
|
||
|
// add timeout of 3 seconds if layers doesn't response
|
||
|
setTimeout((function (index) {
|
||
|
if (index == this._loadingTimeIndex) {
|
||
|
console.log('Change time for timeout');
|
||
|
this._newTimeIndexLoaded();
|
||
|
}
|
||
|
}).bind(this, newIndex), this._loadingTimeout);
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
_newTimeIndexLoaded: function () {
|
||
|
if (this._loadingTimeIndex === -1) {
|
||
|
return;
|
||
|
}
|
||
|
var time = this._availableTimes[this._loadingTimeIndex];
|
||
|
console.log('END -- Current time: ' + new Date(time).toISOString());
|
||
|
this._currentTimeIndex = this._loadingTimeIndex;
|
||
|
this.fire('timeload', {
|
||
|
time: time
|
||
|
});
|
||
|
this._loadingTimeIndex = -1;
|
||
|
},
|
||
|
|
||
|
_checkSyncedLayersReady: function (time) {
|
||
|
for (var i = 0, len = this._syncedLayers.length; i < len; i++) {
|
||
|
if (this._syncedLayers[i].isReady) {
|
||
|
if (!this._syncedLayers[i].isReady(time)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
},
|
||
|
|
||
|
setCurrentTime: function (time) {
|
||
|
var newIndex = this._seekNearestTimeIndex(time);
|
||
|
this.setCurrentTimeIndex(newIndex);
|
||
|
},
|
||
|
|
||
|
seekNearestTime: function (time) {
|
||
|
var index = this._seekNearestTimeIndex(time);
|
||
|
return this._availableTimes[index];
|
||
|
},
|
||
|
|
||
|
nextTime: function (numSteps, loop) {
|
||
|
if (!numSteps) {
|
||
|
numSteps = 1;
|
||
|
}
|
||
|
var newIndex = this._currentTimeIndex;
|
||
|
var upperLimit = this._upperLimit || this._availableTimes.length - 1;
|
||
|
var lowerLimit = this._lowerLimit || 0;
|
||
|
if (this._loadingTimeIndex > -1) {
|
||
|
newIndex = this._loadingTimeIndex;
|
||
|
}
|
||
|
newIndex = newIndex + numSteps;
|
||
|
if (newIndex > upperLimit) {
|
||
|
if (!!loop) {
|
||
|
newIndex = lowerLimit;
|
||
|
} else {
|
||
|
newIndex = upperLimit;
|
||
|
}
|
||
|
}
|
||
|
// loop backwards
|
||
|
if (newIndex < lowerLimit) {
|
||
|
if (!!loop) {
|
||
|
newIndex = upperLimit;
|
||
|
} else {
|
||
|
newIndex = lowerLimit;
|
||
|
}
|
||
|
}
|
||
|
this.setCurrentTimeIndex(newIndex);
|
||
|
},
|
||
|
|
||
|
prepareNextTimes: function (numSteps, howmany, loop) {
|
||
|
if (!numSteps) {
|
||
|
numSteps = 1;
|
||
|
}
|
||
|
|
||
|
var newIndex = this._currentTimeIndex;
|
||
|
var currentIndex = newIndex;
|
||
|
if (this._loadingTimeIndex > -1) {
|
||
|
newIndex = this._loadingTimeIndex;
|
||
|
}
|
||
|
// assure synced layers have a buffer/cache of at least howmany elements
|
||
|
for (var i = 0, len = this._syncedLayers.length; i < len; i++) {
|
||
|
if (this._syncedLayers[i].setMinimumForwardCache) {
|
||
|
this._syncedLayers[i].setMinimumForwardCache(howmany);
|
||
|
}
|
||
|
}
|
||
|
var count = howmany;
|
||
|
var upperLimit = this._upperLimit || this._availableTimes.length - 1;
|
||
|
var lowerLimit = this._lowerLimit || 0;
|
||
|
while (count > 0) {
|
||
|
newIndex = newIndex + numSteps;
|
||
|
if (newIndex > upperLimit) {
|
||
|
if (!!loop) {
|
||
|
newIndex = lowerLimit;
|
||
|
} else {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (newIndex < lowerLimit) {
|
||
|
if (!!loop) {
|
||
|
newIndex = upperLimit;
|
||
|
} else {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (currentIndex === newIndex) {
|
||
|
//we looped around the timeline
|
||
|
//no need to load further, the next times are already loading
|
||
|
break;
|
||
|
}
|
||
|
this.fire('timeloading', {
|
||
|
time: this._availableTimes[newIndex]
|
||
|
});
|
||
|
count--;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getNumberNextTimesReady: function (numSteps, howmany, loop) {
|
||
|
if (!numSteps) {
|
||
|
numSteps = 1;
|
||
|
}
|
||
|
|
||
|
var newIndex = this._currentTimeIndex;
|
||
|
if (this._loadingTimeIndex > -1) {
|
||
|
newIndex = this._loadingTimeIndex;
|
||
|
}
|
||
|
var count = howmany;
|
||
|
var ready = 0;
|
||
|
var upperLimit = this._upperLimit || this._availableTimes.length - 1;
|
||
|
var lowerLimit = this._lowerLimit || 0;
|
||
|
while (count > 0) {
|
||
|
newIndex = newIndex + numSteps;
|
||
|
if (newIndex > upperLimit) {
|
||
|
if (!!loop) {
|
||
|
newIndex = lowerLimit;
|
||
|
} else {
|
||
|
count = 0;
|
||
|
ready = howmany;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (newIndex < lowerLimit) {
|
||
|
if (!!loop) {
|
||
|
newIndex = upperLimit;
|
||
|
} else {
|
||
|
count = 0;
|
||
|
ready = howmany;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
var time = this._availableTimes[newIndex];
|
||
|
if (this._checkSyncedLayersReady(time)) {
|
||
|
ready++;
|
||
|
}
|
||
|
count--;
|
||
|
}
|
||
|
return ready;
|
||
|
},
|
||
|
|
||
|
previousTime: function (numSteps, loop) {
|
||
|
this.nextTime(numSteps*(-1), loop);
|
||
|
},
|
||
|
|
||
|
registerSyncedLayer: function (layer) {
|
||
|
this._syncedLayers.push(layer);
|
||
|
layer.on('timeload', this._onSyncedLayerLoaded, this);
|
||
|
},
|
||
|
|
||
|
unregisterSyncedLayer: function (layer) {
|
||
|
var index = this._syncedLayers.indexOf(layer);
|
||
|
if (index != -1) {
|
||
|
this._syncedLayers.splice(index, 1);
|
||
|
}
|
||
|
layer.off('timeload', this._onSyncedLayerLoaded, this);
|
||
|
},
|
||
|
|
||
|
_onSyncedLayerLoaded: function (e) {
|
||
|
if (e.time == this._availableTimes[this._loadingTimeIndex] && this._checkSyncedLayersReady(e.time)) {
|
||
|
this._newTimeIndexLoaded();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_generateAvailableTimes: function () {
|
||
|
if (this.options.times) {
|
||
|
return L.TimeDimension.Util.parseTimesExpression(this.options.times);
|
||
|
} else if (this.options.timeInterval) {
|
||
|
var tiArray = L.TimeDimension.Util.parseTimeInterval(this.options.timeInterval);
|
||
|
var period = this.options.period || 'P1D';
|
||
|
var validTimeRange = this.options.validTimeRange || undefined;
|
||
|
return L.TimeDimension.Util.explodeTimeRange(tiArray[0], tiArray[1], period, validTimeRange);
|
||
|
} else {
|
||
|
return [];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_getDefaultCurrentTime: function () {
|
||
|
var index = this._seekNearestTimeIndex(new Date().getTime());
|
||
|
return this._availableTimes[index];
|
||
|
},
|
||
|
|
||
|
_seekNearestTimeIndex: function (time) {
|
||
|
var newIndex = 0;
|
||
|
var len = this._availableTimes.length;
|
||
|
for (; newIndex < len; newIndex++) {
|
||
|
if (time < this._availableTimes[newIndex]) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// We've found the first index greater than the time. Return the previous
|
||
|
if (newIndex > 0) {
|
||
|
newIndex--;
|
||
|
}
|
||
|
return newIndex;
|
||
|
},
|
||
|
|
||
|
setAvailableTimes: function (times, mode) {
|
||
|
var currentTime = this.getCurrentTime(),
|
||
|
lowerLimitTime = this.getLowerLimit(),
|
||
|
upperLimitTime = this.getUpperLimit();
|
||
|
|
||
|
if (mode == 'extremes') {
|
||
|
var period = this.options.period || 'P1D';
|
||
|
this._availableTimes = L.TimeDimension.Util.explodeTimeRange(new Date(times[0]), new Date(times[times.length - 1]), period);
|
||
|
} else {
|
||
|
var parsedTimes = L.TimeDimension.Util.parseTimesExpression(times);
|
||
|
if (this._availableTimes.length === 0) {
|
||
|
this._availableTimes = parsedTimes;
|
||
|
} else if (mode == 'intersect') {
|
||
|
this._availableTimes = L.TimeDimension.Util.intersect_arrays(parsedTimes, this._availableTimes);
|
||
|
} else if (mode == 'union') {
|
||
|
this._availableTimes = L.TimeDimension.Util.union_arrays(parsedTimes, this._availableTimes);
|
||
|
} else if (mode == 'replace') {
|
||
|
this._availableTimes = parsedTimes;
|
||
|
} else {
|
||
|
throw 'Merge available times mode not implemented: ' + mode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (lowerLimitTime) {
|
||
|
this.setLowerLimit(lowerLimitTime); //restore lower limit
|
||
|
}
|
||
|
if (upperLimitTime) {
|
||
|
this.setUpperLimit(upperLimitTime); //restore upper limit
|
||
|
}
|
||
|
this.setCurrentTime(currentTime);
|
||
|
this.fire('availabletimeschanged', {
|
||
|
availableTimes: this._availableTimes,
|
||
|
currentTime: currentTime
|
||
|
});
|
||
|
console.log('available times changed');
|
||
|
},
|
||
|
getLowerLimit: function () {
|
||
|
return this._availableTimes[this.getLowerLimitIndex()];
|
||
|
},
|
||
|
getUpperLimit: function () {
|
||
|
return this._availableTimes[this.getUpperLimitIndex()];
|
||
|
},
|
||
|
setLowerLimit: function (time) {
|
||
|
var index = this._seekNearestTimeIndex(time);
|
||
|
this.setLowerLimitIndex(index);
|
||
|
},
|
||
|
setUpperLimit: function (time) {
|
||
|
var index = this._seekNearestTimeIndex(time);
|
||
|
this.setUpperLimitIndex(index);
|
||
|
},
|
||
|
setLowerLimitIndex: function (index) {
|
||
|
this._lowerLimit = Math.min(Math.max(index || 0, 0), this._upperLimit || this._availableTimes.length - 1);
|
||
|
this.fire('limitschanged', {
|
||
|
lowerLimit: this._lowerLimit,
|
||
|
upperLimit: this._upperLimit
|
||
|
});
|
||
|
},
|
||
|
setUpperLimitIndex: function (index) {
|
||
|
this._upperLimit = Math.max(Math.min(index, this._availableTimes.length - 1), this._lowerLimit || 0);
|
||
|
this.fire('limitschanged', {
|
||
|
lowerLimit: this._lowerLimit,
|
||
|
upperLimit: this._upperLimit
|
||
|
});
|
||
|
},
|
||
|
getLowerLimitIndex: function () {
|
||
|
return this._lowerLimit;
|
||
|
},
|
||
|
getUpperLimitIndex: function () {
|
||
|
return this._upperLimit;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.Map.addInitHook(function () {
|
||
|
if (this.options.timeDimension) {
|
||
|
this.timeDimension = L.timeDimension(this.options.timeDimensionOptions || {});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.timeDimension = function (options) {
|
||
|
return new L.TimeDimension(options);
|
||
|
};
|