The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/plugins/panel/xychart/dims.ts

102 lines
2.3 KiB

import { DataFrame, Field, FieldMatcher, FieldType, getFieldDisplayName } from '@grafana/data';
import { XYDimensionConfig } from './models.gen';
// TODO: fix import
import { XYFieldMatchers } from '@grafana/ui/src/components/GraphNG/types';
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;
}
export function getXYDimensions(cfg?: XYDimensionConfig, data?: DataFrame[]): XYDimensions {
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;
}
// the field may change if sorted
return (field) => f === field || !!(f.state && f.state === field.state);
}
function getSimpleFieldNotMatcher(f: Field): FieldMatcher {
if (!f) {
return () => false;
}
const m = getSimpleFieldMatcher(f);
return (field) => !m(field, undefined as any, undefined as any);
}