
META-INF.resources.js.geojsf.TimeManager.js Maven / Gradle / Ivy
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control.js
* @requires OpenLayers/BaseTypes/Date.js
*/
/**
* Class: OpenLayers.Control.TimeManager
* Control to display and animate map layers across time.
*
* Inherits From:
* -
*/
OpenLayers.Control.TimeManager = OpenLayers.Class(OpenLayers.Control, {
/**
* Constant: EVENT_TYPES
*
* Supported event types:
* - *beforetick* Triggered before the control advances one step in time.
* Return false to prevent the tick from occuring.
* - *tick* Triggered when the control advances one step in time.
* Listeners receive an event object with a *currentTime* parameter.
* Event is fired after the time has been incremented but before the
* map or layer display is modified.
* - *play* Triggered when the control begins a time-series animation.
* - *stop* Triggered when the control stops a time-series animation.
* Listeners receive an event object with a {Boolean} *rangeExceeded*
* property indicating the control stopped due to reaching the end of
* its configured time range (true) or due to the stop function call
* (false). This event will only fire on the stop function call during
* a loop-mode animation.
* - *rangemodified* Triggered when the control adds or removes layers which
* affect the range or interval of the control or when the range is set
* programattically.
* - *reset* Triggered when the control resets a time-series animation.
* Listeners receive an event object with a {Boolean} *looped*
* property indicating the control reset due to running in looped mode
* (true) or the reset function call (false)
*/
EVENT_TYPES: ["beforetick","tick","play","stop","reset","rangemodified"],
/**
* APIProperty: layers
* {Array()}
*/
layers: null,
/**
* APIProperty: units
* {OpenLayers.TimeUnit}
*/
units:null,
/**
* APIProperty: step
* {Number} The number of time units each tick will advance the current
* animation time. Negative units with tick time in reverse.
* Default : 1.
*/
step:1,
/**
* APIProperty: range
* {Array(Date|String)} 2 member array containing the minimum and maximum times
* in UTC that the time-series animation will use. (Optional if using
* the intervals property). The 1st value should ALWAYS be less than
* the second value. Use negative step values to do reverse time.
* Note: You can use an ISO 8601 formated string (see
* http://tools.ietf.org/html/rfc3339) or Date objects.
*/
range:null,
/**
* APIProperty: intervals
* {Array(Date|String)} Array of valid distinct UTC dates/times that the time-
* series animation can use. (Optional)
* Note: You can use an ISO 8601 formated string (see
* http://tools.ietf.org/html/rfc3339) or Date objects.
*/
intervals:null,
/**
* APIProperty: timespans
* {Array(Object|String)} Array of valid start,end,resolution objects
* series animation can use. (Optional)
* Note: You can use an ISO 8601 formated string (see
* http://tools.ietf.org/html/rfc3339) or Date objects.
*/
timespans:null,
/**
* APIProperty: frameRate
* {Number} A positive floating point number of frames (or ticks) per
* second to use in time-series animations. Values less than 1 will
* make each tick last for more than 1 second. Example: 0.5 = 1 tick
* every 2 seconds. 3 = 3 ticks per second.
* Default : 1.
*/
frameRate:1,
/**
* APIProperty: loop
* {Boolean} true to continue running the animation until stop is called
* Default:false
*/
loop:false,
/**
* APIProperty: snapToIntervals
* {Boolean} If intervals are configured and this property is true then
* tick will advance to the next time/date in the intervals array
* regardless of the step value.
*/
snapToIntervals:false,
/**
* APIProperty: maxFrameDelay
* {Number} The number of frame counts to delay the firing of the tick event
* while the control waits for its time agents to be ready to advance.
* Default: 1
*/
maxFrameDelay: 1,
/**
* APIProperty: currentTime
* {Date} The current time of the time-series animation
*/
currentTime:null,
/**
* Property: timeAgents
* {Array()} An array of the agents that
* this control "manages". Read-Only
*/
timeAgents:null,
/**
* Property: lastTimeIndex
* {Number} The array index of the last time used in the control when
* snapToIntevals is true.
*/
lastTimeIndex:-1,
/**
* Constructor: OpenLayers.Control.TimeManager
* Create a new time manager control.
*
* Parameters:
* options - {Object} Optional object whose properties will be set on the
* control.
*/
initialize: function(options) {
options = options || {};
OpenLayers.Control.prototype.initialize.call(this, options);
if(this.intervals) {
for(var i = 0, len = this.intervals.length; i < len; i++) {
var interval = this.intervals[i];
if(!(interval[i] instanceof Date)) {
this.intervals[i] = OpenLayers.Date.parse(interval);
}
}
this.intervals.sort(function(a, b) {
return a - b;
});
this.range = [this.intervals[0], this.intervals[this.intervals.length - 1]];
this.fixedIntervals = true;
}
else if(this.range) {
if(!(this.range[0] instanceof Date)) {
this.range[0] = OpenLayers.Date.parse(this.range[0]);
}
if(!(this.range[1] instanceof Date)) {
this.range[1] = OpenLayers.Date.parse(this.range[1]);
}
this.fixedRange = true;
}
if(this.range && this.range.length) {
this.currentTime = this.currentTime || new Date(this.range[0].getTime());
}
if(options.layers && !this.timeAgents) {
this.timeAgents = this.buildTimeAgents(options.layers);
if(this.timeAgents.length) {
this.fixedLayers = true;
}
}
else if(this.timeAgents){
for(var i=0,len=this.timeAgents.length;i-1;i--){
this.timeAgents[i].destroy();
}
this.layers=null;
OpenLayers.Control.prototype.destroy.call(this);
},
/**
* APIMethod: setMap
* Sets the map parameter of the control. Also called automattically when
* the control is added to the map.
* Parameter:
* map {}
*/
setMap:function(map) {
OpenLayers.Control.prototype.setMap.call(this, map);
//if the control was not directly intialized with specific layers, then
//get layers from map and build appropiate time agents
var layers = this.layers || map.layers;
if(layers){
this.layers = [];
}
for(var i = 0, len = layers.length; i < len; i++) {
var lyr = layers[i];
if(lyr.dimensions && lyr.dimensions.time) {!lyr.metadata && (lyr.metadata = {});
lyr.metadata.timeInterval = this.timeExtentsToIntervals(lyr.dimensions.time.values);
}
if((lyr.dimensions && lyr.dimensions.time) || (lyr.metadata.timeInterval && lyr.metadata.timeInterval.length)) {
this.layers.push(lyr);
}
}
if(!this.timeAgents) {
this.timeAgents = this.buildTimeAgents(this.layers);
}
this.timeSpans = this.getValidTimeSpans();
//if no interval was specified & interval !== false, get from timeAgents
if(!this.intervals && this.intervals !== false) {
this.intervals = this.buildIntervals(this.timeAgents);
}
//if no range was specified then get from timeAgents
if(!this.range) {
this.range = this.buildRange(this.timeAgents);
}
if(this.range || this.intervals) {
//handle when the current time is at the range endpoint and not the same as the interval endpoints
if(this.range && this.intervals){
var rIndex = (this.step>0) ? 0 : 1;
var inIndex = (this.step>0) ? 0 : this.intervals.length-1;
if(this.range[rIndex] > this.intervals[inIndex] || this.range[rIndex] < this.intervals[inIndex]){
if(this.currentTime.getTime() == this.range[rIndex].getTime()){
this.setTime(this.currentTime);
}
}
}
this.events.triggerEvent('rangemodified');
}
if(this.range && !this.currentTime) {
this.setTime(new Date(this.range[(this.step > 0) ? 0 : 1].getTime()));
} else if(this.currentTime){
//force a tick call and maybe a tick event
this.setTime(this.currentTime);
}
//set map agents for layer additions and removal
this.map.events.on({
'addlayer' : this.onAddLayer,
'removelayer' : this.onRemoveLayer,
scope : this
});
},
onAddLayer: function(evt) {
var lyr = evt.layer;
if(lyr.dimensions && lyr.dimensions.time) {
lyr.metadata.timeInterval = this.timeExtentsToIntervals(lyr.dimensions.time.values);
}
//don't do anything if layer is non-temporal
if(!lyr.metadata.timeInterval) {
return;
}
else {
var added = false;
if(lyr.metadata.timeInterval && !this.fixedLayers) {
this.timeAgents || (this.timeAgents = []);
var agentClass = lyr.CLASS_NAME.match(/\.Layer\.(\w+)/)[1];
if( agentClass in OpenLayers.TimeAgent) {
for(var i = 0, len = this.timeAgents.length; i < len; i++) {
if(!lyr.timeAgent && this.timeAgents[i] instanceof OpenLayers.TimeAgent[agentClass]) {
this.timeAgents[i].addLayer(lyr);
added = true;
break;
}
}
}
if(!added) {
var agents = this.buildTimeAgents([lyr]);
if(agents) {
this.timeAgents.push(agents[0]);
added = true;
}
}
//check if layer could be used in a time agent & if so modify the
//control range & interval as needed. time agent will convert timeInterval
//values to real dates
if(added) {
var lyrIntervals = lyr.metadata.timeInterval;
if(lyrIntervals.length && lyrIntervals[0] instanceof Date && !this.fixedIntervals) {
this.intervals || (this.intervals = []);
var oldIntervalsLen = this.intervals.length, oldRange = [this.range[0] || new Date(1), this.range[1] || new Date(1)];
this.intervals = this.getUniqueDates(this.intervals.concat(lyrIntervals));
this.timeSpans = this.getValidTimeSpans();
//adjust range as needed
if(!this.range) {
this.setRange([this.intervals[0], this.intervals[this.intervals.length - 1]]);
}
else if(this.intervals[0] < this.range[0] || this.intervals[1] > this.range[1]) {
this.setRange([Math.min(this.intervals[0], this.range[0]), Math.max(this.intervals[1], this.range[1])]);
}
if(oldIntervalsLen != this.intervals.length || oldRange[0].getTime() != range[0].getTime() || oldRange[1].getTime() != range[1].getTime()) {
this.events.triggerEvent('rangemodified');
}
}
else if(!this.fixedRange) {
if(!this.range) {
this.setRange([lyrIntervals.start, lyrIntervals.end]);
}
else if(lyrIntervals.start < this.range[0] || lyrIntervals.end > this.range[1]) {
this.setRange([Math.min(lyrIntervals.start, this.range[0]), Math.max(lyrIntervals.end, this.range[1])]);
}
}
//handle when the current time is at the range endpoint and not the same as the interval endpoints
if(this.range && this.intervals){
var rIndex = (this.step>0) ? 0 : 1;
var inIndex = (this.step>0) ? 0 : this.intervals.length-1;
if(this.range[rIndex] > this.intervals[inIndex] || this.range[rIndex] < this.intervals[inIndex]){
if(this.currentTime.getTime() == this.range[rIndex].getTime()){
this.setTime(this.currentTime);
}
}
}
}
}
}
},
onRemoveLayer:function(evt) {
var lyr = evt.layer;
if(lyr.metadata.timeInterval) {
var lyrIntervals = lyr.metadata.timeInterval;
var lyrIndex = OpenLayers.Util.indexOf(this.layers, lyr);
this.layers.splice(lyrIndex, 1);
this.removeAgentLayer(lyr);
if(lyrIntervals.length && lyrIntervals[0] instanceof Date && !this.fixedIntervals) {
this.intervals = this.buildIntervals(this.timeAgents);
if(this.intervals) {
if(this.intervals[0] < this.range[0] || this.intervals[1] > this.range[1]) {
this.setRange([Math.max(this.intervals[0], this.range[0]), Math.min(this.intervals[1], this.range[1])]);
}
}
}
else if(!this.fixedRange) {
if(this.timeSpans) {
if(lyrIntervals.start < this.range[0] || lyrIntervals.end > this.range[1]) {
this.setRange([Math.max(lyrIntervals.start, this.range[0]), Math.min(lyrIntervals.end, this.range[1])]);
}
}
}
if(!this.fixedRange && !this.fixedIntervals && !this.intervals && !this.timeSpans) {
//we have NO time layers
this.setRange([null, null]);
}
}
},
/**
* Method: tick
* Advance/reverse time one step forward/backward. Fires the 'tick' event
* if time can be incremented without exceeding the time range.
*
*/
tick:function() {
if(this.intervals && this.snapToIntervals) {
var newIndex = this.lastTimeIndex + ((this.step > 0) ? 1 : -1);
if(newIndex < this.intervals.length && newIndex > -1) {
this.currentTime = this.intervals[newIndex];
this.lastTimeIndex = newIndex;
}
else {
//force the currentTime beyond the range
this.currentTime = (this.step > 0) ? new Date(this.range[1].getTime() + 100) : new Date(this.range[0].getTime() - 100);
}
}
else {
this.incrementTime();
}
//test that we have reached the end of our range
if(this.currentTime > this.range[1] || this.currentTime < this.range[0]) {
//loop in looping mode
if(this.loop) {
this.clearTimer();
this.reset(true);
this.play();
}
//stop in normal mode
else {
this.clearTimer();
this.events.triggerEvent('stop', {
'rangeExceeded' : true
});
}
}
else {
if(this.canTickCheck()) {
this.events.triggerEvent('tick', {
currentTime : this.currentTime
});
}
else {
var intervalId, checkCount = 0, maxDelays = this.maxFrameDelay * 4;
this.clearTimer();
intervalId = setInterval(OpenLayers.Function.bind(function() {
var doTick = this.canTickCheck() || checkCount++ >= maxDelays;
if(checkCount > maxDelays) {
//console.debug('ADVANCED DUE TO TIME LIMIT');
}
if(doTick) {
clearInterval(intervalId);
this.events.triggerEvent('tick', {
currentTime : this.currentTime
});
if(!this._stopped){
this.clearTimer();
this.timer = setInterval(OpenLayers.Function.bind(this.tick, this), 1000 / this.frameRate);
}
}
}, this), 1000 / (this.frameRate * 4));
}
}
},
/**
* APIMethod: play
* Begins/resumes the time-series animation. Fires the 'play' event,
* then calls 'tick' at the interval set by the frameRate property
*/
play:function() {
//ensure that we don't have multiple timers running
this.clearTimer();
//start playing
if(this.events.triggerEvent('play') !== false) {
delete this._stopped;
this.tick();
this.clearTimer(); //no seriously we really really only want 1 timer
this.timer = setInterval(OpenLayers.Function.bind(this.tick, this), 1000 / this.frameRate);
}
},
/**
* APIMethod: stop
* Stops the time-series animation. Fires the 'stop' event.
*/
stop:function(){
this.clearTimer();
this.events.triggerEvent('stop',{'rangeExceeded':false});
this._stopped=true;
},
/**
* APIMethod: setRange
* Sets the time range used by this control. Will modify the start time or
* current time only if the animation is not currently running
*
* Parameters:
* range - {Arrray(Date|String)} UTC time range using either Date objects
* or ISO 8601 formatted strings
*/
setRange:function(range) {
var oldRange = [this.range[0].getTime(), this.range[1].getTime()];
for(var i = 0; i < 2; i++) {
if(!range[i]) {
//go ahead and make this a dummy date since so many functions expect this to be a date
range[i]=new Date(-8e15);
}
if(!(range[i] instanceof Date)) {
range[i] = OpenLayers.Date.parse(range[i]);
}
}
this.range = range;
//set current time to correct location if the timer isn't running yet.
if(!this.timer) {
var newTime = new Date(this.range[(this.step > 0) ? 0 : 1].getTime());
this.setTime(newTime);
}
if(this.range[0].getTime() != oldRange[0] || this.range[1].getTime() != oldRange[1]) {
this.events.triggerEvent("rangemodified");
}
},
/**
* APIMethod:setStart
* Sets the start time for an animation. If the step is negative then this
* sets the maximum time in the control's range parameter. Will only effect
* the currentTime if an animation has not begun.
*
* Parameters:
* time - {Date|String} UTC start time/date using either a Date object or
* ISO 8601 formatted string.
*/
setStart:function(time){
if(this.step>0){
this.setRange([time,this.range[1]]);
} else {
this.setRange([this.range[0],time]);
}
},
/**
* APIMethod:setEnd
* Sets the end time for an animation. If the step is negative then this
* sets the minimum time in the control's range parameter. Will not effect
* the current time.
*
* Parameters:
* time - {Date|String} UTC stop time/date using either a Date object or
* ISO 8601 formatted string.
*/
setEnd:function(time){
if(this.step>0){
this.setRange([this.range[0],time]);
} else {
this.setRange([time,this.range[1]]);
}
},
/**
* APIMethod:setTime
* Manually sets the currentTime used in the control's animation.
*
* Parameters: {Object} time
* time - {Date|String} UTC current animantion time/date using either a
* Date object or ISO 8601 formatted string.
*/
setTime:function(time) {
if(!( time instanceof Date)) {
time = OpenLayers.Date.parse(time);
}
if(this.snapToIntervals) {
var nearest = OpenLayers.TimeAgent.WMS.prototype.findNearestTimes.apply(this, [time, this.intervals]);
var index = this.lastTimeIndex;
if(nearest.exact > -1){
index = nearest.exact;
} else if(nearest.before > -1 && nearest.after > -1) {
//requested time is somewhere between 2 valid times
//find the actual closest one.
var bdiff = this.intervals[nearest.before] - this.currentTime;
var adiff = this.currentTime - this.intervals[nearest.after];
index = (adiff > bdiff) ? nearest.before : nearest.after;
} else if (nearest.before > -1){
index = nearest.before;
} else if (nearest.after >-1){
index = nearest.after;
}
this.currentTime = this.intervals[index];
this.lastTimeIndex = index;
}
else {
this.currentTime = time;
}
this.events.triggerEvent('tick', {
'currentTime' : this.currentTime
});
},
/**
* APIMethod:setFrameRate
* Sets the control's playback frameRate (ticks/second)
* Parameters: {Number} rate - the ticks/second rate
*/
setFrameRate: function(rate){
var playing = !!this.timer;
this.clearTimer();
this.frameRate = rate;
if(playing){
//this.tick();
this.timer = setInterval(OpenLayers.Function.bind(this.tick, this), 1000 / this.frameRate);
}
},
/**
* APIMethod:reset
* Resets the time to the animation start time. Fires the 'reset' event.
*
* Parameters: {Boolean} looped - trigger reset event with looped = true
* Returns:
* {Date} the control's currentTime, which is also the control's start time
*/
reset:function(looped) {
this.clearTimer();
var newTime = new Date(this.range[(this.step > 0) ? 0 : 1].getTime());
this.setTime(newTime);
this.events.triggerEvent('reset', {
'looped' : !!looped
});
return this.currentTime;
},
/**
* APIMethod: incrementTime
* Moves the current animation time forward by the specified step & stepUnit
*
* Parameters:
* step - {Number}
* stepUnit - {}
*/
incrementTime:function(step,stepUnit) {
var step = step || this.step;
var stepUnit = stepUnit || this.units;
var newTime = parseFloat(this.currentTime['getUTC'+stepUnit]()) + parseFloat(step);
this.currentTime['setUTC'+stepUnit](newTime);
},
/**
* Method: buildTimeAgents
* Creates the controls "managed" by this control.
*
* Parameters:
* layers - {Array()}
*
* Returns:
* {Array()}
*/
buildTimeAgents:function(layers) {
layers = layers || this.layers || [];
var layerTypes = {}, agents = [];
//categorize layers and separate into arrays for use in subclasses
for(var i = 0, len = layers.length; i < len; i++) {
var lyr = layers[i];
if(lyr.dimensions && lyr.dimensions.time) {
lyr.metadata.timeInterval = this.timeExtentsToIntervals(lyr.dimensions.time.values);
}
//allow user specified overrides and custom behavior
if(lyr.timeAgent) {
var agent;
if(lyr.timeAgent instanceof Function) {
agent = new OpenLayers.TimeAgent({
onTick : lyr.timeAgent,
layers : [lyr],
timeManager : this
});
}
this.events.on({
tick : agent.onTick,
scope : agent
});
agents.push(agent);
}
else {
var lyrClass = lyr.CLASS_NAME.match(/\.Layer\.(\w+)/)[1];
if(OpenLayers.TimeAgent[lyrClass]) {
if(!layerTypes[lyrClass]) {
layerTypes[lyrClass] = [];
}
layerTypes[lyrClass].push(lyr);
}
}
}
//create subclassed time agents
for(var k in layerTypes) {
var agentOpts = {
layers : layerTypes[k],
timeManager : this
};
if(this.agentOptions && this.agentOptions[k]) {
OpenLayers.Util.applyDefaults(agentOpts, this.agentOptions[k]);
}
var agent = new OpenLayers.TimeAgent[k](agentOpts);
this.events.on({
'tick' : agent.onTick,
scope : agent
});
agents.push(agent);
}
return (agents.length) ? agents : null;
},
removeAgentLayer: function(lyr) {
//find the agent with the layer
for(var i = 0, len = this.timeAgents.length; i < len; i++) {
var agent = this.timeAgents[i];
if(OpenLayers.Util.indexOf(agent.layers, lyr) > -1) {
agent.removeLayer(lyr);
//if the agent doesn't handle any layers, get rid of it
if(!agent.layers.length) {
this.timeAgents.splice(i, 1);
agent.destroy();
}
this.timeSpans = this.getValidTimeSpans();
break;
}
}
},
/**
* Method: buildIntervals
* Builds an array of distinct date/times that the time agents are
* configured with
* Parameters:
* agents - {Array()}
* (Optional) An array of time agents to calculate the intervals from.
* Defaults to the control's timeAgents property.
* Returns: {Array(Date)}
*/
buildIntervals:function(agents){
agents = agents || this.timeAgents || [];
var intervals = [];
for(var i=0,len=agents.length;i)}
* (Optional) An array of time agents to calculate the intervals from.
* Defaults to the control's timeAgents property.
* Returns: {Array(Date)}
*/
buildRange:function(agents){
agents = agents || this.timeAgents || [];
var range = [];
for(var i=0,len=agents.length;irange[1]){range[1]=new Date(subrange[1].getTime());}
}
return (range.length)?range:null;
},
guessPlaybackRate:function(){
if(!this.timeAgents){return false;}
var timeSpans=this.getValidTimeSpans();
if (timeSpans) {
timeSpans.sort(function(a, b){
//sort by most restrictive range
var arange = a.end - a.start, brange = b.end - b.start;
if (arange != brange) {
return (arange < brange) ? 1 : -1;
}
else if (a.resolution.units != b.resolution.units) {
//same range find biggest step unit
switch (a.resolution.units) {
case OpenLayers.TimeUnit.YEARS:
return 1;
case OpenLayers.TimeUnit.SECONDS:
return -1;
case OpenLayers.TimeUnit.MONTHS:
return (b.resolution.units == OpenLayers.TimeUnit.YEARS) ? -1 : 1;
case OpenLayers.TimeUnit.MINUTES:
return (b.resolution.units == OpenLayers.TimeUnit.SECONDS) ? 1 : -1;
case OpenLayers.TimeUnit.HOURS:
if (b.resolution.units == OpenLayers.TimeUnit.MINUTES || b.resolution.units == OpenLayers.TimeUnit.SECONDS) {
return 1;
}
else {
return -1;
}
case OpenLayers.TimeUnit.DAYS:
if (b.resolution.units == OpenLayers.TimeUnit.MONTHS || b.resolution.units == OpenLayers.TimeUnit.YEARS) {
return -1;
}
else {
return 1;
}
}
}
else {
//same range and units, pick largest step
return a.resolution.step - b.resolution.step;
}
});
this.setRange([timeSpans[0].start, timeSpans[0].end]);
this.units = timeSpans[0].resolution.units;
this.step = timeSpans[0].resolution.step;
}
else if (this.intervals) {
this.snapToIntervals = true;
}
else {
//guess based on range, keep step at 1
var diff = this.range[1] - this.range[0];
if (diff < 6e3) {
this.units = OpenLayers.TimeUnit.SECONDS;
}
else if (diff < 36e5) {
this.units = OpenLayers.TimeUnit.MINUTES;
}
else if (diff < 864e5) {
this.units = OpenLayers.TimeUnit.HOURS;
}
else if (diff < 2628e6) {
this.units = OpenLayers.TimeUnit.DAYS;
}
else if (diff < 31536e6) {
this.units = OpenLayers.TimeUnit.MONTHS;
}
else {
this.units = OpenLayers.TimeUnit.YEARS;
}
}
},
getValidTimeSpans:function(agents) {
agents = agents || this.timeAgents || [];
var validTimes = [];
for(var i = 0, len = agents.length; i < len; i++) {
if(agents[i].timeSpans) {
validTimes = validTimes.concat(agents[i].timeSpans);
}
}
return (validTimes.length) ? validTimes : null;
},
timeExtentsToIntervals: function(timeExtents) {
var intervals = [];
for(var i = 0; i < timeExtents.length; ++i) {
var timeParts = timeExtents[i].split("/");
if(timeParts.length > 1) {
var min = timeParts[0], max = timeParts[1], res = timeParts[2];
intervals.push([min, max, res]);
}
else {
intervals.push(timeParts[0]);
}
}
return (intervals.length) ? intervals : null;
},
getUniqueDates:function(dates) {
//sort the times
dates.sort(function(a, b) {
return a - b;
});
//filter for unique
dates = OpenLayers.Array.filter(dates, function(item, index, array) {
for(var i = index + 1; i < array.length; i++) {
if(item.getTime() == array[i].getTime()) {
return false;
}
}
return true;
});
return dates;
},
canTickCheck: function() {
var canTick = false;
for(var i = 0, len = this.timeAgents.length; i < len; i++) {
canTick = this.timeAgents[i].canTick;
if(!canTick) {
break;
}
}
return canTick;
},
clearTimer: function() {
if(this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
CLASS_NAME:'OpenLayers.Control.TimeManager'
});
OpenLayers.TimeUnit = {
SECONDS:'Seconds',
MINUTES:'Minutes',
HOURS:'Hours',
DAYS:'Date',
MONTHS:'Month',
YEARS:'FullYear'
};
//Adjust the OpenLayers date parse regex to handle BCE dates & years longer than 4 digits
OpenLayers.Date.dateRegEx =
/^(?:(-?\d+)(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/;
© 2015 - 2025 Weber Informatics LLC | Privacy Policy