adaguc-webmapjs
Version:
Interactive maps library, capable of parsing a OGC WMS getcapabilities and display geographical layers
410 lines (379 loc) • 14.7 kB
JavaScript
import { WMJSDateOutSideRange, WMJSDateTooEarlyString, WMJSDateTooLateString, error } from './WMJSConstants.js';
import { isDefined } from './WMJSTools.js';
import { parseISO8601DateToDate, parseISO8601IntervalToDateInterval, ParseISOTimeRangeDuration } from './WMJSTime.js';
/**
* WMJSDimension Class
* Keep all information for a single dimension, like time.
* Author : MaartenPlieger (plieger at knmi.nl)
* Copyright KNMI
*/
export default class WMJSDimension {
constructor (config) {
this.name = undefined; // Name of the dimension, e.g. 'time'
this.units = undefined; // Units of the dimension, e.g. 'ISO8601'
this.values = undefined; // Values of the dimension, according to values defined in WMS specification, e.g. 2011-01-01T00:00:00Z/2012-01-01T00:00:00Z/P1M or list of values.
this.currentValue = undefined; // The current value of the dimension, changed by setValue and read by getValue
this.defaultValue = undefined;
this.parentLayer = undefined;
this.timeRangeDuration = undefined;
this.linked = true;
/* Private starts with _ */
this._initialized = false;
this._timeRangeDurationDate = null; // Used for timerange (start/stop/res)
this._allDates = []; // Used for individual timevalues
this._type = null; // Can be 'timestartstopres', 'timevalues' or 'anyvalue'
this._allValues = [];
/* Deprecated starts with __ */
this.__setStartTime = this.__setStartTime.bind(this);
this.generateAllValues = this.generateAllValues.bind(this);
this.reInitializeValues = this.reInitializeValues.bind(this);
this.initialize = this.initialize.bind(this);
this.getValue = this.getValue.bind(this);
this.setValue = this.setValue.bind(this);
this.setClosestValue = this.setClosestValue.bind(this);
this.getNextClosestValue = this.getNextClosestValue.bind(this);
this.addTimeRangeDurationToValue = this.addTimeRangeDurationToValue.bind(this);
this.setTimeRangeDuration = this.setTimeRangeDuration.bind(this);
this.getClosestValue = this.getClosestValue.bind(this);
this.getValueForIndex = this.getValueForIndex.bind(this);
this.get = this.get.bind(this);
this.getIndexForValue = this.getIndexForValue.bind(this);
this.size = this.size.bind(this);
this.clone = this.clone.bind(this);
if (isDefined(config)) {
if (isDefined(config.name)) { this.name = config.name; }
if (isDefined(config.units)) { this.units = config.units; }
if (isDefined(config.values)) { this.values = config.values; }
if (isDefined(config.currentValue)) { this.currentValue = config.currentValue; }
if (isDefined(config.defaultValue)) { this.defaultValue = config.defaultValue; }
if (isDefined(config.parentLayer)) { this.parentLayer = config.parentLayer; }
if (isDefined(config.linked)) { this.linked = config.linked; }
}
}
generateAllValues () {
const vals = [];
if (this.size() > 5000) {
throw new Error('Error: Dimension too large to query all possible values at once');
}
for (let i = 0; i < this.size(); i++) {
vals.push(this.getValueForIndex(i));
}
return vals;
}
/* The setStartTime function set the first value of the dimension to given value
* This is useful when a reference_time is used in combination with time.
* By default the time values prior to the reference_time will not give valid results.
* This function can be used to remove the first time values from the dimension by setting the start date
* a bit later in time
*/
__setStartTime (_val) {
if (!this._initialized) {
this.initialize();
}
let val = _val;
if (!val || val.length === 0) {
this.reInitializeValues(this.values);
this.setClosestValue(true); /* TODO: Check, was timeDim. */
console.log('returning');
return;
}
val = parseISO8601DateToDate(val).toISO8601();
if (this._type === 'timestartstopres') {
let v = this.values;
/* Adjust the first value for start/stop/res */
let newValue = val + v.substring(v.indexOf('/'));
this.reInitializeValues(newValue);
this.setClosestValue();
} else if (this._type === 'timevalues') {
/* Filter all dates from the array which are lower than given start value */
let newValue = parseISO8601DateToDate(val);
let newArray = this._allDates.filter(function (x) {
return x >= newValue;
});
let newValues = '';
for (let j = 0; j < newArray.length; j++) {
if (j > 0) newValues += ',';
newValues += newArray[j].toISO8601();
}
this.reInitializeValues(newValues);
this.setClosestValue();
}
}
reInitializeValues (values) {
this._initialized = false;
this.initialize(values);
}
initialize (forceothervalues) {
if (this._initialized === true) return;
let ogcdimvalues = this.values;
if (forceothervalues) {
ogcdimvalues = forceothervalues;
}
if (!isDefined(ogcdimvalues)) return;
this._allValues = [];
this._initialized = true;
if (this.units === 'ISO8601') {
if (ogcdimvalues.indexOf('/') > 0) {
this._type = 'timestartstopres';
this._timeRangeDurationDate = new ParseISOTimeRangeDuration(ogcdimvalues);
} else {
// TODO Parse 2007-03-27T00:00:00.000Z/2007-03-31T00:00:00.000Z/PT1H,2007-04-07T00:00:00.000Z/2007-04-11T00:00:00.000Z/PT1H
this._type = 'timevalues';
}
} else {
this._type = 'anyvalue';
this.linked = false;
}
if (this._type !== 'timestartstopres') {
let values = ogcdimvalues.split(',');
for (let j = 0; j < values.length; j++) {
let valuesRanged = values[j].split('/');
if (valuesRanged.length === 3) {
let start = parseFloat(valuesRanged[0]);
let stop = parseFloat(valuesRanged[1]);
let res = parseFloat(valuesRanged[2]);
stop += res;
if (start > stop)stop = start;
if (res <= 0)res = 1;
for (let j = start; j < stop; j = j + res) {
this._allValues.push(j);
}
} else {
this._allValues.push(values[j]);
}
}
if (this._type === 'timevalues') {
for (let j = 0; j < this._allValues.length; j++) {
this._allDates[j] = parseISO8601DateToDate(this._allValues[j]);
}
}
}
if (!isDefined(this.defaultValue)) {
this.defaultValue = this.getValueForIndex(0);
}
if (!isDefined(this.currentValue)) {
this.currentValue = this.getValueForIndex(0);
}
this.dimMinValue = this.getValueForIndex(0);
this.dimMaxValue = this.getValueForIndex(this.size() - 1);
}
/**
* Returns the current value of this dimensions
*/
getValue () {
if (!this._initialized) {
this.initialize();
}
let value = this.defaultValue;
if (isDefined(this.currentValue)) {
value = this.currentValue;
}
value = this.addTimeRangeDurationToValue(value);
return value;
};
/**
* Set current value of this dimension
*/
setValue (value) {
if (!this._initialized) {
this.initialize();
}
if (value === WMJSDateOutSideRange ||
value === WMJSDateTooEarlyString ||
value === WMJSDateTooLateString) {
return;
}
this.currentValue = value;
};
setClosestValue (newValue, evenWhenOutsideRange) {
if (!newValue) {
newValue = this.getValue();
evenWhenOutsideRange = true;
}
this.currentValue = this.getClosestValue(newValue, evenWhenOutsideRange);
};
getNextClosestValue (newValue) {
let closestValue = this.getClosestValue(newValue);
let index = this.getIndexForValue(closestValue);
let nextValue = this.getValueForIndex(index + 1);
// Only return future dates
if (!nextValue || nextValue === 'date too early' || moment(newValue) >= moment(nextValue)) {
return null;
}
return nextValue;
};
addTimeRangeDurationToValue (value) {
if (value === WMJSDateOutSideRange ||
value === WMJSDateTooEarlyString ||
value === WMJSDateTooLateString) {
return value;
}
if (this.timeRangeDuration && this.timeRangeDuration.length > 0) {
let interval = parseISO8601IntervalToDateInterval(this.timeRangeDuration);
let value2date = parseISO8601DateToDate(value);
value2date.add(interval);
let value2 = value2date.toISO8601();
return value + '/' + value2;
}
return value;
}
setTimeRangeDuration (duration) {
this.timeRangeDuration = duration;
if (duration && duration.length > 0) {
this.reInitializeValues(this.values);
let startDate = parseISO8601DateToDate(this.dimMinValue);
let stopDate = (this.dimMaxValue);
let interval = parseISO8601IntervalToDateInterval(this.timeRangeDuration);
if (interval.second !== 0) startDate.setUTCSeconds(0);
if (interval.minute !== 0) { startDate.setUTCSeconds(0); startDate.setUTCMinutes(0); }
if (interval.hour !== 0) { startDate.setUTCSeconds(0); startDate.setUTCMinutes(0); startDate.setUTCSHours(0); }
if (interval.day !== 0) { startDate.setUTCSeconds(0); startDate.setUTCMinutes(0); startDate.setUTCSHours(0); startDate.setUTCDate(0); }
if (interval.month !== 0) { startDate.setUTCSeconds(0); startDate.setUTCMinutes(0); startDate.setUTCSHours(0); startDate.setUTCDate(0); }
this.reInitializeValues(startDate.toISO8601() + '/' + stopDate + '/' + this.timeRangeDuration);
} else {
this.reInitializeValues(this.values);
}
};
getClosestValue (newValue, evenWhenOutsideRange) {
if (newValue && newValue.indexOf('/') !== -1) {
newValue = newValue.split('/')[0];
}
evenWhenOutsideRange = typeof evenWhenOutsideRange !== 'undefined' ? evenWhenOutsideRange : false;
let index = -1;
let _value = WMJSDateOutSideRange;
try {
index = this.getIndexForValue(newValue);
_value = this.getValueForIndex(index);
} catch (e) {
if (typeof (e) === 'number') {
if (e === 0)_value = WMJSDateTooEarlyString; else _value = WMJSDateTooLateString;
}
}
if (newValue === 'current' || newValue === 'default' || newValue === '') {
_value = this.defaultValue;
} else if (newValue === 'latest' || (evenWhenOutsideRange && _value === WMJSDateTooLateString)) {
_value = this.getValueForIndex(this.size() - 1);
} else if (newValue === 'earliest' || (evenWhenOutsideRange && _value === WMJSDateTooEarlyString)) {
_value = this.getValueForIndex(0);
} else if (newValue === 'middle') {
let middleIndex = (this.size() / 2) - 1;
if (middleIndex < 0) middleIndex = 0;
_value = this.getValueForIndex(middleIndex);
}
// alert(_value);
return _value;
};
/**
* Get dimension value for specified index
*/
getValueForIndex (index) {
this.initialize();
if (index < 0) {
if (index === -1) {
return WMJSDateTooEarlyString;
}
if (index === -2) {
return WMJSDateTooLateString;
}
return -1;
}
if (this._type === 'timestartstopres') {
try {
return this._timeRangeDurationDate.getDateAtTimeStep(index).toISO8601();
} catch (e) {}
return this._timeRangeDurationDate.getDateAtTimeStep(index);
}
if (this._type === 'timevalues') return this._allValues[index];
if (this._type === 'anyvalue') return this._allValues[index];
};
/**
* same as getValueForIndex
*/
get (index) {
return this.getValueForIndex(index);
};
/**
* Get index value for specified value. Returns the index in the store for the given time value, either a date or a iso8601 string can be passes as input.
* @param value Either a JS Date object or an ISO8601 String
* @return The index of the value. If outSideOfRangeFlag is false, a valid index will
* always be returned. If outSideOfRangeFlag is true: -1 if the index is not in the store,
* but is lower than available values, -2 if the index is not in store, but is higher than available values
*/
getIndexForValue (value, outSideOfRangeFlag) {
this.initialize();
if (!isDefined(outSideOfRangeFlag))outSideOfRangeFlag = true;
if (typeof (value) === 'string') {
if (value === 'current' && this.defaultValue !== 'current') {
return this.getIndexForValue(this.defaultValue);
}
}
if (this._type === 'timestartstopres') {
try {
if (typeof (value) === 'string') {
return this._timeRangeDurationDate.getTimeStepFromISODate(value, outSideOfRangeFlag);
}
return this._timeRangeDurationDate.getTimeStepFromDate(value, outSideOfRangeFlag);
} catch (e) {
// error("WMSJDimension::getIndexForValue,1: "+e);
if (parseInt(e) === 0) return -1; else return -2;
}
}
if (this._type === 'timevalues') {
try {
let dateToFind = parseISO8601DateToDate(value).getTime();
let minDistance;
let foundIndex = 0;
for (let j = 0; j < this._allValues.length; j++) {
let distance = (this._allDates[j].getTime() - dateToFind);
if (distance < 0)distance = -distance;
// debug(j+" = "+distance+" via "+allDates[j].getTime()+" and "+dateToFind);
if (j === 0)minDistance = distance;
if (distance < minDistance) {
minDistance = distance;
foundIndex = j;
}
}
return foundIndex;
} catch (e) {
error('WMSJDimension::getIndexForValue,2: ' + e);
return -1;
}
/* let dateToFind = parseISO8601DateToDate(value).getTime();
allValues[j]
let max = allValues.length-1;
let min = 0;
let average = parseInt((max-min)/2); */
}
if (this._type === 'anyvalue') {
for (let j = 0; j < this._allValues.length; j++) {
if (this._allValues[j] === value) return j;
}
}
return -1;
}
/**
* Get number of values
*/
size () {
this.initialize();
if (this._type === 'timestartstopres') return this._timeRangeDurationDate.getTimeSteps();
if (this._type === 'timevalues' || this._type === 'anyvalue') {
return this._allValues.length;
}
}
/**
* Clone this dimension
*/
clone () {
let dim = new WMJSDimension();
dim.name = this.name;
dim.units = this.units;
dim.values = this.values;
dim.initialize();
dim.currentValue = this.currentValue;
dim.defaultValue = this.defaultValue;
dim.parentLayer = this.parentLayer;
dim.linked = this.linked;
return dim;
}
};