2021-02-15 09:46:29 -06:00
|
|
|
import {
|
|
|
|
DataFrame,
|
|
|
|
FieldType,
|
|
|
|
formattedValueToString,
|
|
|
|
getFieldColorModeForField,
|
|
|
|
getFieldDisplayName,
|
|
|
|
getFieldSeriesColor,
|
|
|
|
MutableDataFrame,
|
|
|
|
VizOrientation,
|
|
|
|
} from '@grafana/data';
|
2021-05-11 13:57:52 -05:00
|
|
|
import { BarChartFieldConfig, BarChartOptions, defaultBarChartFieldConfig } from './types';
|
2021-02-15 09:46:29 -06:00
|
|
|
import { BarsOptions, getConfig } from './bars';
|
2021-05-11 13:57:52 -05:00
|
|
|
import {
|
|
|
|
AxisPlacement,
|
|
|
|
FIXED_UNIT,
|
|
|
|
ScaleDirection,
|
|
|
|
ScaleDistribution,
|
|
|
|
ScaleOrientation,
|
|
|
|
UPlotConfigBuilder,
|
2021-05-11 14:40:04 -05:00
|
|
|
UPlotConfigPrepFn,
|
2021-05-11 13:57:52 -05:00
|
|
|
} from '@grafana/ui';
|
2021-02-15 09:46:29 -06:00
|
|
|
|
|
|
|
/** @alpha */
|
2021-05-11 12:24:23 -05:00
|
|
|
function getBarCharScaleOrientation(orientation: VizOrientation) {
|
|
|
|
if (orientation === VizOrientation.Vertical) {
|
|
|
|
return {
|
|
|
|
xOri: ScaleOrientation.Horizontal,
|
|
|
|
xDir: ScaleDirection.Right,
|
|
|
|
yOri: ScaleOrientation.Vertical,
|
|
|
|
yDir: ScaleDirection.Up,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
xOri: ScaleOrientation.Vertical,
|
|
|
|
xDir: ScaleDirection.Down,
|
|
|
|
yOri: ScaleOrientation.Horizontal,
|
|
|
|
yDir: ScaleDirection.Right,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-05-11 13:57:52 -05:00
|
|
|
export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptions> = ({
|
2021-05-11 12:24:23 -05:00
|
|
|
frame,
|
|
|
|
theme,
|
|
|
|
orientation,
|
|
|
|
showValue,
|
|
|
|
groupWidth,
|
|
|
|
barWidth,
|
2021-05-19 10:33:56 -05:00
|
|
|
text,
|
2021-05-11 12:24:23 -05:00
|
|
|
}) => {
|
2021-02-15 09:46:29 -06:00
|
|
|
const builder = new UPlotConfigBuilder();
|
2021-05-11 12:24:23 -05:00
|
|
|
const defaultValueFormatter = (seriesIdx: number, value: any) =>
|
|
|
|
formattedValueToString(frame.fields[seriesIdx].display!(value));
|
2021-02-15 09:46:29 -06:00
|
|
|
|
|
|
|
// bar orientation -> x scale orientation & direction
|
2021-05-11 12:24:23 -05:00
|
|
|
const vizOrientation = getBarCharScaleOrientation(orientation);
|
2021-02-15 09:46:29 -06:00
|
|
|
|
2021-05-19 10:33:56 -05:00
|
|
|
const formatValue = defaultValueFormatter;
|
2021-02-15 09:46:29 -06:00
|
|
|
|
|
|
|
// Use bar width when only one field
|
2021-05-11 12:24:23 -05:00
|
|
|
if (frame.fields.length === 2) {
|
2021-02-15 09:46:29 -06:00
|
|
|
groupWidth = barWidth;
|
|
|
|
barWidth = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const opts: BarsOptions = {
|
2021-05-11 12:24:23 -05:00
|
|
|
xOri: vizOrientation.xOri,
|
|
|
|
xDir: vizOrientation.xDir,
|
2021-02-15 09:46:29 -06:00
|
|
|
groupWidth,
|
|
|
|
barWidth,
|
|
|
|
formatValue,
|
2021-05-19 10:33:56 -05:00
|
|
|
text,
|
|
|
|
showValue,
|
2021-02-15 09:46:29 -06:00
|
|
|
};
|
|
|
|
|
2021-05-19 10:33:56 -05:00
|
|
|
const config = getConfig(opts, theme);
|
2021-02-15 09:46:29 -06:00
|
|
|
|
|
|
|
builder.addHook('init', config.init);
|
|
|
|
builder.addHook('drawClear', config.drawClear);
|
2021-05-19 10:33:56 -05:00
|
|
|
builder.addHook('draw', config.draw);
|
|
|
|
|
2021-05-11 12:24:23 -05:00
|
|
|
builder.setTooltipInterpolator(config.interpolateBarChartTooltip);
|
2021-02-15 09:46:29 -06:00
|
|
|
|
|
|
|
builder.addScale({
|
|
|
|
scaleKey: 'x',
|
|
|
|
isTime: false,
|
|
|
|
distribution: ScaleDistribution.Ordinal,
|
2021-05-11 12:24:23 -05:00
|
|
|
orientation: vizOrientation.xOri,
|
|
|
|
direction: vizOrientation.xDir,
|
2021-02-15 09:46:29 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
builder.addAxis({
|
|
|
|
scaleKey: 'x',
|
|
|
|
isTime: false,
|
2021-05-11 12:24:23 -05:00
|
|
|
placement: vizOrientation.xOri === 0 ? AxisPlacement.Bottom : AxisPlacement.Left,
|
2021-02-15 09:46:29 -06:00
|
|
|
splits: config.xSplits,
|
|
|
|
values: config.xValues,
|
|
|
|
grid: false,
|
|
|
|
ticks: false,
|
|
|
|
gap: 15,
|
|
|
|
theme,
|
|
|
|
});
|
|
|
|
|
|
|
|
let seriesIndex = 0;
|
|
|
|
|
|
|
|
// iterate the y values
|
2021-05-11 12:24:23 -05:00
|
|
|
for (let i = 1; i < frame.fields.length; i++) {
|
|
|
|
const field = frame.fields[i];
|
2021-02-15 09:46:29 -06:00
|
|
|
|
|
|
|
field.state!.seriesIndex = seriesIndex++;
|
|
|
|
|
|
|
|
const customConfig: BarChartFieldConfig = { ...defaultBarChartFieldConfig, ...field.config.custom };
|
|
|
|
|
|
|
|
const scaleKey = field.config.unit || FIXED_UNIT;
|
|
|
|
const colorMode = getFieldColorModeForField(field);
|
|
|
|
const scaleColor = getFieldSeriesColor(field, theme);
|
|
|
|
const seriesColor = scaleColor.color;
|
|
|
|
|
|
|
|
builder.addSeries({
|
|
|
|
scaleKey,
|
|
|
|
pxAlign: false,
|
|
|
|
lineWidth: customConfig.lineWidth,
|
|
|
|
lineColor: seriesColor,
|
|
|
|
fillOpacity: customConfig.fillOpacity,
|
|
|
|
theme,
|
|
|
|
colorMode,
|
|
|
|
pathBuilder: config.drawBars,
|
2021-05-06 14:22:03 -05:00
|
|
|
show: !customConfig.hideFrom?.viz,
|
2021-02-15 09:46:29 -06:00
|
|
|
gradientMode: customConfig.gradientMode,
|
|
|
|
thresholds: field.config.thresholds,
|
|
|
|
|
|
|
|
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
|
|
|
dataFrameFieldIndex: {
|
|
|
|
fieldIndex: i,
|
|
|
|
frameIndex: 0,
|
|
|
|
},
|
2021-05-11 12:24:23 -05:00
|
|
|
fieldName: getFieldDisplayName(field, frame),
|
2021-02-15 09:46:29 -06:00
|
|
|
hideInLegend: customConfig.hideFrom?.legend,
|
|
|
|
});
|
|
|
|
|
|
|
|
// The builder will manage unique scaleKeys and combine where appropriate
|
|
|
|
builder.addScale({
|
|
|
|
scaleKey,
|
|
|
|
min: field.config.min,
|
|
|
|
max: field.config.max,
|
|
|
|
softMin: customConfig.axisSoftMin,
|
|
|
|
softMax: customConfig.axisSoftMax,
|
2021-05-11 12:24:23 -05:00
|
|
|
orientation: vizOrientation.yOri,
|
|
|
|
direction: vizOrientation.yDir,
|
2021-02-15 09:46:29 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
if (customConfig.axisPlacement !== AxisPlacement.Hidden) {
|
|
|
|
let placement = customConfig.axisPlacement;
|
|
|
|
if (!placement || placement === AxisPlacement.Auto) {
|
|
|
|
placement = AxisPlacement.Left;
|
|
|
|
}
|
2021-05-11 12:24:23 -05:00
|
|
|
if (vizOrientation.xOri === 1) {
|
2021-02-15 09:46:29 -06:00
|
|
|
if (placement === AxisPlacement.Left) {
|
|
|
|
placement = AxisPlacement.Bottom;
|
|
|
|
}
|
|
|
|
if (placement === AxisPlacement.Right) {
|
|
|
|
placement = AxisPlacement.Top;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
builder.addAxis({
|
|
|
|
scaleKey,
|
|
|
|
label: customConfig.axisLabel,
|
|
|
|
size: customConfig.axisWidth,
|
|
|
|
placement,
|
|
|
|
formatValue: (v) => formattedValueToString(field.display!(v)),
|
|
|
|
theme,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return builder;
|
2021-05-11 12:24:23 -05:00
|
|
|
};
|
2021-02-15 09:46:29 -06:00
|
|
|
|
|
|
|
/** @internal */
|
|
|
|
export function preparePlotFrame(data: DataFrame[]) {
|
|
|
|
const firstFrame = data[0];
|
|
|
|
const firstString = firstFrame.fields.find((f) => f.type === FieldType.string);
|
|
|
|
|
|
|
|
if (!firstString) {
|
|
|
|
throw new Error('No string field in DF');
|
|
|
|
}
|
|
|
|
|
|
|
|
const resultFrame = new MutableDataFrame();
|
|
|
|
resultFrame.addField(firstString);
|
|
|
|
|
|
|
|
for (const f of firstFrame.fields) {
|
|
|
|
if (f.type === FieldType.number) {
|
|
|
|
resultFrame.addField(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return resultFrame;
|
|
|
|
}
|