|
|
|
@ -1,9 +1,16 @@ |
|
|
|
|
import uPlot, { Axis } from 'uplot'; |
|
|
|
|
import { pointWithin, Quadtree, Rect } from './quadtree'; |
|
|
|
|
import { distribute, SPACE_BETWEEN } from './distribute'; |
|
|
|
|
import { BarValueVisibility, ScaleDirection, ScaleOrientation } from '@grafana/ui/src/components/uPlot/config'; |
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data'; |
|
|
|
|
import { calculateFontSize, PlotTooltipInterpolator, VizTextDisplayOptions } from '@grafana/ui'; |
|
|
|
|
import { |
|
|
|
|
calculateFontSize, |
|
|
|
|
PlotTooltipInterpolator, |
|
|
|
|
VizTextDisplayOptions, |
|
|
|
|
StackingMode, |
|
|
|
|
BarValueVisibility, |
|
|
|
|
ScaleDirection, |
|
|
|
|
ScaleOrientation, |
|
|
|
|
} from '@grafana/ui'; |
|
|
|
|
|
|
|
|
|
const groupDistr = SPACE_BETWEEN; |
|
|
|
|
const barDistr = SPACE_BETWEEN; |
|
|
|
@ -33,6 +40,8 @@ export interface BarsOptions { |
|
|
|
|
groupWidth: number; |
|
|
|
|
barWidth: number; |
|
|
|
|
showValue: BarValueVisibility; |
|
|
|
|
stacking: StackingMode; |
|
|
|
|
rawValue: (seriesIdx: number, valueIdx: number) => number | null; |
|
|
|
|
formatValue: (seriesIdx: number, value: any) => string; |
|
|
|
|
text?: VizTextDisplayOptions; |
|
|
|
|
onHover?: (seriesIdx: number, valueIdx: number) => void; |
|
|
|
@ -43,9 +52,10 @@ export interface BarsOptions { |
|
|
|
|
* @internal |
|
|
|
|
*/ |
|
|
|
|
export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) { |
|
|
|
|
const { xOri, xDir: dir, groupWidth, barWidth, formatValue, showValue } = opts; |
|
|
|
|
const { xOri, xDir: dir, groupWidth, barWidth, rawValue, formatValue, showValue } = opts; |
|
|
|
|
const isXHorizontal = xOri === ScaleOrientation.Horizontal; |
|
|
|
|
const hasAutoValueSize = !Boolean(opts.text?.valueSize); |
|
|
|
|
const isStacked = opts.stacking !== StackingMode.None; |
|
|
|
|
|
|
|
|
|
let qt: Quadtree; |
|
|
|
|
let hovered: Rect | undefined = undefined; |
|
|
|
@ -91,6 +101,22 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) { |
|
|
|
|
return out; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let distrOne = (groupCount: number, barCount: number) => { |
|
|
|
|
let out = Array.from({ length: barCount }, () => ({ |
|
|
|
|
offs: Array(groupCount).fill(0), |
|
|
|
|
size: Array(groupCount).fill(0), |
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
distribute(groupCount, groupWidth, groupDistr, null, (groupIdx, groupOffPct, groupDimPct) => { |
|
|
|
|
distribute(barCount, barWidth, barDistr, null, (barIdx, barOffPct, barDimPct) => { |
|
|
|
|
out[barIdx].offs[groupIdx] = groupOffPct; |
|
|
|
|
out[barIdx].size[groupIdx] = groupDimPct; |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return out; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let barsPctLayout: Array<null | { offs: number[]; size: number[] }> = []; |
|
|
|
|
let barRects: Rect[] = []; |
|
|
|
|
|
|
|
|
@ -151,7 +177,12 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) { |
|
|
|
|
s._paths = null; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
barsPctLayout = ([null] as any).concat(distrTwo(u.data[0].length, u.data.length - 1)); |
|
|
|
|
if (isStacked) { |
|
|
|
|
//barsPctLayout = [null as any].concat(distrOne(u.data.length - 1, u.data[0].length));
|
|
|
|
|
barsPctLayout = [null as any].concat(distrOne(u.data[0].length, u.data.length - 1)); |
|
|
|
|
} else { |
|
|
|
|
barsPctLayout = [null as any].concat(distrTwo(u.data[0].length, u.data.length - 1)); |
|
|
|
|
} |
|
|
|
|
barRects.length = 0; |
|
|
|
|
vSpace = hSpace = Infinity; |
|
|
|
|
}; |
|
|
|
@ -166,7 +197,7 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) { |
|
|
|
|
let labelOffset = LABEL_OFFSET_MAX; |
|
|
|
|
|
|
|
|
|
barRects.forEach((r, i) => { |
|
|
|
|
texts[i] = formatValue(r.sidx, u.data[r.sidx][r.didx]); |
|
|
|
|
texts[i] = formatValue(r.sidx, rawValue(r.sidx, r.didx)); |
|
|
|
|
labelOffset = Math.min(labelOffset, Math.round(LABEL_OFFSET_FACTOR * (isXHorizontal ? r.w : r.h))); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
@ -201,7 +232,7 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) { |
|
|
|
|
let curAlign: CanvasTextAlign, curBaseline: CanvasTextBaseline; |
|
|
|
|
|
|
|
|
|
barRects.forEach((r, i) => { |
|
|
|
|
let value = u.data[r.sidx][r.didx]; |
|
|
|
|
let value = rawValue(r.sidx, r.didx); |
|
|
|
|
let text = texts[i]; |
|
|
|
|
|
|
|
|
|
if (value != null) { |
|
|
|
|