vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
4.8 KiB

  1. var DataView = require('../DataView');
  2. /**
  3. * @class Filter
  4. *
  5. * @param {DataSet} data The google data table
  6. * @param {Number} column The index of the column to be filtered
  7. * @param {Graph} graph The graph
  8. */
  9. function Filter (data, column, graph) {
  10. this.data = data;
  11. this.column = column;
  12. this.graph = graph; // the parent graph
  13. this.index = undefined;
  14. this.value = undefined;
  15. // read all distinct values and select the first one
  16. this.values = graph.getDistinctValues(data.get(), this.column);
  17. // sort both numeric and string values correctly
  18. this.values.sort(function (a, b) {
  19. return a > b ? 1 : a < b ? -1 : 0;
  20. });
  21. if (this.values.length > 0) {
  22. this.selectValue(0);
  23. }
  24. // create an array with the filtered datapoints. this will be loaded afterwards
  25. this.dataPoints = [];
  26. this.loaded = false;
  27. this.onLoadCallback = undefined;
  28. if (graph.animationPreload) {
  29. this.loaded = false;
  30. this.loadInBackground();
  31. }
  32. else {
  33. this.loaded = true;
  34. }
  35. };
  36. /**
  37. * Return the label
  38. * @return {string} label
  39. */
  40. Filter.prototype.isLoaded = function() {
  41. return this.loaded;
  42. };
  43. /**
  44. * Return the loaded progress
  45. * @return {Number} percentage between 0 and 100
  46. */
  47. Filter.prototype.getLoadedProgress = function() {
  48. var len = this.values.length;
  49. var i = 0;
  50. while (this.dataPoints[i]) {
  51. i++;
  52. }
  53. return Math.round(i / len * 100);
  54. };
  55. /**
  56. * Return the label
  57. * @return {string} label
  58. */
  59. Filter.prototype.getLabel = function() {
  60. return this.graph.filterLabel;
  61. };
  62. /**
  63. * Return the columnIndex of the filter
  64. * @return {Number} columnIndex
  65. */
  66. Filter.prototype.getColumn = function() {
  67. return this.column;
  68. };
  69. /**
  70. * Return the currently selected value. Returns undefined if there is no selection
  71. * @return {*} value
  72. */
  73. Filter.prototype.getSelectedValue = function() {
  74. if (this.index === undefined)
  75. return undefined;
  76. return this.values[this.index];
  77. };
  78. /**
  79. * Retrieve all values of the filter
  80. * @return {Array} values
  81. */
  82. Filter.prototype.getValues = function() {
  83. return this.values;
  84. };
  85. /**
  86. * Retrieve one value of the filter
  87. * @param {Number} index
  88. * @return {*} value
  89. */
  90. Filter.prototype.getValue = function(index) {
  91. if (index >= this.values.length)
  92. throw 'Error: index out of range';
  93. return this.values[index];
  94. };
  95. /**
  96. * Retrieve the (filtered) dataPoints for the currently selected filter index
  97. * @param {Number} [index] (optional)
  98. * @return {Array} dataPoints
  99. */
  100. Filter.prototype._getDataPoints = function(index) {
  101. if (index === undefined)
  102. index = this.index;
  103. if (index === undefined)
  104. return [];
  105. var dataPoints;
  106. if (this.dataPoints[index]) {
  107. dataPoints = this.dataPoints[index];
  108. }
  109. else {
  110. var f = {};
  111. f.column = this.column;
  112. f.value = this.values[index];
  113. var dataView = new DataView(this.data,{filter: function (item) {return (item[f.column] == f.value);}}).get();
  114. dataPoints = this.graph._getDataPoints(dataView);
  115. this.dataPoints[index] = dataPoints;
  116. }
  117. return dataPoints;
  118. };
  119. /**
  120. * Set a callback function when the filter is fully loaded.
  121. */
  122. Filter.prototype.setOnLoadCallback = function(callback) {
  123. this.onLoadCallback = callback;
  124. };
  125. /**
  126. * Add a value to the list with available values for this filter
  127. * No double entries will be created.
  128. * @param {Number} index
  129. */
  130. Filter.prototype.selectValue = function(index) {
  131. if (index >= this.values.length)
  132. throw 'Error: index out of range';
  133. this.index = index;
  134. this.value = this.values[index];
  135. };
  136. /**
  137. * Load all filtered rows in the background one by one
  138. * Start this method without providing an index!
  139. */
  140. Filter.prototype.loadInBackground = function(index) {
  141. if (index === undefined)
  142. index = 0;
  143. var frame = this.graph.frame;
  144. if (index < this.values.length) {
  145. var dataPointsTemp = this._getDataPoints(index);
  146. //this.graph.redrawInfo(); // TODO: not neat
  147. // create a progress box
  148. if (frame.progress === undefined) {
  149. frame.progress = document.createElement('DIV');
  150. frame.progress.style.position = 'absolute';
  151. frame.progress.style.color = 'gray';
  152. frame.appendChild(frame.progress);
  153. }
  154. var progress = this.getLoadedProgress();
  155. frame.progress.innerHTML = 'Loading animation... ' + progress + '%';
  156. // TODO: this is no nice solution...
  157. frame.progress.style.bottom = 60 + 'px'; // TODO: use height of slider
  158. frame.progress.style.left = 10 + 'px';
  159. var me = this;
  160. setTimeout(function() {me.loadInBackground(index+1);}, 10);
  161. this.loaded = false;
  162. }
  163. else {
  164. this.loaded = true;
  165. // remove the progress box
  166. if (frame.progress !== undefined) {
  167. frame.removeChild(frame.progress);
  168. frame.progress = undefined;
  169. }
  170. if (this.onLoadCallback)
  171. this.onLoadCallback();
  172. }
  173. };
  174. module.exports = Filter;