mirror of
https://github.com/grafana/grafana.git
synced 2025-02-15 01:53:33 -06:00
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
This commit is contained in:
parent
60502463e2
commit
3c9310e93c
@ -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());
|
||||
|
@ -0,0 +1,21 @@
|
||||
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,
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user