ticks.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import { getDataMinMax } from 'app/core/time_series2';
  2. /**
  3. * Calculate tick step.
  4. * Implementation from d3-array (ticks.js)
  5. * https://github.com/d3/d3-array/blob/master/src/ticks.js
  6. * @param start Start value
  7. * @param stop End value
  8. * @param count Ticks count
  9. */
  10. export function tickStep(start: number, stop: number, count: number): number {
  11. let e10 = Math.sqrt(50),
  12. e5 = Math.sqrt(10),
  13. e2 = Math.sqrt(2);
  14. let step0 = Math.abs(stop - start) / Math.max(0, count),
  15. step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
  16. error = step0 / step1;
  17. if (error >= e10) {
  18. step1 *= 10;
  19. } else if (error >= e5) {
  20. step1 *= 5;
  21. } else if (error >= e2) {
  22. step1 *= 2;
  23. }
  24. return stop < start ? -step1 : step1;
  25. }
  26. export function getScaledDecimals(decimals, tick_size) {
  27. return decimals - Math.floor(Math.log(tick_size) / Math.LN10);
  28. }
  29. /**
  30. * Calculate tick size based on min and max values, number of ticks and precision.
  31. * Implementation from Flot.
  32. * @param min Axis minimum
  33. * @param max Axis maximum
  34. * @param noTicks Number of ticks
  35. * @param tickDecimals Tick decimal precision
  36. */
  37. export function getFlotTickSize(
  38. min: number,
  39. max: number,
  40. noTicks: number,
  41. tickDecimals: number
  42. ) {
  43. var delta = (max - min) / noTicks,
  44. dec = -Math.floor(Math.log(delta) / Math.LN10),
  45. maxDec = tickDecimals;
  46. var magn = Math.pow(10, -dec),
  47. norm = delta / magn, // norm is between 1.0 and 10.0
  48. size;
  49. if (norm < 1.5) {
  50. size = 1;
  51. } else if (norm < 3) {
  52. size = 2;
  53. // special case for 2.5, requires an extra decimal
  54. if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
  55. size = 2.5;
  56. ++dec;
  57. }
  58. } else if (norm < 7.5) {
  59. size = 5;
  60. } else {
  61. size = 10;
  62. }
  63. size *= magn;
  64. return size;
  65. }
  66. /**
  67. * Calculate axis range (min and max).
  68. * Implementation from Flot.
  69. */
  70. export function getFlotRange(panelMin, panelMax, datamin, datamax) {
  71. const autoscaleMargin = 0.02;
  72. let min = +(panelMin != null ? panelMin : datamin);
  73. let max = +(panelMax != null ? panelMax : datamax);
  74. let delta = max - min;
  75. if (delta === 0.0) {
  76. // Grafana fix: wide Y min and max using increased wideFactor
  77. // when all series values are the same
  78. var wideFactor = 0.25;
  79. var widen = Math.abs(max === 0 ? 1 : max * wideFactor);
  80. if (panelMin === null) {
  81. min -= widen;
  82. }
  83. // always widen max if we couldn't widen min to ensure we
  84. // don't fall into min == max which doesn't work
  85. if (panelMax == null || panelMin != null) {
  86. max += widen;
  87. }
  88. } else {
  89. // consider autoscaling
  90. var margin = autoscaleMargin;
  91. if (margin != null) {
  92. if (panelMin == null) {
  93. min -= delta * margin;
  94. // make sure we don't go below zero if all values
  95. // are positive
  96. if (min < 0 && datamin != null && datamin >= 0) {
  97. min = 0;
  98. }
  99. }
  100. if (panelMax == null) {
  101. max += delta * margin;
  102. if (max > 0 && datamax != null && datamax <= 0) {
  103. max = 0;
  104. }
  105. }
  106. }
  107. }
  108. return { min, max };
  109. }
  110. /**
  111. * Calculate tick decimals.
  112. * Implementation from Flot.
  113. */
  114. export function getFlotTickDecimals(data, axis) {
  115. let { datamin, datamax } = getDataMinMax(data);
  116. let { min, max } = getFlotRange(axis.min, axis.max, datamin, datamax);
  117. let noTicks = 3;
  118. let tickDecimals, maxDec;
  119. let delta = (max - min) / noTicks;
  120. let dec = -Math.floor(Math.log(delta) / Math.LN10);
  121. let magn = Math.pow(10, -dec);
  122. // norm is between 1.0 and 10.0
  123. let norm = delta / magn;
  124. let size;
  125. if (norm < 1.5) {
  126. size = 1;
  127. } else if (norm < 3) {
  128. size = 2;
  129. // special case for 2.5, requires an extra decimal
  130. if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
  131. size = 2.5;
  132. ++dec;
  133. }
  134. } else if (norm < 7.5) {
  135. size = 5;
  136. } else {
  137. size = 10;
  138. }
  139. size *= magn;
  140. tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
  141. // grafana addition
  142. const scaledDecimals = tickDecimals - Math.floor(Math.log(size) / Math.LN10);
  143. return { tickDecimals, scaledDecimals };
  144. }