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.

210 lines
4.5 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.data = dataGroup.getDataSet();
  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.data,{filter: function (item) {return (item[f.column] == f.value);}}).get();
  110. dataPoints = this.graph._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. Filter.prototype.setOnLoadCallback = function(callback) {
  119. this.onLoadCallback = callback;
  120. };
  121. /**
  122. * Add a value to the list with available values for this filter
  123. * No double entries will be created.
  124. * @param {Number} index
  125. */
  126. Filter.prototype.selectValue = function(index) {
  127. if (index >= this.values.length)
  128. throw new Error('Index out of range');
  129. this.index = index;
  130. this.value = this.values[index];
  131. };
  132. /**
  133. * Load all filtered rows in the background one by one
  134. * Start this method without providing an index!
  135. */
  136. Filter.prototype.loadInBackground = function(index) {
  137. if (index === undefined)
  138. index = 0;
  139. var frame = this.graph.frame;
  140. if (index < this.values.length) {
  141. // create a progress box
  142. if (frame.progress === undefined) {
  143. frame.progress = document.createElement('DIV');
  144. frame.progress.style.position = 'absolute';
  145. frame.progress.style.color = 'gray';
  146. frame.appendChild(frame.progress);
  147. }
  148. var progress = this.getLoadedProgress();
  149. frame.progress.innerHTML = 'Loading animation... ' + progress + '%';
  150. // TODO: this is no nice solution...
  151. frame.progress.style.bottom = 60 + 'px'; // TODO: use height of slider
  152. frame.progress.style.left = 10 + 'px';
  153. var me = this;
  154. setTimeout(function() {me.loadInBackground(index+1);}, 10);
  155. this.loaded = false;
  156. }
  157. else {
  158. this.loaded = true;
  159. // remove the progress box
  160. if (frame.progress !== undefined) {
  161. frame.removeChild(frame.progress);
  162. frame.progress = undefined;
  163. }
  164. if (this.onLoadCallback)
  165. this.onLoadCallback();
  166. }
  167. };
  168. module.exports = Filter;