Commit 3c9310e9 by Ryan McKinley Committed by GitHub

GraphNG: support auto and explicit axis width (#29553)

* auto axis

* auto axis

* expand everyhting with the same scale/unit

* expand everyhting with the same scale/unit
parent 60502463
......@@ -114,14 +114,15 @@ export const GraphNG: React.FC<GraphNGProps> = ({
}
const fmt = field.display ?? defaultFormatter;
const scale = config.unit || '__fixed';
const isNewScale = !builder.hasScale(scale);
const scaleKey = config.unit || '__fixed';
if (isNewScale && customConfig.axisPlacement !== AxisPlacement.Hidden) {
builder.addScale({ scaleKey: scale, min: field.config.min, max: field.config.max });
if (customConfig.axisPlacement !== AxisPlacement.Hidden) {
// The builder will manage unique scaleKeys and combine where appropriate
builder.addScale({ scaleKey, min: field.config.min, max: field.config.max });
builder.addAxis({
scaleKey: scale,
scaleKey,
label: customConfig.axisLabel,
size: customConfig.axisWidth,
placement: customConfig.axisPlacement ?? AxisPlacement.Auto,
formatValue: v => formattedValueToString(fmt(v)),
theme,
......@@ -136,7 +137,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
const pointsMode = customConfig.mode === GraphMode.Points ? PointMode.Always : customConfig.points;
builder.addSeries({
scaleKey: scale,
scaleKey,
mode: customConfig.mode!,
lineColor: seriesColor,
lineWidth: customConfig.lineWidth,
......@@ -149,7 +150,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
});
if (hasLegend.current) {
const axisPlacement = builder.getAxisPlacement(scale);
const axisPlacement = builder.getAxisPlacement(scaleKey);
legendItems.push({
color: seriesColor,
......
......@@ -3,13 +3,14 @@ import uPlot, { Axis } from 'uplot';
import { PlotConfigBuilder } from '../types';
import { measureText } from '../../../utils/measureText';
import { AxisPlacement } from '../config';
import { optMinMax } from './UPlotScaleBuilder';
export interface AxisProps {
scaleKey: string;
theme: GrafanaTheme;
label?: string;
show?: boolean;
size?: number;
size?: number | null;
placement?: AxisPlacement;
grid?: boolean;
formatValue?: (v: any) => string;
......@@ -19,6 +20,16 @@ export interface AxisProps {
}
export class UPlotAxisBuilder extends PlotConfigBuilder<AxisProps, Axis> {
merge(props: AxisProps) {
this.props.size = optMinMax('max', this.props.size, props.size);
if (!this.props.label) {
this.props.label = props.label;
}
if (this.props.placement === AxisPlacement.Auto) {
this.props.placement = props.placement;
}
}
getConfig(): Axis {
const {
scaleKey,
......@@ -42,7 +53,7 @@ export class UPlotAxisBuilder extends PlotConfigBuilder<AxisProps, Axis> {
side: getUPlotSideFromAxis(placement),
font: `12px 'Roboto'`,
labelFont: `12px 'Roboto'`,
size: calculateAxisSize,
size: this.props.size ?? calculateAxisSize,
grid: {
show: grid,
stroke: gridColor,
......@@ -107,8 +118,7 @@ function calculateAxisSize(self: uPlot, values: string[], axisIdx: number) {
}
}
let axisWidth = measureText(maxLength, 12).width + 18;
return axisWidth;
return measureText(maxLength, 12).width + 18;
}
/** Format time axis ticks */
......
......@@ -61,7 +61,6 @@ describe('UPlotConfigBuilder', () => {
formatValue: () => 'test value',
grid: false,
show: true,
size: 1,
theme: { isDark: true, palette: { gray25: '#ffffff' }, colors: { text: 'gray' } } as GrafanaTheme,
values: [],
});
......
......@@ -8,13 +8,17 @@ export class UPlotConfigBuilder {
private series: UPlotSeriesBuilder[] = [];
private axes: Record<string, UPlotAxisBuilder> = {};
private scales: UPlotScaleBuilder[] = [];
private registeredScales: string[] = [];
hasLeftAxis = false;
addAxis(props: AxisProps) {
props.placement = props.placement ?? AxisPlacement.Auto;
if (this.axes[props.scaleKey]) {
this.axes[props.scaleKey].merge(props);
return;
}
// Handle auto placement logic
if (props.placement === AxisPlacement.Auto) {
props.placement = this.hasLeftAxis ? AxisPlacement.Right : AxisPlacement.Left;
......@@ -36,15 +40,16 @@ export class UPlotConfigBuilder {
this.series.push(new UPlotSeriesBuilder(props));
}
/** Add or update the scale with the scale key */
addScale(props: ScaleProps) {
this.registeredScales.push(props.scaleKey);
const current = this.scales.find(v => v.props.scaleKey === props.scaleKey);
if (current) {
current.merge(props);
return;
}
this.scales.push(new UPlotScaleBuilder(props));
}
hasScale(scaleKey: string) {
return this.registeredScales.indexOf(scaleKey) > -1;
}
getConfig() {
const config: PlotSeriesConfig = { series: [{}] };
config.axes = Object.values(this.axes).map(a => a.getConfig());
......
import { optMinMax } from './UPlotScaleBuilder';
describe('UPlotScaleBuilder', () => {
it('opt min max', () => {
expect(7).toEqual(optMinMax('min', null, 7));
expect(7).toEqual(optMinMax('min', undefined, 7));
expect(7).toEqual(optMinMax('min', 20, 7));
expect(7).toEqual(optMinMax('min', 7, null));
expect(7).toEqual(optMinMax('min', 7, undefined));
expect(7).toEqual(optMinMax('min', 7, 20));
expect(7).toEqual(optMinMax('max', null, 7));
expect(7).toEqual(optMinMax('max', undefined, 7));
expect(7).toEqual(optMinMax('max', 5, 7));
expect(7).toEqual(optMinMax('max', 7, null));
expect(7).toEqual(optMinMax('max', 7, undefined));
expect(7).toEqual(optMinMax('max', 7, 5));
});
});
......@@ -9,6 +9,11 @@ export interface ScaleProps {
}
export class UPlotScaleBuilder extends PlotConfigBuilder<ScaleProps, Scale> {
merge(props: ScaleProps) {
this.props.min = optMinMax('min', this.props.min, props.min);
this.props.max = optMinMax('max', this.props.max, props.max);
}
getConfig() {
const { isTime, scaleKey } = this.props;
if (isTime) {
......@@ -29,3 +34,18 @@ export class UPlotScaleBuilder extends PlotConfigBuilder<ScaleProps, Scale> {
};
}
}
export function optMinMax(minmax: 'min' | 'max', a?: number | null, b?: number | null): undefined | number | null {
const hasA = !(a === undefined || a === null);
const hasB = !(b === undefined || b === null);
if (hasA) {
if (!hasB) {
return a;
}
if (minmax === 'min') {
return a! < b! ? a : b;
}
return a! > b! ? a : b;
}
return b;
}
......@@ -107,9 +107,8 @@ export const plugin = new PanelPlugin<Options, GraphFieldConfig>(GraphPanel)
path: 'axisWidth',
name: 'Width',
category: ['Axis'],
defaultValue: 60,
settings: {
placeholder: '60',
placeholder: 'Auto',
},
showIf: c => c.axisPlacement !== AxisPlacement.Hidden,
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment