mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Histogram: enable client-side zoom (with bucket snapping) (#35220)
This commit is contained in:
parent
e1af571efd
commit
43d3d97562
@ -1,5 +1,5 @@
|
||||
import uPlot, { Cursor, Band, Hooks, Select } from 'uplot';
|
||||
import { defaultsDeep } from 'lodash';
|
||||
import { merge } from 'lodash';
|
||||
import {
|
||||
DataFrame,
|
||||
DefaultTimeZone,
|
||||
@ -17,6 +17,24 @@ import { AxisPlacement } from '../config';
|
||||
import { pluginLog } from '../utils';
|
||||
import { getThresholdsDrawHook, UPlotThresholdOptions } from './UPlotThresholds';
|
||||
|
||||
const cursorDefaults: Cursor = {
|
||||
// prevent client-side zoom from triggering at the end of a selection
|
||||
drag: { setScale: false },
|
||||
points: {
|
||||
/*@ts-ignore*/
|
||||
size: (u, seriesIdx) => u.series[seriesIdx].points.size * 2,
|
||||
/*@ts-ignore*/
|
||||
width: (u, seriesIdx, size) => size / 4,
|
||||
/*@ts-ignore*/
|
||||
stroke: (u, seriesIdx) => u.series[seriesIdx].points.stroke(u, seriesIdx) + '80',
|
||||
/*@ts-ignore*/
|
||||
fill: (u, seriesIdx) => u.series[seriesIdx].points.stroke(u, seriesIdx),
|
||||
},
|
||||
focus: {
|
||||
prox: 30,
|
||||
},
|
||||
};
|
||||
|
||||
export class UPlotConfigBuilder {
|
||||
private series: UPlotSeriesBuilder[] = [];
|
||||
private axes: Record<string, UPlotAxisBuilder> = {};
|
||||
@ -98,7 +116,7 @@ export class UPlotConfigBuilder {
|
||||
}
|
||||
|
||||
setCursor(cursor?: Cursor) {
|
||||
this.cursor = { ...this.cursor, ...cursor };
|
||||
this.cursor = merge({}, this.cursor, cursor);
|
||||
}
|
||||
|
||||
setSelect(select: Select) {
|
||||
@ -153,11 +171,9 @@ export class UPlotConfigBuilder {
|
||||
|
||||
config.hooks = this.hooks;
|
||||
|
||||
/* @ts-ignore */
|
||||
// uPlot types don't export the Select interface prior to 1.6.4
|
||||
config.select = this.select;
|
||||
|
||||
config.cursor = this.cursor || {};
|
||||
config.cursor = merge({}, cursorDefaults, this.cursor);
|
||||
|
||||
config.tzDate = this.tzDate;
|
||||
|
||||
@ -181,26 +197,6 @@ export class UPlotConfigBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
const cursorDefaults: Cursor = {
|
||||
// prevent client-side zoom from triggering at the end of a selection
|
||||
drag: { setScale: false },
|
||||
points: {
|
||||
/*@ts-ignore*/
|
||||
size: (u, seriesIdx) => u.series[seriesIdx].points.size * 2,
|
||||
/*@ts-ignore*/
|
||||
width: (u, seriesIdx, size) => size / 4,
|
||||
/*@ts-ignore*/
|
||||
stroke: (u, seriesIdx) => u.series[seriesIdx].points.stroke(u, seriesIdx) + '80',
|
||||
/*@ts-ignore*/
|
||||
fill: (u, seriesIdx) => u.series[seriesIdx].points.stroke(u, seriesIdx),
|
||||
},
|
||||
focus: {
|
||||
prox: 30,
|
||||
},
|
||||
};
|
||||
|
||||
defaultsDeep(config.cursor, cursorDefaults);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,14 @@ import {
|
||||
import { PanelOptions } from './models.gen';
|
||||
import { ScaleDistribution } from '@grafana/ui/src/components/uPlot/models.gen';
|
||||
|
||||
function incrRoundDn(num: number, incr: number) {
|
||||
return Math.floor(num / incr) * incr;
|
||||
}
|
||||
|
||||
function incrRoundUp(num: number, incr: number) {
|
||||
return Math.ceil(num / incr) * incr;
|
||||
}
|
||||
|
||||
export interface HistogramProps extends Themeable2 {
|
||||
options: PanelOptions; // used for diff
|
||||
alignedFrame: DataFrame; // This could take HistogramFields
|
||||
@ -70,7 +78,24 @@ const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => {
|
||||
distribution: ScaleDistribution.Linear,
|
||||
orientation: ScaleOrientation.Horizontal,
|
||||
direction: ScaleDirection.Right,
|
||||
range: (u) => [u.data[0][0], u.data[0][u.data[0].length - 1] + bucketSize],
|
||||
range: (u, wantedMin, wantedMax) => {
|
||||
let fullRangeMin = u.data[0][0];
|
||||
let fullRangeMax = u.data[0][u.data[0].length - 1];
|
||||
|
||||
// snap to bucket divisors...
|
||||
|
||||
if (wantedMax === fullRangeMax) {
|
||||
wantedMax += bucketSize;
|
||||
} else {
|
||||
wantedMax = incrRoundUp(wantedMax, bucketSize);
|
||||
}
|
||||
|
||||
if (wantedMin > fullRangeMin) {
|
||||
wantedMin = incrRoundDn(wantedMin, bucketSize);
|
||||
}
|
||||
|
||||
return [wantedMin, wantedMax];
|
||||
},
|
||||
});
|
||||
|
||||
builder.addScale({
|
||||
@ -114,6 +139,14 @@ const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => {
|
||||
theme,
|
||||
});
|
||||
|
||||
builder.setCursor({
|
||||
drag: {
|
||||
x: true,
|
||||
y: false,
|
||||
setScale: true,
|
||||
},
|
||||
});
|
||||
|
||||
let pathBuilder = uPlot.paths.bars!({ align: 1, size: [1, Infinity] });
|
||||
|
||||
let seriesIndex = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user