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.

156 lines
4.4 KiB

  1. /**
  2. * @prototype StepNumber
  3. * The class StepNumber is an iterator for Numbers. You provide a start and end
  4. * value, and a best step size. StepNumber itself rounds to fixed values and
  5. * a finds the step that best fits the provided step.
  6. *
  7. * If prettyStep is true, the step size is chosen as close as possible to the
  8. * provided step, but being a round value like 1, 2, 5, 10, 20, 50, ....
  9. *
  10. * Example usage:
  11. * var step = new StepNumber(0, 10, 2.5, true);
  12. * step.start();
  13. * while (!step.end()) {
  14. * alert(step.getCurrent());
  15. * step.next();
  16. * }
  17. *
  18. * Version: 1.0
  19. *
  20. * @param {Number} start The start value
  21. * @param {Number} end The end value
  22. * @param {Number} step Optional. Step size. Must be a positive value.
  23. * @param {boolean} prettyStep Optional. If true, the step size is rounded
  24. * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
  25. */
  26. function StepNumber(start, end, step, prettyStep) {
  27. // set default values
  28. this._start = 0;
  29. this._end = 0;
  30. this._step = 1;
  31. this.prettyStep = true;
  32. this.precision = 5;
  33. this._current = 0;
  34. this.setRange(start, end, step, prettyStep);
  35. };
  36. /**
  37. * Set a new range: start, end and step.
  38. *
  39. * @param {Number} start The start value
  40. * @param {Number} end The end value
  41. * @param {Number} step Optional. Step size. Must be a positive value.
  42. * @param {boolean} prettyStep Optional. If true, the step size is rounded
  43. * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
  44. */
  45. StepNumber.prototype.setRange = function(start, end, step, prettyStep) {
  46. this._start = start ? start : 0;
  47. this._end = end ? end : 0;
  48. this.setStep(step, prettyStep);
  49. };
  50. /**
  51. * Set a new step size
  52. * @param {Number} step New step size. Must be a positive value
  53. * @param {boolean} prettyStep Optional. If true, the provided step is rounded
  54. * to a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
  55. */
  56. StepNumber.prototype.setStep = function(step, prettyStep) {
  57. if (step === undefined || step <= 0)
  58. return;
  59. if (prettyStep !== undefined)
  60. this.prettyStep = prettyStep;
  61. if (this.prettyStep === true)
  62. this._step = StepNumber.calculatePrettyStep(step);
  63. else
  64. this._step = step;
  65. };
  66. /**
  67. * Calculate a nice step size, closest to the desired step size.
  68. * Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an
  69. * integer Number. For example 1, 2, 5, 10, 20, 50, etc...
  70. * @param {Number} step Desired step size
  71. * @return {Number} Nice step size
  72. */
  73. StepNumber.calculatePrettyStep = function (step) {
  74. var log10 = function (x) {return Math.log(x) / Math.LN10;};
  75. // try three steps (multiple of 1, 2, or 5
  76. var step1 = Math.pow(10, Math.round(log10(step))),
  77. step2 = 2 * Math.pow(10, Math.round(log10(step / 2))),
  78. step5 = 5 * Math.pow(10, Math.round(log10(step / 5)));
  79. // choose the best step (closest to minimum step)
  80. var prettyStep = step1;
  81. if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2;
  82. if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5;
  83. // for safety
  84. if (prettyStep <= 0) {
  85. prettyStep = 1;
  86. }
  87. return prettyStep;
  88. };
  89. /**
  90. * returns the current value of the step
  91. * @return {Number} current value
  92. */
  93. StepNumber.prototype.getCurrent = function () {
  94. return parseFloat(this._current.toPrecision(this.precision));
  95. };
  96. /**
  97. * returns the current step size
  98. * @return {Number} current step size
  99. */
  100. StepNumber.prototype.getStep = function () {
  101. return this._step;
  102. };
  103. /**
  104. * Set the current to its starting value.
  105. *
  106. * By default, this will be the largest value smaller than start, which
  107. * is a multiple of the step size.
  108. *
  109. * Parameters checkFirst is optional, default false.
  110. * If set to true, move the current value one step if smaller than start.
  111. */
  112. StepNumber.prototype.start = function(checkFirst) {
  113. if (checkFirst === undefined) {
  114. checkFirst = false;
  115. }
  116. this._current = this._start - this._start % this._step;
  117. if (checkFirst) {
  118. if (this.getCurrent() < this._start) {
  119. this.next();
  120. }
  121. }
  122. };
  123. /**
  124. * Do a step, add the step size to the current value
  125. */
  126. StepNumber.prototype.next = function () {
  127. this._current += this._step;
  128. };
  129. /**
  130. * Returns true whether the end is reached
  131. * @return {boolean} True if the current value has passed the end value.
  132. */
  133. StepNumber.prototype.end = function () {
  134. return (this._current > this._end);
  135. };
  136. module.exports = StepNumber;