mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Heatmap: Support heatmap rows with non-timeseries X axis (#60929)
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
@@ -191,7 +191,7 @@ export function rowsToCellsHeatmap(opts: RowsHeatmapOptions): DataFrame {
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'xMax',
|
||||
name: xField.type === FieldType.time ? 'xMax' : 'x',
|
||||
type: xField.type,
|
||||
values: new ArrayVector(xs),
|
||||
config: xField.config,
|
||||
|
||||
@@ -237,7 +237,7 @@ const HeatmapHoverCell = ({ data, hover, showHistogram }: Props) => {
|
||||
<>
|
||||
<div>
|
||||
<div>{xDisp(xBucketMin)}</div>
|
||||
<div>{xDisp(xBucketMax)}</div>
|
||||
{data.xLayout !== HeatmapCellLayout.unknown && <div>{xDisp(xBucketMax)}</div>}
|
||||
</div>
|
||||
{showHistogram && (
|
||||
<canvas
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
incrRoundDn,
|
||||
incrRoundUp,
|
||||
TimeRange,
|
||||
FieldType,
|
||||
} from '@grafana/data';
|
||||
import { AxisPlacement, ScaleDirection, ScaleDistribution, ScaleOrientation } from '@grafana/schema';
|
||||
import { UPlotConfigBuilder } from '@grafana/ui';
|
||||
@@ -98,7 +99,13 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
} = opts;
|
||||
|
||||
const xScaleKey = 'x';
|
||||
const xScaleUnit = 'time';
|
||||
let xScaleUnit = 'time';
|
||||
let isTime = true;
|
||||
|
||||
if (dataRef.current?.heatmap?.fields[0].type !== FieldType.time) {
|
||||
xScaleUnit = dataRef.current?.heatmap?.fields[0].config?.unit ?? 'x';
|
||||
isTime = false;
|
||||
}
|
||||
|
||||
const pxRatio = devicePixelRatio;
|
||||
|
||||
@@ -145,22 +152,24 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);
|
||||
});
|
||||
|
||||
// this is a tmp hack because in mode: 2, uplot does not currently call scales.x.range() for setData() calls
|
||||
// scales.x.range() typically reads back from drilled-down panelProps.timeRange via getTimeRange()
|
||||
builder.addHook('setData', (u) => {
|
||||
//let [min, max] = (u.scales!.x!.range! as uPlot.Range.Function)(u, 0, 100, xScaleKey);
|
||||
if (isTime) {
|
||||
// this is a tmp hack because in mode: 2, uplot does not currently call scales.x.range() for setData() calls
|
||||
// scales.x.range() typically reads back from drilled-down panelProps.timeRange via getTimeRange()
|
||||
builder.addHook('setData', (u) => {
|
||||
//let [min, max] = (u.scales!.x!.range! as uPlot.Range.Function)(u, 0, 100, xScaleKey);
|
||||
|
||||
let { min: xMin, max: xMax } = u.scales!.x;
|
||||
let { min: xMin, max: xMax } = u.scales!.x;
|
||||
|
||||
let min = getTimeRange().from.valueOf();
|
||||
let max = getTimeRange().to.valueOf();
|
||||
let min = getTimeRange().from.valueOf();
|
||||
let max = getTimeRange().to.valueOf();
|
||||
|
||||
if (xMin !== min || xMax !== max) {
|
||||
queueMicrotask(() => {
|
||||
u.setScale(xScaleKey, { min, max });
|
||||
});
|
||||
}
|
||||
});
|
||||
if (xMin !== min || xMax !== max) {
|
||||
queueMicrotask(() => {
|
||||
u.setScale(xScaleKey, { min, max });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// rect of .u-over (grid area)
|
||||
builder.addHook('syncRect', (u, r) => {
|
||||
@@ -236,19 +245,42 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
|
||||
builder.addScale({
|
||||
scaleKey: xScaleKey,
|
||||
isTime: true,
|
||||
isTime,
|
||||
orientation: ScaleOrientation.Horizontal,
|
||||
direction: ScaleDirection.Right,
|
||||
// TODO: expand by x bucket size and layout
|
||||
range: () => {
|
||||
return [getTimeRange().from.valueOf(), getTimeRange().to.valueOf()];
|
||||
range: (u, dataMin, dataMax) => {
|
||||
if (isTime) {
|
||||
return [getTimeRange().from.valueOf(), getTimeRange().to.valueOf()];
|
||||
} else {
|
||||
if (dataRef.current?.xLayout === HeatmapCellLayout.le) {
|
||||
return [dataMin - dataRef.current?.xBucketSize!, dataMax];
|
||||
} else if (dataRef.current?.xLayout === HeatmapCellLayout.ge) {
|
||||
return [dataMin, dataMax + dataRef.current?.xBucketSize!];
|
||||
} else {
|
||||
let offset = dataRef.current?.xBucketSize! / 2;
|
||||
|
||||
return [dataMin - offset, dataMax + offset];
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let incrs;
|
||||
|
||||
if (!isTime) {
|
||||
incrs = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
incrs.push(i * dataRef.current?.xBucketSize!);
|
||||
}
|
||||
}
|
||||
|
||||
builder.addAxis({
|
||||
scaleKey: xScaleKey,
|
||||
placement: AxisPlacement.Bottom,
|
||||
isTime: true,
|
||||
incrs,
|
||||
isTime,
|
||||
theme: theme,
|
||||
timeZone,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user