dims.ts 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { DataFrame, Field, FieldMatcher, FieldType, getFieldDisplayName } from '@grafana/data';
  2. import { XYFieldMatchers } from '@grafana/ui/src/components/GraphNG/types';
  3. import { XYDimensionConfig } from './models.gen';
  4. // TODO: fix import
  5. export enum DimensionError {
  6. NoData,
  7. BadFrameSelection,
  8. XNotFound,
  9. }
  10. export interface XYDimensions {
  11. frame: DataFrame; // matches order from configs, excluds non-graphable values
  12. x: Field;
  13. fields: XYFieldMatchers;
  14. error?: DimensionError;
  15. hasData?: boolean;
  16. hasTime?: boolean;
  17. }
  18. export function isGraphable(field: Field) {
  19. return field.type === FieldType.number;
  20. }
  21. export function getXYDimensions(cfg?: XYDimensionConfig, data?: DataFrame[]): XYDimensions {
  22. if (!data || !data.length) {
  23. return { error: DimensionError.NoData } as XYDimensions;
  24. }
  25. if (!cfg) {
  26. cfg = {
  27. frame: 0,
  28. };
  29. }
  30. let frame = data[cfg.frame ?? 0];
  31. if (!frame) {
  32. return { error: DimensionError.BadFrameSelection } as XYDimensions;
  33. }
  34. let xIndex = -1;
  35. for (let i = 0; i < frame.fields.length; i++) {
  36. const f = frame.fields[i];
  37. if (cfg.x && cfg.x === getFieldDisplayName(f, frame, data)) {
  38. xIndex = i;
  39. break;
  40. }
  41. if (isGraphable(f) && !cfg.x) {
  42. xIndex = i;
  43. break;
  44. }
  45. }
  46. let hasTime = false;
  47. const x = frame.fields[xIndex];
  48. const fields: Field[] = [x];
  49. for (const f of frame.fields) {
  50. if (f.type === FieldType.time) {
  51. hasTime = true;
  52. }
  53. if (f === x || !isGraphable(f)) {
  54. continue;
  55. }
  56. if (cfg.exclude) {
  57. const name = getFieldDisplayName(f, frame, data);
  58. if (cfg.exclude.includes(name)) {
  59. continue;
  60. }
  61. }
  62. fields.push(f);
  63. }
  64. return {
  65. x,
  66. fields: {
  67. x: getSimpleFieldMatcher(x),
  68. y: getSimpleFieldNotMatcher(x), // Not x
  69. },
  70. frame: {
  71. ...frame,
  72. fields,
  73. },
  74. hasData: frame.fields.length > 0,
  75. hasTime,
  76. };
  77. }
  78. function getSimpleFieldMatcher(f: Field): FieldMatcher {
  79. if (!f) {
  80. return () => false;
  81. }
  82. // the field may change if sorted
  83. return (field) => f === field || !!(f.state && f.state === field.state);
  84. }
  85. function getSimpleFieldNotMatcher(f: Field): FieldMatcher {
  86. if (!f) {
  87. return () => false;
  88. }
  89. const m = getSimpleFieldMatcher(f);
  90. return (field) => !m(field, undefined as any, undefined as any);
  91. }