poblados-colonizacion-colon.../docs/colonizacion-leaflet/js/leaflet.timedimension.js
2017-06-18 04:33:09 +02:00

377 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);
};