AnnotationsPlugin2: Implement support for rectangular annotations in Heatmap (#88107)
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
co-authored by
Leon Sorokin
parent
2403665998
commit
277067ac9d
+14
@@ -28,6 +28,15 @@ export enum HeatmapColorScale {
|
||||
Linear = 'linear',
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls which axis to allow selection on
|
||||
*/
|
||||
export enum HeatmapSelectionMode {
|
||||
X = 'x',
|
||||
Xy = 'xy',
|
||||
Y = 'y',
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls various color options
|
||||
*/
|
||||
@@ -222,6 +231,10 @@ export interface Options {
|
||||
* Controls tick alignment and value name when not calculating from data
|
||||
*/
|
||||
rowsFrame?: RowsHeatmapOptions;
|
||||
/**
|
||||
* Controls which axis to allow selection on
|
||||
*/
|
||||
selectionMode?: HeatmapSelectionMode;
|
||||
/**
|
||||
* | *{
|
||||
* layout: ui.HeatmapCellLayout & "auto" // TODO: fix after remove when https://github.com/grafana/cuetsy/issues/74 is fixed
|
||||
@@ -265,6 +278,7 @@ export const defaultOptions: Partial<Options> = {
|
||||
legend: {
|
||||
show: true,
|
||||
},
|
||||
selectionMode: HeatmapSelectionMode.X,
|
||||
showValue: ui.VisibilityMode.Auto,
|
||||
tooltip: {
|
||||
mode: ui.TooltipDisplayMode.Single,
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
|
||||
import { AdHocFilterItem } from '../Table/types';
|
||||
|
||||
import { SeriesVisibilityChangeMode } from './types';
|
||||
import { OnSelectRangeCallback, SeriesVisibilityChangeMode } from './types';
|
||||
|
||||
/** @alpha */
|
||||
export interface PanelContext {
|
||||
@@ -43,6 +43,12 @@ export interface PanelContext {
|
||||
onAnnotationUpdate?: (annotation: AnnotationEventUIModel) => void;
|
||||
onAnnotationDelete?: (id: string) => void;
|
||||
|
||||
/**
|
||||
* Called when a user selects an area on the panel, if defined will override the default behavior of the panel,
|
||||
* which is to update the time range
|
||||
*/
|
||||
onSelectRange?: OnSelectRangeCallback;
|
||||
|
||||
/**
|
||||
* Used from visualizations like Table to add ad-hoc filters from cell values
|
||||
*/
|
||||
|
||||
@@ -8,3 +8,15 @@ export enum SeriesVisibilityChangeMode {
|
||||
ToggleSelection = 'select',
|
||||
AppendToSelection = 'append',
|
||||
}
|
||||
|
||||
export type OnSelectRangeCallback = (selections: RangeSelection2D[]) => void;
|
||||
|
||||
export interface RangeSelection1D {
|
||||
from: number;
|
||||
to: number;
|
||||
}
|
||||
|
||||
export interface RangeSelection2D {
|
||||
x?: RangeSelection1D;
|
||||
y?: RangeSelection1D;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { DashboardCursorSync } from '@grafana/schema';
|
||||
|
||||
import { useStyles2 } from '../../../themes';
|
||||
import { RangeSelection1D, RangeSelection2D, OnSelectRangeCallback } from '../../PanelChrome';
|
||||
import { getPortalContainer } from '../../Portal/Portal';
|
||||
import { UPlotConfigBuilder } from '../config/UPlotConfigBuilder';
|
||||
|
||||
@@ -37,6 +38,8 @@ interface TooltipPlugin2Props {
|
||||
// y-only, via shiftKey
|
||||
clientZoom?: boolean;
|
||||
|
||||
onSelectRange?: OnSelectRangeCallback;
|
||||
|
||||
render: (
|
||||
u: uPlot,
|
||||
dataIdxs: Array<number | null>,
|
||||
@@ -107,6 +110,7 @@ export const TooltipPlugin2 = ({
|
||||
render,
|
||||
clientZoom = false,
|
||||
queryZoom,
|
||||
onSelectRange,
|
||||
maxWidth,
|
||||
syncMode = DashboardCursorSync.Off,
|
||||
syncScope = 'global', // eventsScope
|
||||
@@ -319,9 +323,65 @@ export const TooltipPlugin2 = ({
|
||||
|
||||
config.addHook('setSelect', (u) => {
|
||||
const isXAxisHorizontal = u.scales.x.ori === 0;
|
||||
|
||||
if (!viaSync && (clientZoom || queryZoom != null)) {
|
||||
if (maybeZoomAction(u.cursor!.event)) {
|
||||
if (clientZoom && yDrag) {
|
||||
if (onSelectRange != null) {
|
||||
let selections: RangeSelection2D[] = [];
|
||||
|
||||
const yDrag = Boolean(u.cursor!.drag!.y);
|
||||
const xDrag = Boolean(u.cursor!.drag!.x);
|
||||
|
||||
let xSel = null;
|
||||
let ySels: RangeSelection1D[] = [];
|
||||
|
||||
// get x selection
|
||||
if (xDrag) {
|
||||
xSel = {
|
||||
from: isXAxisHorizontal
|
||||
? u.posToVal(u.select.left!, 'x')
|
||||
: u.posToVal(u.select.top + u.select.height, 'x'),
|
||||
to: isXAxisHorizontal
|
||||
? u.posToVal(u.select.left! + u.select.width, 'x')
|
||||
: u.posToVal(u.select.top, 'x'),
|
||||
};
|
||||
}
|
||||
|
||||
// get y selections
|
||||
if (yDrag) {
|
||||
config.scales.forEach((scale) => {
|
||||
const key = scale.props.scaleKey;
|
||||
|
||||
if (key !== 'x') {
|
||||
let ySel = {
|
||||
from: isXAxisHorizontal
|
||||
? u.posToVal(u.select.top + u.select.height, key)
|
||||
: u.posToVal(u.select.left + u.select.width, key),
|
||||
to: isXAxisHorizontal ? u.posToVal(u.select.top, key) : u.posToVal(u.select.left, key),
|
||||
};
|
||||
|
||||
ySels.push(ySel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (xDrag) {
|
||||
if (yDrag) {
|
||||
// x + y
|
||||
selections = ySels.map((ySel) => ({ x: xSel!, y: ySel }));
|
||||
} else {
|
||||
// x only
|
||||
selections = [{ x: xSel! }];
|
||||
}
|
||||
} else {
|
||||
if (yDrag) {
|
||||
// y only
|
||||
selections = ySels.map((ySel) => ({ y: ySel }));
|
||||
}
|
||||
}
|
||||
|
||||
onSelectRange(selections);
|
||||
} else if (clientZoom && yDrag) {
|
||||
if (u.select.height >= MIN_ZOOM_DIST) {
|
||||
for (let key in u.scales!) {
|
||||
if (key !== 'x') {
|
||||
|
||||
Reference in New Issue
Block a user