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.

214 lines
4.6 KiB

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