PageRenderTime 105ms CodeModel.GetById 40ms app.highlight 23ms RepoModel.GetById 37ms app.codeStats 0ms

/timeplot/scripts/sources.js

http://showslow.googlecode.com/
JavaScript | 371 lines | 249 code | 44 blank | 78 comment | 47 complexity | f778183d8f5cd1d78081b8cbe8b23e1f MD5 | raw file
  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 */
 15Timeplot.DefaultEventSource = function(eventIndex) {
 16    Timeline.DefaultEventSource.apply(this, arguments);
 17};
 18
 19Object.extend(Timeplot.DefaultEventSource.prototype, Timeline.DefaultEventSource.prototype);
 20
 21/**
 22 * Function used by Timeplot to load time series data from a text file.
 23 */
 24Timeplot.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 */
 69Timeplot.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 */
132Timeplot.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 */
151Timeplot.DefaultEventSource.NumericEvent = function(time, values) {
152    this._id = "e" + Math.round(Math.random() * 1000000);
153    this._time = time;
154    this._values = values;
155};
156
157Timeplot.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 */
174Timeplot.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
187Timeplot.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 */
295Timeplot.ColumnSource = function(eventSource, column) {
296    Timeplot.DataSource.apply(this, arguments);
297    this._column = column - 1;
298};
299
300Object.extend(Timeplot.ColumnSource.prototype,Timeplot.DataSource.prototype);
301
302Timeplot.ColumnSource.prototype.dispose = function() {
303    this.removeListener(this._processingListener);
304    this._clear();
305}
306
307Timeplot.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
348Timeplot.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 */
360Timeplot.ColumnDiffSource = function(eventSource, column1, column2) {
361    Timeplot.ColumnSource.apply(this, arguments);
362    this._column2 = column2 - 1;
363};
364
365Object.extend(Timeplot.ColumnDiffSource.prototype,Timeplot.ColumnSource.prototype);
366
367Timeplot.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}