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