2021-01-22 13:25:39 -08:00
|
|
|
import { DataFrame, Field, FieldMatcher, FieldType, getFieldDisplayName } from '@grafana/data';
|
2022-04-22 14:33:13 +01:00
|
|
|
import { XYFieldMatchers } from '@grafana/ui/src/components/GraphNG/types';
|
|
|
|
|
|
2023-07-10 17:54:01 -07:00
|
|
|
import { XYDimensionConfig } from './panelcfg.gen';
|
2021-01-10 22:57:48 -08:00
|
|
|
|
2021-02-15 16:46:29 +01:00
|
|
|
// TODO: fix import
|
|
|
|
|
|
2021-01-10 22:57:48 -08:00
|
|
|
export enum DimensionError {
|
|
|
|
|
NoData,
|
|
|
|
|
BadFrameSelection,
|
|
|
|
|
XNotFound,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface XYDimensions {
|
|
|
|
|
frame: DataFrame; // matches order from configs, excluds non-graphable values
|
|
|
|
|
x: Field;
|
|
|
|
|
fields: XYFieldMatchers;
|
|
|
|
|
error?: DimensionError;
|
|
|
|
|
hasData?: boolean;
|
|
|
|
|
hasTime?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isGraphable(field: Field) {
|
|
|
|
|
return field.type === FieldType.number;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-15 16:46:29 +01:00
|
|
|
export function getXYDimensions(cfg?: XYDimensionConfig, data?: DataFrame[]): XYDimensions {
|
2021-01-10 22:57:48 -08:00
|
|
|
if (!data || !data.length) {
|
|
|
|
|
return { error: DimensionError.NoData } as XYDimensions;
|
|
|
|
|
}
|
|
|
|
|
if (!cfg) {
|
|
|
|
|
cfg = {
|
|
|
|
|
frame: 0,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let frame = data[cfg.frame ?? 0];
|
|
|
|
|
if (!frame) {
|
|
|
|
|
return { error: DimensionError.BadFrameSelection } as XYDimensions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let xIndex = -1;
|
|
|
|
|
for (let i = 0; i < frame.fields.length; i++) {
|
|
|
|
|
const f = frame.fields[i];
|
|
|
|
|
if (cfg.x && cfg.x === getFieldDisplayName(f, frame, data)) {
|
|
|
|
|
xIndex = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (isGraphable(f) && !cfg.x) {
|
|
|
|
|
xIndex = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let hasTime = false;
|
|
|
|
|
const x = frame.fields[xIndex];
|
|
|
|
|
const fields: Field[] = [x];
|
|
|
|
|
for (const f of frame.fields) {
|
|
|
|
|
if (f.type === FieldType.time) {
|
|
|
|
|
hasTime = true;
|
|
|
|
|
}
|
|
|
|
|
if (f === x || !isGraphable(f)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (cfg.exclude) {
|
|
|
|
|
const name = getFieldDisplayName(f, frame, data);
|
|
|
|
|
if (cfg.exclude.includes(name)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fields.push(f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
x,
|
|
|
|
|
fields: {
|
|
|
|
|
x: getSimpleFieldMatcher(x),
|
|
|
|
|
y: getSimpleFieldNotMatcher(x), // Not x
|
|
|
|
|
},
|
|
|
|
|
frame: {
|
|
|
|
|
...frame,
|
|
|
|
|
fields,
|
|
|
|
|
},
|
|
|
|
|
hasData: frame.fields.length > 0,
|
|
|
|
|
hasTime,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSimpleFieldMatcher(f: Field): FieldMatcher {
|
|
|
|
|
if (!f) {
|
|
|
|
|
return () => false;
|
|
|
|
|
}
|
2021-01-22 13:25:39 -08:00
|
|
|
// the field may change if sorted
|
|
|
|
|
return (field) => f === field || !!(f.state && f.state === field.state);
|
2021-01-10 22:57:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSimpleFieldNotMatcher(f: Field): FieldMatcher {
|
|
|
|
|
if (!f) {
|
|
|
|
|
return () => false;
|
|
|
|
|
}
|
2021-01-22 13:25:39 -08:00
|
|
|
const m = getSimpleFieldMatcher(f);
|
|
|
|
|
return (field) => !m(field, undefined as any, undefined as any);
|
2021-01-10 22:57:48 -08:00
|
|
|
}
|