BarChart: refactor x tick label placement logic (#43256)

This commit is contained in:
Leon Sorokin
2021-12-17 11:35:09 -06:00
committed by GitHub
parent 5cffd98e24
commit dd247f26de
2 changed files with 33 additions and 13 deletions

View File

@ -1,4 +1,4 @@
import uPlot, { Axis, AlignedData } from 'uplot'; import uPlot, { Axis, AlignedData, Scale } from 'uplot';
import { pointWithin, Quadtree, Rect } from './quadtree'; import { pointWithin, Quadtree, Rect } from './quadtree';
import { distribute, SPACE_BETWEEN } from './distribute'; import { distribute, SPACE_BETWEEN } from './distribute';
import { DataFrame, GrafanaTheme2 } from '@grafana/data'; import { DataFrame, GrafanaTheme2 } from '@grafana/data';
@ -75,24 +75,42 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
barMark.style.background = 'rgba(255,255,255,0.4)'; barMark.style.background = 'rgba(255,255,255,0.4)';
const xSplits: Axis.Splits = (u: uPlot) => { const xSplits: Axis.Splits = (u: uPlot) => {
const dim = isXHorizontal ? u.bbox.width : u.bbox.height;
const _dir = dir * (isXHorizontal ? 1 : -1); const _dir = dir * (isXHorizontal ? 1 : -1);
let splits: number[] = []; // for distr: 2 scales, the splits array should contain indices into data[0] rather than values
let splits = u.data[0].map((v, i) => i);
distribute(u.data[0].length, groupWidth, groupDistr, null, (di, leftPct, widPct) => {
let groupLftPx = (dim * leftPct) / devicePixelRatio;
let groupWidPx = (dim * widPct) / devicePixelRatio;
let groupCenterPx = groupLftPx + groupWidPx / 2;
splits.push(u.posToVal(groupCenterPx, 'x'));
});
return _dir === 1 ? splits : splits.reverse(); return _dir === 1 ? splits : splits.reverse();
}; };
const xValues: Axis.Values = (u) => u.data[0].map((x) => formatValue(0, x)); // the splits passed into here are data[0] values looked up by the indices returned from splits()
const xValues: Axis.Values = (u, splits) => {
return splits.map((v) => formatValue(0, v));
};
// this expands the distr: 2 scale so that the indicies of each data[0] land at the proper justified positions
const xRange: Scale.Range = (u, min, max) => {
min = 0;
max = u.data[0].length - 1;
let pctOffset = 0;
// how far in is the first tick in % of full dimension
distribute(u.data[0].length, groupWidth, groupDistr, 0, (di, lftPct, widPct) => {
pctOffset = lftPct + widPct / 2;
});
// expand scale range by equal amounts on both ends
let rn = max - min; // TODO: clamp to 1?
let upScale = 1 / (1 - pctOffset * 2);
let offset = (upScale * rn - rn) / 2;
min -= offset;
max += offset;
return [min, max];
};
let distrTwo = (groupCount: number, barCount: number) => { let distrTwo = (groupCount: number, barCount: number) => {
let out = Array.from({ length: barCount }, () => ({ let out = Array.from({ length: barCount }, () => ({
@ -335,6 +353,7 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) {
points: { show: false }, points: { show: false },
}, },
// scale & axis opts // scale & axis opts
xRange,
xValues, xValues,
xSplits, xSplits,

View File

@ -108,6 +108,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptions> = ({
builder.addScale({ builder.addScale({
scaleKey: 'x', scaleKey: 'x',
isTime: false, isTime: false,
range: config.xRange,
distribution: ScaleDistribution.Ordinal, distribution: ScaleDistribution.Ordinal,
orientation: vizOrientation.xOri, orientation: vizOrientation.xOri,
direction: vizOrientation.xDir, direction: vizOrientation.xDir,