comparison geotemco/lib/simile/timeplot/scripts/sources.js @ 0:b12c99b7c3f0

commit for previous development
author Zoe Hong <zhong@mpiwg-berlin.mpg.de>
date Mon, 19 Jan 2015 17:13:49 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:b12c99b7c3f0
1 /**
2 * Sources
3 *
4 * @fileOverview Sources
5 * @name Sources
6 */
7
8 /**
9 * Timeplot.DefaultEventSource is an extension of Timeline.DefaultEventSource
10 * and therefore reuses the exact same event loading subsystem that
11 * Timeline uses.
12 *
13 * @constructor
14 */
15 Timeplot.DefaultEventSource = function(eventIndex) {
16 Timeline.DefaultEventSource.apply(this, arguments);
17 };
18
19 Object.extend(Timeplot.DefaultEventSource.prototype, Timeline.DefaultEventSource.prototype);
20
21 /**
22 * Function used by Timeplot to load time series data from a text file.
23 */
24 Timeplot.DefaultEventSource.prototype.loadText = function(text, separator, url, filter, format) {
25
26 if (text == null) {
27 return;
28 }
29
30 this._events.maxValues = new Array();
31 var base = this._getBaseURL(url);
32
33 if (!format) format = 'iso8601';
34 var parseDateTimeFunction = this._events.getUnit().getParser(format);
35
36 var data = this._parseText(text, separator);
37
38 var added = false;
39
40 if (filter) {
41 data = filter(data);
42 }
43
44 if (data) {
45 for (var i = 0; i < data.length; i++){
46 var row = data[i];
47 if (row.length > 1) {
48 var dateStr = SimileAjax.jQuery.trim(row[0]);
49 var date = parseDateTimeFunction(dateStr);
50 if (date) {
51 var evt = new Timeplot.DefaultEventSource.NumericEvent(date,row.slice(1));
52 this._events.add(evt);
53 added = true;
54 }
55 }
56 }
57 }
58
59 if (added) {
60 this._fire("onAddMany", []);
61 }
62 }
63
64 /*
65 * Parse the data file.
66 *
67 * Adapted from http://www.kawa.net/works/js/jkl/js/jkl-parsexml.js by Yusuke Kawasaki
68 */
69 Timeplot.DefaultEventSource.prototype._parseText = function (text, separator) {
70 text = text.replace( /\r\n?/g, "\n" ); // normalize newlines
71 var pos = 0;
72 var len = text.length;
73 var table = [];
74 while (pos < len) {
75 var line = [];
76 if (text.charAt(pos) != '#') { // if it's not a comment, process
77 while (pos < len) {
78 if (text.charAt(pos) == '"') { // "..." quoted column
79 var nextquote = text.indexOf('"', pos+1 );
80 while (nextquote<len && nextquote > -1) {
81 if (text.charAt(nextquote+1) != '"') {
82 break; // end of column
83 }
84 nextquote = text.indexOf('"', nextquote + 2);
85 }
86 if ( nextquote < 0 ) {
87 // unclosed quote
88 } else if (text.charAt(nextquote + 1) == separator) { // end of column
89 var quoted = text.substr(pos + 1, nextquote-pos - 1);
90 quoted = quoted.replace(/""/g,'"');
91 line[line.length] = quoted;
92 pos = nextquote + 2;
93 continue;
94 } else if (text.charAt(nextquote + 1) == "\n" || // end of line
95 len == nextquote + 1 ) { // end of file
96 var quoted = text.substr(pos + 1, nextquote-pos - 1);
97 quoted = quoted.replace(/""/g,'"');
98 line[line.length] = quoted;
99 pos = nextquote + 2;
100 break;
101 } else {
102 // invalid column
103 }
104 }
105 var nextseparator = text.indexOf(separator, pos);
106 var nextnline = text.indexOf("\n", pos);
107 if (nextnline < 0) nextnline = len;
108 if (nextseparator > -1 && nextseparator < nextnline) {
109 line[line.length] = text.substr(pos, nextseparator-pos);
110 pos = nextseparator + 1;
111 } else { // end of line
112 line[line.length] = text.substr(pos, nextnline-pos);
113 pos = nextnline + 1;
114 break;
115 }
116 }
117 } else { // if it's a comment, ignore
118 var nextnline = text.indexOf("\n", pos);
119 pos = (nextnline > -1) ? nextnline + 1 : cur;
120 }
121 if (line.length > 0) {
122 table[table.length] = line; // push line
123 }
124 }
125 if (table.length < 0) return; // null data
126 return table;
127 }
128
129 /**
130 * Return the range of the loaded data
131 */
132 Timeplot.DefaultEventSource.prototype.getRange = function() {
133 var earliestDate = this.getEarliestDate();
134 var latestDate = this.getLatestDate();
135 return {
136 earliestDate: (earliestDate) ? earliestDate : null,
137 latestDate: (latestDate) ? latestDate : null,
138 min: 0,
139 max: 0
140 };
141 }
142
143 // -----------------------------------------------------------------------
144
145 /**
146 * A NumericEvent is an Event that also contains an array of values,
147 * one for each columns in the loaded data file.
148 *
149 * @constructor
150 */
151 Timeplot.DefaultEventSource.NumericEvent = function(time, values) {
152 this._id = "e" + Math.round(Math.random() * 1000000);
153 this._time = time;
154 this._values = values;
155 };
156
157 Timeplot.DefaultEventSource.NumericEvent.prototype = {
158 getID: function() { return this._id; },
159 getTime: function() { return this._time; },
160 getValues: function() { return this._values; },
161
162 // these are required by the EventSource
163 getStart: function() { return this._time; },
164 getEnd: function() { return this._time; }
165 };
166
167 // -----------------------------------------------------------------------
168
169 /**
170 * A DataSource represent an abstract class that represents a monodimensional time series.
171 *
172 * @constructor
173 */
174 Timeplot.DataSource = function(eventSource) {
175 this._eventSource = eventSource;
176 var source = this;
177 this._processingListener = {
178 onAddMany: function() { source._process(); },
179 onClear: function() { source._clear(); }
180 }
181 this.addListener(this._processingListener);
182 this._listeners = [];
183 this._data = null;
184 this._range = null;
185 };
186
187 Timeplot.DataSource.prototype = {
188
189 _clear: function() {
190 this._data = null;
191 this._range = null;
192 },
193
194 _process: function() {
195 this._data = {
196 times: new Array(),
197 values: new Array()
198 };
199 this._range = {
200 earliestDate: null,
201 latestDate: null,
202 min: 0,
203 max: 0
204 };
205 },
206
207 /**
208 * Return the range of this data source
209 */
210 getRange: function() {
211 return this._range;
212 },
213
214 /**
215 * Return the actual data that this data source represents.
216 * NOTE: _data = { times: [], values: [] }
217 */
218 getData: function() {
219 return this._data;
220 },
221
222 /**
223 * Return the value associated with the given time in this time series
224 */
225 getValue: function(t) {
226 if (this._data) {
227 for (var i = 0; i < this._data.times.length; i++) {
228 var l = this._data.times[i];
229 if (l >= t) {
230 return this._data.values[i];
231 }
232 }
233 }
234 return 0;
235 },
236
237 /**
238 * Return the time of the data point closest to the given time.
239 */
240 getClosestValidTime: function(t) {
241 if (this._data) {
242 for (var i = 0; i < this._data.times.length; i++) {
243 var currentTime = this._data.times[i];
244 if (currentTime >= t) {
245 if (i <= 0) {
246 return currentTime;
247 } else {
248 var lastTime = this._data.times[i - 1];
249 // t must be between currentTime and lastTime.
250 // Find the closest one.
251 if (t - lastTime < currentTime - t) {
252 return lastTime;
253 } else {
254 return currentTime;
255 }
256 }
257 }
258 }
259 }
260 return 0;
261 },
262
263 /**
264 * Add a listener to the underlying event source
265 */
266 addListener: function(listener) {
267 this._eventSource.addListener(listener);
268 },
269
270 /**
271 * Remove a listener from the underlying event source
272 */
273 removeListener: function(listener) {
274 this._eventSource.removeListener(listener);
275 },
276
277 /**
278 * Replace a listener from the underlying event source
279 */
280 replaceListener: function(oldListener, newListener) {
281 this.removeListener(oldListener);
282 this.addListener(newListener);
283 }
284
285 }
286
287 // -----------------------------------------------------------------------
288
289 /**
290 * Implementation of a DataSource that extracts the time series out of a
291 * single column from the events
292 *
293 * @constructor
294 */
295 Timeplot.ColumnSource = function(eventSource, column) {
296 Timeplot.DataSource.apply(this, arguments);
297 this._column = column - 1;
298 };
299
300 Object.extend(Timeplot.ColumnSource.prototype,Timeplot.DataSource.prototype);
301
302 Timeplot.ColumnSource.prototype.dispose = function() {
303 this.removeListener(this._processingListener);
304 this._clear();
305 }
306
307 Timeplot.ColumnSource.prototype._process = function() {
308 var count = this._eventSource.getCount();
309 var times = new Array(count);
310 var values = new Array(count);
311 var min = Number.MAX_VALUE;
312 var max = Number.MIN_VALUE;
313 var i = 0;
314
315 var iterator = this._eventSource.getAllEventIterator();
316 while (iterator.hasNext()) {
317 var event = iterator.next();
318 var time = event.getTime();
319 times[i] = time;
320 var value = this._getValue(event);
321 if (!isNaN(value)) {
322 if (value < min) {
323 min = value;
324 }
325 if (value > max) {
326 max = value;
327 }
328 values[i] = value;
329 }
330 i++;
331 }
332
333 this._data = {
334 times: times,
335 values: values
336 };
337
338 if (max == Number.MIN_VALUE) max = 1;
339
340 this._range = {
341 earliestDate: this._eventSource.getEarliestDate(),
342 latestDate: this._eventSource.getLatestDate(),
343 min: min,
344 max: max
345 };
346 }
347
348 Timeplot.ColumnSource.prototype._getValue = function(event) {
349 return parseFloat(event.getValues()[this._column]);
350 }
351
352 // ---------------------------------------------------------------
353
354 /**
355 * Data Source that generates the time series out of the difference
356 * between the first and the second column
357 *
358 * @constructor
359 */
360 Timeplot.ColumnDiffSource = function(eventSource, column1, column2) {
361 Timeplot.ColumnSource.apply(this, arguments);
362 this._column2 = column2 - 1;
363 };
364
365 Object.extend(Timeplot.ColumnDiffSource.prototype,Timeplot.ColumnSource.prototype);
366
367 Timeplot.ColumnDiffSource.prototype._getValue = function(event) {
368 var a = parseFloat(event.getValues()[this._column]);
369 var b = parseFloat(event.getValues()[this._column2]);
370 return a - b;
371 }