scale.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import { DataFrame, Field } from '@grafana/data';
  2. import { getMinMaxAndDelta } from '../../../../packages/grafana-data/src/field/scale';
  3. import { ScaleDimensionConfig, DimensionSupplier, ScaleDimensionOptions } from './types';
  4. import { findField, getLastNotNullFieldValue } from './utils';
  5. import { ScaleDimensionMode } from '.';
  6. //---------------------------------------------------------
  7. // Scale dimension
  8. //---------------------------------------------------------
  9. export function getScaledDimension(
  10. frame: DataFrame | undefined,
  11. config: ScaleDimensionConfig
  12. ): DimensionSupplier<number> {
  13. return getScaledDimensionForField(findField(frame, config?.field), config);
  14. }
  15. export function getScaledDimensionForField(
  16. field: Field | undefined,
  17. config: ScaleDimensionConfig,
  18. mode?: ScaleDimensionMode
  19. ): DimensionSupplier<number> {
  20. if (!field) {
  21. const v = config.fixed ?? 0;
  22. return {
  23. isAssumed: Boolean(config.field?.length) || !config.fixed,
  24. fixed: v,
  25. value: () => v,
  26. get: () => v,
  27. };
  28. }
  29. const info = getMinMaxAndDelta(field);
  30. const delta = config.max - config.min;
  31. const values = field.values;
  32. if (values.length < 1 || delta <= 0 || info.delta <= 0) {
  33. return {
  34. fixed: config.min,
  35. value: () => config.min,
  36. get: () => config.min,
  37. };
  38. }
  39. let scaled = (percent: number) => config.min + percent * delta;
  40. if (mode === ScaleDimensionMode.Quadratic) {
  41. const maxArea = Math.PI * (config.max / 2) ** 2;
  42. const minArea = Math.PI * (config.min / 2) ** 2;
  43. const deltaArea = maxArea - minArea;
  44. // quadratic scaling (px area)
  45. scaled = (percent: number) => {
  46. let area = minArea + deltaArea * percent;
  47. return Math.sqrt(area / Math.PI) * 2;
  48. };
  49. }
  50. const get = (i: number) => {
  51. const value = field.values.get(i);
  52. let percent = 0;
  53. if (value !== -Infinity) {
  54. percent = (value - info.min!) / info.delta;
  55. }
  56. if (percent > 1) {
  57. percent = 1;
  58. } else if (percent < 0) {
  59. percent = 0;
  60. }
  61. return scaled(percent);
  62. };
  63. return {
  64. get,
  65. value: () => get(getLastNotNullFieldValue(field)),
  66. field,
  67. };
  68. }
  69. // This will mutate options
  70. export function validateScaleOptions(options?: ScaleDimensionOptions): ScaleDimensionOptions {
  71. if (!options) {
  72. options = { min: 0, max: 1 };
  73. }
  74. if (options.min == null) {
  75. options.min = 0;
  76. }
  77. if (options.max == null) {
  78. options.max = 1;
  79. }
  80. return options;
  81. }
  82. /** Mutates and will return a valid version */
  83. export function validateScaleConfig(copy: ScaleDimensionConfig, options: ScaleDimensionOptions): ScaleDimensionConfig {
  84. let { min, max } = validateScaleOptions(options);
  85. if (!copy) {
  86. copy = {} as any;
  87. }
  88. if (copy.max == null) {
  89. copy.max = max;
  90. }
  91. if (copy.min == null) {
  92. copy.min = min;
  93. }
  94. // Make sure the order is right
  95. if (copy.min > copy.max) {
  96. const tmp = copy.max;
  97. copy.max = copy.min;
  98. copy.min = tmp;
  99. }
  100. // Validate range
  101. if (copy.min < min) {
  102. copy.min = min;
  103. }
  104. if (copy.max > max) {
  105. copy.max = max;
  106. }
  107. if (copy.fixed == null) {
  108. copy.fixed = copy.min + (copy.max - copy.min) / 2.0;
  109. }
  110. // Make sure the field value is within the absolute range
  111. if (!copy.field) {
  112. if (copy.fixed > max) {
  113. copy.fixed = max;
  114. } else if (copy.fixed < min) {
  115. copy.fixed = min;
  116. }
  117. }
  118. return copy;
  119. }