utils.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import {
  2. ArrayVector,
  3. DataFrame,
  4. Field,
  5. FieldType,
  6. getDisplayProcessor,
  7. GrafanaTheme2,
  8. isBooleanUnit,
  9. TimeRange,
  10. } from '@grafana/data';
  11. import { GraphFieldConfig, LineInterpolation } from '@grafana/schema';
  12. import { applyNullInsertThreshold } from '@grafana/ui/src/components/GraphNG/nullInsertThreshold';
  13. import { nullToValue } from '@grafana/ui/src/components/GraphNG/nullToValue';
  14. /**
  15. * Returns null if there are no graphable fields
  16. */
  17. export function prepareGraphableFields(
  18. series: DataFrame[],
  19. theme: GrafanaTheme2,
  20. timeRange?: TimeRange
  21. ): DataFrame[] | null {
  22. if (!series?.length) {
  23. return null;
  24. }
  25. let copy: Field;
  26. const frames: DataFrame[] = [];
  27. for (let frame of series) {
  28. const fields: Field[] = [];
  29. let hasTimeField = false;
  30. let hasValueField = false;
  31. let nulledFrame = applyNullInsertThreshold({
  32. frame,
  33. refFieldPseudoMin: timeRange?.from.valueOf(),
  34. refFieldPseudoMax: timeRange?.to.valueOf(),
  35. });
  36. for (const field of nullToValue(nulledFrame).fields) {
  37. switch (field.type) {
  38. case FieldType.time:
  39. hasTimeField = true;
  40. fields.push(field);
  41. break;
  42. case FieldType.number:
  43. hasValueField = true;
  44. copy = {
  45. ...field,
  46. values: new ArrayVector(
  47. field.values.toArray().map((v) => {
  48. if (!(Number.isFinite(v) || v == null)) {
  49. return null;
  50. }
  51. return v;
  52. })
  53. ),
  54. };
  55. fields.push(copy);
  56. break; // ok
  57. case FieldType.boolean:
  58. hasValueField = true;
  59. const custom: GraphFieldConfig = field.config?.custom ?? {};
  60. const config = {
  61. ...field.config,
  62. max: 1,
  63. min: 0,
  64. custom,
  65. };
  66. // smooth and linear do not make sense
  67. if (custom.lineInterpolation !== LineInterpolation.StepBefore) {
  68. custom.lineInterpolation = LineInterpolation.StepAfter;
  69. }
  70. copy = {
  71. ...field,
  72. config,
  73. type: FieldType.number,
  74. values: new ArrayVector(
  75. field.values.toArray().map((v) => {
  76. if (v == null) {
  77. return v;
  78. }
  79. return Boolean(v) ? 1 : 0;
  80. })
  81. ),
  82. };
  83. if (!isBooleanUnit(config.unit)) {
  84. config.unit = 'bool';
  85. copy.display = getDisplayProcessor({ field: copy, theme });
  86. }
  87. fields.push(copy);
  88. break;
  89. }
  90. }
  91. if (hasTimeField && hasValueField) {
  92. frames.push({
  93. ...frame,
  94. length: nulledFrame.length,
  95. fields,
  96. });
  97. }
  98. }
  99. if (frames.length) {
  100. return frames;
  101. }
  102. return null;
  103. }