Trend: Support disconnect values and connect nulls options (#70616)

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
This commit is contained in:
Drew Slobodnjak
2023-07-13 19:28:58 -07:00
committed by GitHub
co-authored by Leon Sorokin nmarrs
parent 3afc20fae9
commit 1a857552a1
11 changed files with 1336 additions and 489 deletions
@@ -54,7 +54,7 @@ export interface GraphNGProps extends Themeable2 {
children?: (builder: UPlotConfigBuilder, alignedFrame: DataFrame) => React.ReactNode;
prepConfig: (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => UPlotConfigBuilder;
propsToDiff?: Array<string | PropDiffFn>;
preparePlotFrame?: (frames: DataFrame[], dimFields: XYFieldMatchers) => DataFrame;
preparePlotFrame?: (frames: DataFrame[], dimFields: XYFieldMatchers) => DataFrame | null;
renderLegend: (config: UPlotConfigBuilder) => React.ReactElement | null;
/**
@@ -1,4 +1,6 @@
import { DataFrame, FieldType } from '@grafana/data';
import { DataFrame } from '@grafana/data';
import { getRefField } from './utils';
type InsertMode = (prev: number, next: number, threshold: number) => number;
@@ -29,10 +31,7 @@ export function applyNullInsertThreshold(opts: NullInsertOptions): DataFrame {
insertMode = INSERT_MODES.threshold;
}
const refField = frame.fields.find((field) => {
// note: getFieldDisplayName() would require full DF[]
return refFieldName != null ? field.name === refFieldName : field.type === FieldType.time;
});
const refField = getRefField(frame, refFieldName);
if (refField == null) {
return frame;
@@ -18,9 +18,17 @@ function isVisibleBarField(f: Field) {
);
}
export function getRefField(frame: DataFrame, refFieldName?: string | null) {
return frame.fields.find((field) => {
// note: getFieldDisplayName() would require full DF[]
return refFieldName != null ? field.name === refFieldName : field.type === FieldType.time;
});
}
// will mutate the DataFrame's fields' values
function applySpanNullsThresholds(frame: DataFrame) {
let refField = frame.fields.find((field) => field.type === FieldType.time); // this doesnt need to be time, just any numeric/asc join field
function applySpanNullsThresholds(frame: DataFrame, refFieldName?: string | null) {
const refField = getRefField(frame, refFieldName);
let refValues = refField?.values as any[];
for (let i = 0; i < frame.fields.length; i++) {
@@ -43,12 +51,22 @@ function applySpanNullsThresholds(frame: DataFrame) {
}
export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers, timeRange?: TimeRange | null) {
let xField: Field;
loop: for (let frame of frames) {
for (let field of frame.fields) {
if (dimFields.x(field, frame, frames)) {
xField = field;
break loop;
}
}
}
// apply null insertions at interval
frames = frames.map((frame) => {
if (!frame.fields[0].state?.nullThresholdApplied) {
if (!xField?.state?.nullThresholdApplied) {
return applyNullInsertThreshold({
frame,
refFieldName: null,
refFieldName: xField.name,
refFieldPseudoMin: timeRange?.from.valueOf(),
refFieldPseudoMax: timeRange?.to.valueOf(),
});
@@ -84,7 +102,7 @@ export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers
return;
}
const xVals = frame.fields[0].values;
const xVals = xField.values;
for (let i = 0; i < xVals.length; i++) {
if (i > 0) {
@@ -102,7 +120,7 @@ export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers
});
if (alignedFrame) {
alignedFrame = applySpanNullsThresholds(alignedFrame);
alignedFrame = applySpanNullsThresholds(alignedFrame, xField!.name);
// append 2 null vals at minXDelta to bar series
if (minXDelta !== Infinity) {