mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CursorSync: Extract EventBus logic into shared plugin (#84111)
This commit is contained in:
@@ -1159,11 +1159,9 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "5"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "6"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "7"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "8"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "9"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "10"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "11"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "8"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "9"]
|
||||
],
|
||||
"public/app/core/components/GraphNG/hooks.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import { merge } from 'lodash';
|
||||
import uPlot, { Cursor, Band, Hooks, Select, AlignedData, Padding, Series } from 'uplot';
|
||||
|
||||
import {
|
||||
DataFrame,
|
||||
DefaultTimeZone,
|
||||
EventBus,
|
||||
Field,
|
||||
getTimeZoneInfo,
|
||||
GrafanaTheme2,
|
||||
TimeRange,
|
||||
TimeZone,
|
||||
} from '@grafana/data';
|
||||
import { DataFrame, DefaultTimeZone, Field, getTimeZoneInfo, GrafanaTheme2, TimeRange, TimeZone } from '@grafana/data';
|
||||
import { AxisPlacement, VizOrientation } from '@grafana/schema';
|
||||
|
||||
import { FacetedData, PlotConfig, PlotTooltipInterpolator } from '../types';
|
||||
@@ -306,7 +297,6 @@ type UPlotConfigPrepOpts<T extends Record<string, unknown> = {}> = {
|
||||
theme: GrafanaTheme2;
|
||||
timeZones: TimeZone[];
|
||||
getTimeRange: () => TimeRange;
|
||||
eventBus: EventBus;
|
||||
allFrames: DataFrame[];
|
||||
renderers?: Renderers;
|
||||
tweakScale?: (opts: ScaleProps, forField: Field) => ScaleProps;
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
import { throttle } from 'lodash';
|
||||
import { useLayoutEffect, useRef } from 'react';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { throttleTime } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
DataFrame,
|
||||
DataHoverClearEvent,
|
||||
DataHoverEvent,
|
||||
DataHoverPayload,
|
||||
EventBus,
|
||||
LegacyGraphHoverEvent,
|
||||
} from '@grafana/data';
|
||||
|
||||
import { UPlotConfigBuilder } from '../config/UPlotConfigBuilder';
|
||||
|
||||
interface EventBusPluginProps {
|
||||
config: UPlotConfigBuilder;
|
||||
eventBus: EventBus;
|
||||
sync: () => boolean;
|
||||
frame?: DataFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export const EventBusPlugin = ({ config, eventBus, sync, frame }: EventBusPluginProps) => {
|
||||
const frameRef = useRef<DataFrame | undefined>(frame);
|
||||
frameRef.current = frame;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
let u: uPlot | null = null;
|
||||
|
||||
const payload: DataHoverPayload = {
|
||||
point: {
|
||||
time: null,
|
||||
},
|
||||
data: frameRef.current,
|
||||
};
|
||||
|
||||
config.addHook('init', (_u) => {
|
||||
u = _u;
|
||||
});
|
||||
|
||||
let closestSeriesIdx: number | null = null;
|
||||
|
||||
config.addHook('setSeries', (u, seriesIdx) => {
|
||||
closestSeriesIdx = seriesIdx;
|
||||
});
|
||||
|
||||
config.addHook('setLegend', () => {
|
||||
let viaSync = u!.cursor.event == null;
|
||||
|
||||
if (!viaSync && sync()) {
|
||||
let dataIdx = u!.cursor.idxs!.find((v) => v != null);
|
||||
|
||||
if (dataIdx == null) {
|
||||
throttledClear();
|
||||
} else {
|
||||
let rowIdx = dataIdx;
|
||||
let colIdx = closestSeriesIdx;
|
||||
|
||||
let xData = u!.data[0] ?? u!.data[1][0];
|
||||
|
||||
payload.point.time = xData[rowIdx];
|
||||
payload.rowIndex = rowIdx ?? undefined;
|
||||
payload.columnIndex = colIdx ?? undefined;
|
||||
payload.data = frameRef.current;
|
||||
|
||||
// used by old graph panel to position tooltip
|
||||
let top = u!.cursor.top!;
|
||||
payload.point.panelRelY = top === 0 ? 0.001 : top > 0 ? top / u!.rect.height : 1;
|
||||
|
||||
throttledHover();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function handleCursorUpdate(evt: DataHoverEvent | LegacyGraphHoverEvent) {
|
||||
const time = evt.payload?.point?.time;
|
||||
|
||||
if (time) {
|
||||
// Try finding left position on time axis
|
||||
const left = u!.valToPos(time, 'x');
|
||||
|
||||
// let top;
|
||||
|
||||
// if (left) {
|
||||
// top = findMidPointYPosition(u!, u!.posToIdx(left));
|
||||
// }
|
||||
|
||||
// if (!top || !left) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
u!.setCursor({
|
||||
left,
|
||||
top: u!.rect.height / 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const subscription = new Subscription();
|
||||
|
||||
const hoverEvent = new DataHoverEvent(payload).setTags(['uplot']);
|
||||
const clearEvent = new DataHoverClearEvent().setTags(['uplot']);
|
||||
|
||||
let throttledHover = throttle(() => {
|
||||
eventBus.publish(hoverEvent);
|
||||
}, 100);
|
||||
|
||||
let throttledClear = throttle(() => {
|
||||
eventBus.publish(clearEvent);
|
||||
}, 100);
|
||||
|
||||
subscription.add(
|
||||
eventBus.getStream(DataHoverEvent).subscribe({
|
||||
next: (evt) => {
|
||||
// ignore uplot-emitted events, since we already use uPlot's sync
|
||||
if (eventBus === evt.origin || evt.tags?.has('uplot')) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleCursorUpdate(evt);
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Legacy events (from flot graph)
|
||||
subscription.add(
|
||||
eventBus.getStream(LegacyGraphHoverEvent).subscribe({
|
||||
next: (evt) => handleCursorUpdate(evt),
|
||||
})
|
||||
);
|
||||
|
||||
subscription.add(
|
||||
eventBus
|
||||
.getStream(DataHoverClearEvent)
|
||||
.pipe(throttleTime(50)) // dont throttle here, throttle on emission
|
||||
.subscribe({
|
||||
next: (evt) => {
|
||||
// ignore uplot-emitted events, since we already use uPlot's sync
|
||||
if (eventBus === evt.origin || evt.tags?.has('uplot')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (!u!.cursor._lock) {
|
||||
u!.setCursor({
|
||||
left: -10,
|
||||
top: -10,
|
||||
});
|
||||
}
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, [config]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -501,9 +501,9 @@ export const TooltipPlugin2 = ({
|
||||
}
|
||||
});
|
||||
|
||||
const onscroll = () => {
|
||||
const onscroll = (e: Event) => {
|
||||
updatePlotVisible();
|
||||
_isHovering && !_isPinned && dismiss();
|
||||
_isHovering && !_isPinned && e.target instanceof HTMLElement && e.target.contains(_plot!.root) && dismiss();
|
||||
};
|
||||
|
||||
window.addEventListener('resize', updateWinSize);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export { ZoomPlugin } from './ZoomPlugin';
|
||||
export { TooltipPlugin } from './TooltipPlugin';
|
||||
export { TooltipPlugin2 } from './TooltipPlugin2';
|
||||
export { EventBusPlugin } from './EventBusPlugin';
|
||||
export { KeyboardPlugin } from './KeyboardPlugin';
|
||||
|
||||
@@ -75,13 +75,10 @@ exports[`GraphNG utils preparePlotConfigBuilder 1`] = `
|
||||
"width": [Function],
|
||||
},
|
||||
"sync": {
|
||||
"filters": {
|
||||
"pub": [Function],
|
||||
},
|
||||
"key": "__global_",
|
||||
"scales": [
|
||||
"x",
|
||||
"__fixed/na-na/na-na/auto/linear/na/number",
|
||||
null,
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
DashboardCursorSync,
|
||||
DataFrame,
|
||||
DefaultTimeZone,
|
||||
EventBusSrv,
|
||||
// EventBusSrv,
|
||||
FieldColorModeId,
|
||||
FieldConfig,
|
||||
FieldMatcherID,
|
||||
@@ -215,7 +215,6 @@ describe('GraphNG utils', () => {
|
||||
theme: createTheme(),
|
||||
timeZones: [DefaultTimeZone],
|
||||
getTimeRange: getDefaultTimeRange,
|
||||
eventBus: new EventBusSrv(),
|
||||
sync: () => DashboardCursorSync.Tooltip,
|
||||
allFrames: [frame!],
|
||||
}).getConfig();
|
||||
|
||||
@@ -19,7 +19,7 @@ export class UnthemedTimeSeries extends Component<TimeSeriesProps> {
|
||||
declare context: React.ContextType<typeof PanelContextRoot>;
|
||||
|
||||
prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
|
||||
const { eventBus, eventsScope, sync } = this.context;
|
||||
const { eventsScope, sync } = this.context;
|
||||
const { theme, timeZone, renderers, tweakAxis, tweakScale } = this.props;
|
||||
|
||||
return preparePlotConfigBuilder({
|
||||
@@ -27,7 +27,6 @@ export class UnthemedTimeSeries extends Component<TimeSeriesProps> {
|
||||
theme,
|
||||
timeZones: Array.isArray(timeZone) ? timeZone : [timeZone],
|
||||
getTimeRange,
|
||||
eventBus,
|
||||
sync,
|
||||
allFrames,
|
||||
renderers,
|
||||
|
||||
@@ -4,9 +4,6 @@ import uPlot from 'uplot';
|
||||
import {
|
||||
DashboardCursorSync,
|
||||
DataFrame,
|
||||
DataHoverClearEvent,
|
||||
DataHoverEvent,
|
||||
DataHoverPayload,
|
||||
FieldConfig,
|
||||
FieldType,
|
||||
formattedValueToString,
|
||||
@@ -81,7 +78,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
theme,
|
||||
timeZones,
|
||||
getTimeRange,
|
||||
eventBus,
|
||||
sync,
|
||||
allFrames,
|
||||
renderers,
|
||||
@@ -107,7 +103,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
}
|
||||
|
||||
const xScaleKey = 'x';
|
||||
let xScaleUnit = '_x';
|
||||
let yScaleKey = '';
|
||||
|
||||
const xFieldAxisPlacement =
|
||||
@@ -115,7 +110,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
const xFieldAxisShow = xField.config.custom?.axisPlacement !== AxisPlacement.Hidden;
|
||||
|
||||
if (xField.type === FieldType.time) {
|
||||
xScaleUnit = 'time';
|
||||
builder.addScale({
|
||||
scaleKey: xScaleKey,
|
||||
orientation: ScaleOrientation.Horizontal,
|
||||
@@ -173,11 +167,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Not time!
|
||||
if (xField.config.unit) {
|
||||
xScaleUnit = xField.config.unit;
|
||||
}
|
||||
|
||||
builder.addScale({
|
||||
scaleKey: xScaleKey,
|
||||
orientation: ScaleOrientation.Horizontal,
|
||||
@@ -609,41 +598,9 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
};
|
||||
|
||||
if (sync && sync() !== DashboardCursorSync.Off) {
|
||||
const payload: DataHoverPayload = {
|
||||
point: {
|
||||
[xScaleKey]: null,
|
||||
[yScaleKey]: null,
|
||||
},
|
||||
data: frame,
|
||||
};
|
||||
|
||||
const hoverEvent = new DataHoverEvent(payload);
|
||||
cursor.sync = {
|
||||
key: eventsScope,
|
||||
filters: {
|
||||
pub: (type: string, src: uPlot, x: number, y: number, w: number, h: number, dataIdx: number) => {
|
||||
if (sync && sync() === DashboardCursorSync.Off) {
|
||||
return false;
|
||||
}
|
||||
|
||||
payload.rowIndex = dataIdx;
|
||||
if (x < 0 && y < 0) {
|
||||
payload.point[xScaleUnit] = null;
|
||||
payload.point[yScaleKey] = null;
|
||||
eventBus.publish(new DataHoverClearEvent());
|
||||
} else {
|
||||
// convert the points
|
||||
payload.point[xScaleUnit] = src.posToVal(x, xScaleKey);
|
||||
payload.point[yScaleKey] = src.posToVal(y, yScaleKey);
|
||||
payload.point.panelRelY = y > 0 ? y / h : 1; // used by old graph panel to position tooltip
|
||||
eventBus.publish(hoverEvent);
|
||||
hoverEvent.payload.down = undefined;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
scales: [xScaleKey, yScaleKey],
|
||||
// match: [() => true, (a, b) => a === b],
|
||||
scales: [xScaleKey, null],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { throttleTime } from 'rxjs/operators';
|
||||
import uPlot, { AlignedData } from 'uplot';
|
||||
|
||||
import {
|
||||
DataFrame,
|
||||
DataHoverClearEvent,
|
||||
DataHoverEvent,
|
||||
DataLinkPostProcessor,
|
||||
Field,
|
||||
FieldMatcherID,
|
||||
@@ -14,17 +10,16 @@ import {
|
||||
FieldType,
|
||||
getLinksSupplier,
|
||||
InterpolateFunction,
|
||||
LegacyGraphHoverEvent,
|
||||
TimeRange,
|
||||
TimeZone,
|
||||
} from '@grafana/data';
|
||||
import { VizLegendOptions } from '@grafana/schema';
|
||||
import { Themeable2, PanelContext, PanelContextRoot, VizLayout } from '@grafana/ui';
|
||||
import { Themeable2, PanelContextRoot, VizLayout } from '@grafana/ui';
|
||||
import { UPlotChart } from '@grafana/ui/src/components/uPlot/Plot';
|
||||
import { AxisProps } from '@grafana/ui/src/components/uPlot/config/UPlotAxisBuilder';
|
||||
import { Renderers, UPlotConfigBuilder } from '@grafana/ui/src/components/uPlot/config/UPlotConfigBuilder';
|
||||
import { ScaleProps } from '@grafana/ui/src/components/uPlot/config/UPlotScaleBuilder';
|
||||
import { findMidPointYPosition, pluginLog } from '@grafana/ui/src/components/uPlot/utils';
|
||||
import { pluginLog } from '@grafana/ui/src/components/uPlot/utils';
|
||||
|
||||
import { GraphNGLegendEvent, XYFieldMatchers } from './types';
|
||||
import { preparePlotFrame as defaultPreparePlotFrame } from './utils';
|
||||
@@ -92,11 +87,8 @@ export interface GraphNGState {
|
||||
*/
|
||||
export class GraphNG extends Component<GraphNGProps, GraphNGState> {
|
||||
static contextType = PanelContextRoot;
|
||||
panelContext: PanelContext = {} as PanelContext;
|
||||
private plotInstance: React.RefObject<uPlot>;
|
||||
|
||||
private subscription = new Subscription();
|
||||
|
||||
constructor(props: GraphNGProps) {
|
||||
super(props);
|
||||
let state = this.prepState(props);
|
||||
@@ -180,82 +172,6 @@ export class GraphNG extends Component<GraphNGProps, GraphNGState> {
|
||||
return state;
|
||||
}
|
||||
|
||||
handleCursorUpdate(evt: DataHoverEvent | LegacyGraphHoverEvent) {
|
||||
// ignore uplot-emitted events, since we already use uPlot's sync
|
||||
if (evt.tags?.has('uplot')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const time = evt.payload?.point?.time;
|
||||
const u = this.plotInstance.current;
|
||||
if (u && time) {
|
||||
// Try finding left position on time axis
|
||||
const left = u.valToPos(time, 'x');
|
||||
let top;
|
||||
if (left) {
|
||||
// find midpoint between points at current idx
|
||||
top = findMidPointYPosition(u, u.posToIdx(left));
|
||||
}
|
||||
|
||||
if (!top || !left) {
|
||||
return;
|
||||
}
|
||||
|
||||
u.setCursor({
|
||||
left,
|
||||
top,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.panelContext = this.context as PanelContext;
|
||||
const { eventBus } = this.panelContext;
|
||||
|
||||
this.subscription.add(
|
||||
eventBus
|
||||
.getStream(DataHoverEvent)
|
||||
.pipe(throttleTime(50))
|
||||
.subscribe({
|
||||
next: (evt) => {
|
||||
if (eventBus === evt.origin) {
|
||||
return;
|
||||
}
|
||||
this.handleCursorUpdate(evt);
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Legacy events (from flot graph)
|
||||
this.subscription.add(
|
||||
eventBus
|
||||
.getStream(LegacyGraphHoverEvent)
|
||||
.pipe(throttleTime(50))
|
||||
.subscribe({
|
||||
next: (evt) => this.handleCursorUpdate(evt),
|
||||
})
|
||||
);
|
||||
|
||||
this.subscription.add(
|
||||
eventBus
|
||||
.getStream(DataHoverClearEvent)
|
||||
.pipe(throttleTime(50))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
const u = this.plotInstance?.current;
|
||||
|
||||
// @ts-ignore
|
||||
if (u && !u.cursor._lock) {
|
||||
u.setCursor({
|
||||
left: -10,
|
||||
top: -10,
|
||||
});
|
||||
}
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: GraphNGProps) {
|
||||
const { frames, structureRev, timeZone, propsToDiff } = this.props;
|
||||
|
||||
@@ -284,10 +200,6 @@ export class GraphNG extends Component<GraphNGProps, GraphNGState> {
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { width, height, children, renderLegend } = this.props;
|
||||
const { config, alignedFrame, alignedData } = this.state;
|
||||
|
||||
@@ -80,9 +80,6 @@ exports[`GraphNG utils preparePlotConfigBuilder 1`] = `
|
||||
"width": [Function],
|
||||
},
|
||||
"sync": {
|
||||
"filters": {
|
||||
"pub": [Function],
|
||||
},
|
||||
"key": "__global_",
|
||||
"scales": [
|
||||
"x",
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
DashboardCursorSync,
|
||||
DataFrame,
|
||||
DefaultTimeZone,
|
||||
EventBusSrv,
|
||||
FieldColorModeId,
|
||||
FieldConfig,
|
||||
FieldMatcherID,
|
||||
@@ -215,7 +214,6 @@ describe('GraphNG utils', () => {
|
||||
theme: createTheme(),
|
||||
timeZones: [DefaultTimeZone],
|
||||
getTimeRange: getDefaultTimeRange,
|
||||
eventBus: new EventBusSrv(),
|
||||
sync: () => DashboardCursorSync.Tooltip,
|
||||
allFrames: [frame!],
|
||||
}).getConfig();
|
||||
|
||||
@@ -19,7 +19,7 @@ export class UnthemedTimeSeries extends Component<TimeSeriesProps> {
|
||||
declare context: React.ContextType<typeof PanelContextRoot>;
|
||||
|
||||
prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
|
||||
const { eventBus, eventsScope, sync } = this.context;
|
||||
const { eventsScope, sync } = this.context;
|
||||
const { theme, timeZone, options, renderers, tweakAxis, tweakScale } = this.props;
|
||||
|
||||
return preparePlotConfigBuilder({
|
||||
@@ -27,7 +27,6 @@ export class UnthemedTimeSeries extends Component<TimeSeriesProps> {
|
||||
theme,
|
||||
timeZones: Array.isArray(timeZone) ? timeZone : [timeZone],
|
||||
getTimeRange,
|
||||
eventBus,
|
||||
sync,
|
||||
allFrames,
|
||||
renderers,
|
||||
|
||||
@@ -4,9 +4,6 @@ import uPlot from 'uplot';
|
||||
import {
|
||||
DashboardCursorSync,
|
||||
DataFrame,
|
||||
DataHoverClearEvent,
|
||||
DataHoverEvent,
|
||||
DataHoverPayload,
|
||||
FieldConfig,
|
||||
FieldType,
|
||||
formattedValueToString,
|
||||
@@ -83,7 +80,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
theme,
|
||||
timeZones,
|
||||
getTimeRange,
|
||||
eventBus,
|
||||
sync,
|
||||
allFrames,
|
||||
renderers,
|
||||
@@ -113,7 +109,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
}
|
||||
|
||||
const xScaleKey = 'x';
|
||||
let xScaleUnit = '_x';
|
||||
let yScaleKey = '';
|
||||
|
||||
const xFieldAxisPlacement =
|
||||
@@ -125,7 +120,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
const xFieldAxisShow = xField.config.custom?.axisPlacement !== AxisPlacement.Hidden;
|
||||
|
||||
if (xField.type === FieldType.time) {
|
||||
xScaleUnit = 'time';
|
||||
builder.addScale({
|
||||
scaleKey: xScaleKey,
|
||||
orientation: isHorizontal ? ScaleOrientation.Horizontal : ScaleOrientation.Vertical,
|
||||
@@ -185,11 +179,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Not time!
|
||||
if (xField.config.unit) {
|
||||
xScaleUnit = xField.config.unit;
|
||||
}
|
||||
|
||||
builder.addScale({
|
||||
scaleKey: xScaleKey,
|
||||
orientation: isHorizontal ? ScaleOrientation.Horizontal : ScaleOrientation.Vertical,
|
||||
@@ -597,40 +586,9 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
},
|
||||
};
|
||||
|
||||
if (sync && sync() !== DashboardCursorSync.Off && xField.type === FieldType.time) {
|
||||
const payload: DataHoverPayload = {
|
||||
point: {
|
||||
[xScaleKey]: null,
|
||||
[yScaleKey]: null,
|
||||
},
|
||||
data: frame,
|
||||
};
|
||||
|
||||
const hoverEvent = new DataHoverEvent(payload).setTags(['uplot']);
|
||||
const clearEvent = new DataHoverClearEvent().setTags(['uplot']);
|
||||
|
||||
if (xField.type === FieldType.time && sync && sync() !== DashboardCursorSync.Off) {
|
||||
cursor.sync = {
|
||||
key: eventsScope,
|
||||
filters: {
|
||||
pub: (type: string, src: uPlot, x: number, y: number, w: number, h: number, dataIdx: number) => {
|
||||
if (sync && sync() === DashboardCursorSync.Off) {
|
||||
return false;
|
||||
}
|
||||
|
||||
payload.rowIndex = dataIdx;
|
||||
if (x < 0 && y < 0) {
|
||||
eventBus.publish(clearEvent);
|
||||
} else {
|
||||
// convert the points
|
||||
payload.point[xScaleUnit] = src.posToVal(x, xScaleKey);
|
||||
payload.point[yScaleKey] = src.posToVal(y, yScaleKey);
|
||||
payload.point.panelRelY = y > 0 ? y / h : 1; // used by old graph panel to position tooltip
|
||||
eventBus.publish(hoverEvent);
|
||||
hoverEvent.payload.down = undefined;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
scales: [xScaleKey, null],
|
||||
// match: [() => true, () => false],
|
||||
};
|
||||
|
||||
@@ -43,12 +43,11 @@ export class TimelineChart extends React.Component<TimelineProps> {
|
||||
|
||||
prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
|
||||
this.panelContext = this.context;
|
||||
const { eventBus, sync } = this.panelContext;
|
||||
const { sync } = this.panelContext;
|
||||
|
||||
return preparePlotConfigBuilder({
|
||||
frame: alignedFrame,
|
||||
getTimeRange,
|
||||
eventBus,
|
||||
sync,
|
||||
allFrames: this.props.frames,
|
||||
...this.props,
|
||||
|
||||
@@ -4,9 +4,6 @@ import uPlot from 'uplot';
|
||||
import {
|
||||
DataFrame,
|
||||
DashboardCursorSync,
|
||||
DataHoverPayload,
|
||||
DataHoverEvent,
|
||||
DataHoverClearEvent,
|
||||
FALLBACK_COLOR,
|
||||
Field,
|
||||
FieldColorModeId,
|
||||
@@ -99,7 +96,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<UPlotConfigOptions> = (
|
||||
timeZones,
|
||||
getTimeRange,
|
||||
mode,
|
||||
eventBus,
|
||||
sync,
|
||||
rowHeight,
|
||||
colWidth,
|
||||
@@ -112,7 +108,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<UPlotConfigOptions> = (
|
||||
}) => {
|
||||
const builder = new UPlotConfigBuilder(timeZones[0]);
|
||||
|
||||
const xScaleUnit = 'time';
|
||||
const xScaleKey = 'x';
|
||||
|
||||
const isDiscrete = (field: Field) => {
|
||||
@@ -177,16 +172,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<UPlotConfigOptions> = (
|
||||
let hoveredDataIdx: number | null = null;
|
||||
|
||||
const coreConfig = getConfig(opts);
|
||||
const payload: DataHoverPayload = {
|
||||
point: {
|
||||
[xScaleUnit]: null,
|
||||
[FIXED_UNIT]: null,
|
||||
},
|
||||
data: frame,
|
||||
};
|
||||
|
||||
const hoverEvent = new DataHoverEvent(payload).setTags(['uplot']);
|
||||
const clearEvent = new DataHoverClearEvent().setTags(['uplot']);
|
||||
|
||||
builder.addHook('init', coreConfig.init);
|
||||
builder.addHook('drawClear', coreConfig.drawClear);
|
||||
@@ -294,23 +279,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<UPlotConfigOptions> = (
|
||||
|
||||
cursor.sync = {
|
||||
key: eventsScope,
|
||||
filters: {
|
||||
pub: (type: string, src: uPlot, x: number, y: number, w: number, h: number, dataIdx: number) => {
|
||||
if (sync && sync() === DashboardCursorSync.Off) {
|
||||
return false;
|
||||
}
|
||||
payload.rowIndex = dataIdx;
|
||||
if (x < 0 && y < 0) {
|
||||
eventBus.publish(clearEvent);
|
||||
} else {
|
||||
payload.point[xScaleUnit] = src.posToVal(x, xScaleKey);
|
||||
payload.point.panelRelY = y > 0 ? y / h : 1; // used for old graph panel to position tooltip
|
||||
payload.down = undefined;
|
||||
eventBus.publish(hoverEvent);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
scales: [xScaleKey, null],
|
||||
};
|
||||
builder.setSync();
|
||||
|
||||
@@ -71,7 +71,7 @@ interface Props extends PanelProps<Options> {}
|
||||
|
||||
export const BarChartPanel = ({ data, options, fieldConfig, width, height, timeZone, id, replaceVariables }: Props) => {
|
||||
const theme = useTheme2();
|
||||
const { eventBus, dataLinkPostProcessor } = usePanelContext();
|
||||
const { dataLinkPostProcessor } = usePanelContext();
|
||||
|
||||
const oldConfig = useRef<UPlotConfigBuilder | undefined>(undefined);
|
||||
const isToolTipOpen = useRef<boolean>(false);
|
||||
@@ -288,7 +288,6 @@ export const BarChartPanel = ({ data, options, fieldConfig, width, height, timeZ
|
||||
timeZone,
|
||||
theme,
|
||||
timeZones: [timeZone],
|
||||
eventBus,
|
||||
orientation,
|
||||
barWidth,
|
||||
barRadius,
|
||||
|
||||
@@ -3,7 +3,6 @@ import { assertIsDefined } from 'test/helpers/asserts';
|
||||
import {
|
||||
createTheme,
|
||||
DefaultTimeZone,
|
||||
EventBusSrv,
|
||||
FieldConfig,
|
||||
FieldType,
|
||||
getDefaultTimeRange,
|
||||
@@ -120,7 +119,6 @@ describe('BarChart utils', () => {
|
||||
theme: createTheme(),
|
||||
timeZones: [DefaultTimeZone],
|
||||
getTimeRange: getDefaultTimeRange,
|
||||
eventBus: new EventBusSrv(),
|
||||
allFrames: [frame],
|
||||
}).getConfig();
|
||||
expect(result).toMatchSnapshot();
|
||||
@@ -135,7 +133,6 @@ describe('BarChart utils', () => {
|
||||
theme: createTheme(),
|
||||
timeZones: [DefaultTimeZone],
|
||||
getTimeRange: getDefaultTimeRange,
|
||||
eventBus: new EventBusSrv(),
|
||||
allFrames: [frame],
|
||||
}).getConfig()
|
||||
).toMatchSnapshot();
|
||||
@@ -150,7 +147,6 @@ describe('BarChart utils', () => {
|
||||
theme: createTheme(),
|
||||
timeZones: [DefaultTimeZone],
|
||||
getTimeRange: getDefaultTimeRange,
|
||||
eventBus: new EventBusSrv(),
|
||||
allFrames: [frame],
|
||||
}).getConfig()
|
||||
).toMatchSnapshot();
|
||||
|
||||
@@ -4,10 +4,19 @@
|
||||
import React, { useMemo, useState, useCallback } from 'react';
|
||||
import uPlot from 'uplot';
|
||||
|
||||
import { Field, getDisplayProcessor, getLinksSupplier, PanelProps } from '@grafana/data';
|
||||
import { Field, getDisplayProcessor, PanelProps } from '@grafana/data';
|
||||
import { PanelDataErrorView } from '@grafana/runtime';
|
||||
import { DashboardCursorSync, TooltipDisplayMode } from '@grafana/schema';
|
||||
import { TooltipPlugin, TooltipPlugin2, UPlotConfigBuilder, usePanelContext, useTheme2, ZoomPlugin } from '@grafana/ui';
|
||||
import {
|
||||
EventBusPlugin,
|
||||
KeyboardPlugin,
|
||||
TooltipPlugin,
|
||||
TooltipPlugin2,
|
||||
UPlotConfigBuilder,
|
||||
usePanelContext,
|
||||
useTheme2,
|
||||
ZoomPlugin,
|
||||
} from '@grafana/ui';
|
||||
import { AxisProps } from '@grafana/ui/src/components/uPlot/config/UPlotAxisBuilder';
|
||||
import { ScaleProps } from '@grafana/ui/src/components/uPlot/config/UPlotScaleBuilder';
|
||||
import { TimeRange2, TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2';
|
||||
@@ -42,8 +51,15 @@ export const CandlestickPanel = ({
|
||||
onChangeTimeRange,
|
||||
replaceVariables,
|
||||
}: CandlestickPanelProps) => {
|
||||
const { sync, canAddAnnotations, onThresholdsChange, canEditThresholds, showThresholds, dataLinkPostProcessor } =
|
||||
usePanelContext();
|
||||
const {
|
||||
sync,
|
||||
canAddAnnotations,
|
||||
onThresholdsChange,
|
||||
canEditThresholds,
|
||||
showThresholds,
|
||||
dataLinkPostProcessor,
|
||||
eventBus,
|
||||
} = usePanelContext();
|
||||
|
||||
const theme = useTheme2();
|
||||
|
||||
@@ -54,6 +70,12 @@ export const CandlestickPanel = ({
|
||||
[]
|
||||
);
|
||||
|
||||
const syncAny = useCallback(
|
||||
() => sync?.() !== DashboardCursorSync.Off,
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
);
|
||||
|
||||
const info = useMemo(() => {
|
||||
return prepareCandlestickFields(data.series, options, theme, timeRange);
|
||||
}, [data.series, options, theme, timeRange]);
|
||||
@@ -260,19 +282,11 @@ export const CandlestickPanel = ({
|
||||
replaceVariables={replaceVariables}
|
||||
dataLinkPostProcessor={dataLinkPostProcessor}
|
||||
>
|
||||
{(uplotConfig, alignedDataFrame) => {
|
||||
alignedDataFrame.fields.forEach((field) => {
|
||||
field.getLinks = getLinksSupplier(
|
||||
alignedDataFrame,
|
||||
field,
|
||||
field.state!.scopedVars!,
|
||||
replaceVariables,
|
||||
timeZone
|
||||
);
|
||||
});
|
||||
|
||||
{(uplotConfig, alignedFrame) => {
|
||||
return (
|
||||
<>
|
||||
<KeyboardPlugin config={uplotConfig} />
|
||||
<EventBusPlugin config={uplotConfig} sync={syncAny} eventBus={eventBus} frame={alignedFrame} />
|
||||
{showNewVizTooltips ? (
|
||||
<TooltipPlugin2
|
||||
config={uplotConfig}
|
||||
@@ -299,7 +313,7 @@ export const CandlestickPanel = ({
|
||||
return (
|
||||
<TimeSeriesTooltip
|
||||
frames={[info.frame]}
|
||||
seriesFrame={alignedDataFrame}
|
||||
seriesFrame={alignedFrame}
|
||||
dataIdxs={dataIdxs}
|
||||
seriesIdx={seriesIdx}
|
||||
mode={viaSync ? TooltipDisplayMode.Multi : options.tooltip.mode}
|
||||
@@ -317,7 +331,7 @@ export const CandlestickPanel = ({
|
||||
<>
|
||||
<ZoomPlugin config={uplotConfig} onZoom={onChangeTimeRange} withZoomY={true} />
|
||||
<TooltipPlugin
|
||||
data={alignedDataFrame}
|
||||
data={alignedFrame}
|
||||
config={uplotConfig}
|
||||
mode={TooltipDisplayMode.Multi}
|
||||
sync={sync}
|
||||
@@ -342,11 +356,11 @@ export const CandlestickPanel = ({
|
||||
{/* Enables annotations creation*/}
|
||||
{!showNewVizTooltips ? (
|
||||
enableAnnotationCreation ? (
|
||||
<AnnotationEditorPlugin data={alignedDataFrame} timeZone={timeZone} config={uplotConfig}>
|
||||
<AnnotationEditorPlugin data={alignedFrame} timeZone={timeZone} config={uplotConfig}>
|
||||
{({ startAnnotating }) => {
|
||||
return (
|
||||
<ContextMenuPlugin
|
||||
data={alignedDataFrame}
|
||||
data={alignedFrame}
|
||||
config={uplotConfig}
|
||||
timeZone={timeZone}
|
||||
replaceVariables={replaceVariables}
|
||||
@@ -377,7 +391,7 @@ export const CandlestickPanel = ({
|
||||
</AnnotationEditorPlugin>
|
||||
) : (
|
||||
<ContextMenuPlugin
|
||||
data={alignedDataFrame}
|
||||
data={alignedFrame}
|
||||
config={uplotConfig}
|
||||
timeZone={timeZone}
|
||||
replaceVariables={replaceVariables}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
useTheme2,
|
||||
VizLayout,
|
||||
VizTooltipContainer,
|
||||
EventBusPlugin,
|
||||
} from '@grafana/ui';
|
||||
import { TimeRange2, TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2';
|
||||
import { ColorScale } from 'app/core/components/ColorScale/ColorScale';
|
||||
@@ -57,6 +58,12 @@ export const HeatmapPanel = ({
|
||||
[]
|
||||
);
|
||||
|
||||
const syncAny = useCallback(
|
||||
() => sync?.() !== DashboardCursorSync.Off,
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
);
|
||||
|
||||
// temp range set for adding new annotation set by TooltipPlugin2, consumed by AnnotationPlugin2
|
||||
const [newAnnotationRange, setNewAnnotationRange] = useState<TimeRange2 | null>(null);
|
||||
|
||||
@@ -140,7 +147,6 @@ export const HeatmapPanel = ({
|
||||
return prepConfig({
|
||||
dataRef,
|
||||
theme,
|
||||
eventBus,
|
||||
onhover: !showNewVizTooltips ? onhover : null,
|
||||
onclick: !showNewVizTooltips && options.tooltip.mode !== TooltipDisplayMode.None ? onclick : null,
|
||||
isToolTipOpen,
|
||||
@@ -207,6 +213,7 @@ export const HeatmapPanel = ({
|
||||
<VizLayout width={width} height={height} legend={renderLegend()}>
|
||||
{(vizWidth: number, vizHeight: number) => (
|
||||
<UPlotChart config={builder} data={facets as any} width={vizWidth} height={vizHeight}>
|
||||
<EventBusPlugin config={builder} sync={syncAny} eventBus={eventBus} frame={info.series ?? info.heatmap} />
|
||||
{!showNewVizTooltips && <ZoomPlugin config={builder} onZoom={onChangeTimeRange} />}
|
||||
{showNewVizTooltips && (
|
||||
<>
|
||||
|
||||
@@ -4,10 +4,6 @@ import uPlot, { Cursor } from 'uplot';
|
||||
import {
|
||||
DashboardCursorSync,
|
||||
DataFrameType,
|
||||
DataHoverClearEvent,
|
||||
DataHoverEvent,
|
||||
DataHoverPayload,
|
||||
EventBus,
|
||||
formattedValueToString,
|
||||
getValueFormat,
|
||||
GrafanaTheme2,
|
||||
@@ -60,7 +56,6 @@ export interface HeatmapZoomEvent {
|
||||
interface PrepConfigOpts {
|
||||
dataRef: RefObject<HeatmapData>;
|
||||
theme: GrafanaTheme2;
|
||||
eventBus: EventBus;
|
||||
onhover?: null | ((evt?: HeatmapHoverEvent | null) => void);
|
||||
onclick?: null | ((evt?: Object) => void);
|
||||
onzoom?: null | ((evt: HeatmapZoomEvent) => void);
|
||||
@@ -82,7 +77,6 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
const {
|
||||
dataRef,
|
||||
theme,
|
||||
eventBus,
|
||||
onhover,
|
||||
onclick,
|
||||
isToolTipOpen,
|
||||
@@ -98,11 +92,9 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
} = opts;
|
||||
|
||||
const xScaleKey = 'x';
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -166,16 +158,6 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
rect = r;
|
||||
});
|
||||
|
||||
const payload: DataHoverPayload = {
|
||||
point: {
|
||||
[xScaleUnit]: null,
|
||||
},
|
||||
data: dataRef.current?.heatmap,
|
||||
};
|
||||
|
||||
const hoverEvent = new DataHoverEvent(payload).setTags(['uplot']);
|
||||
const clearEvent = new DataHoverClearEvent().setTags(['uplot']);
|
||||
|
||||
let pendingOnleave: ReturnType<typeof setTimeout> | 0;
|
||||
|
||||
onhover &&
|
||||
@@ -185,9 +167,6 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
const sel = u.cursor.idxs[i];
|
||||
if (sel != null) {
|
||||
const { left, top } = u.cursor;
|
||||
payload.rowIndex = sel;
|
||||
payload.point[xScaleUnit] = u.posToVal(left!, xScaleKey);
|
||||
eventBus.publish(hoverEvent);
|
||||
|
||||
if (!isToolTipOpen?.current) {
|
||||
if (pendingOnleave) {
|
||||
@@ -211,7 +190,6 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
if (!pendingOnleave) {
|
||||
pendingOnleave = setTimeout(() => {
|
||||
onhover(null);
|
||||
eventBus.publish(clearEvent);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
@@ -609,19 +587,6 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
cursor.sync = {
|
||||
key: eventsScope,
|
||||
scales: [xScaleKey, null],
|
||||
filters: {
|
||||
pub: (type: string, src: uPlot, x: number, y: number, w: number, h: number, dataIdx: number) => {
|
||||
if (x < 0) {
|
||||
payload.point[xScaleUnit] = null;
|
||||
eventBus.publish(new DataHoverClearEvent());
|
||||
} else {
|
||||
payload.point[xScaleUnit] = src.posToVal(x, xScaleKey);
|
||||
eventBus.publish(hoverEvent);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
builder.setSync();
|
||||
|
||||
@@ -4,6 +4,7 @@ import { CartesianCoords2D, DashboardCursorSync, DataFrame, FieldType, PanelProp
|
||||
import { getLastStreamingDataFramePacket } from '@grafana/data/src/dataframe/StreamingDataFrame';
|
||||
import { config } from '@grafana/runtime';
|
||||
import {
|
||||
EventBusPlugin,
|
||||
Portal,
|
||||
TooltipDisplayMode,
|
||||
TooltipPlugin2,
|
||||
@@ -59,6 +60,12 @@ export const StateTimelinePanel = ({
|
||||
[]
|
||||
);
|
||||
|
||||
const syncAny = useCallback(
|
||||
() => sync?.() !== DashboardCursorSync.Off,
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
);
|
||||
|
||||
const oldConfig = useRef<UPlotConfigBuilder | undefined>(undefined);
|
||||
const isToolTipOpen = useRef<boolean>(false);
|
||||
|
||||
@@ -70,7 +77,7 @@ export const StateTimelinePanel = ({
|
||||
const [shouldDisplayCloseButton, setShouldDisplayCloseButton] = useState<boolean>(false);
|
||||
// temp range set for adding new annotation set by TooltipPlugin2, consumed by AnnotationPlugin2
|
||||
const [newAnnotationRange, setNewAnnotationRange] = useState<TimeRange2 | null>(null);
|
||||
const { sync, canAddAnnotations, dataLinkPostProcessor } = usePanelContext();
|
||||
const { sync, canAddAnnotations, dataLinkPostProcessor, eventBus } = usePanelContext();
|
||||
|
||||
const onCloseToolTip = () => {
|
||||
isToolTipOpen.current = false;
|
||||
@@ -205,6 +212,7 @@ export const StateTimelinePanel = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<EventBusPlugin config={builder} sync={syncAny} eventBus={eventBus} frame={alignedFrame} />
|
||||
{showNewVizTooltips ? (
|
||||
<>
|
||||
{options.tooltip.mode !== TooltipDisplayMode.None && (
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { CartesianCoords2D, DashboardCursorSync, DataFrame, FieldType, PanelProps } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import {
|
||||
EventBusPlugin,
|
||||
Portal,
|
||||
TooltipDisplayMode,
|
||||
TooltipPlugin2,
|
||||
@@ -57,6 +58,12 @@ export const StatusHistoryPanel = ({
|
||||
[]
|
||||
);
|
||||
|
||||
const syncAny = useCallback(
|
||||
() => sync?.() !== DashboardCursorSync.Off,
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
);
|
||||
|
||||
const oldConfig = useRef<UPlotConfigBuilder | undefined>(undefined);
|
||||
const isToolTipOpen = useRef<boolean>(false);
|
||||
|
||||
@@ -68,7 +75,7 @@ export const StatusHistoryPanel = ({
|
||||
const [shouldDisplayCloseButton, setShouldDisplayCloseButton] = useState<boolean>(false);
|
||||
// temp range set for adding new annotation set by TooltipPlugin2, consumed by AnnotationPlugin2
|
||||
const [newAnnotationRange, setNewAnnotationRange] = useState<TimeRange2 | null>(null);
|
||||
const { sync, canAddAnnotations, dataLinkPostProcessor } = usePanelContext();
|
||||
const { sync, canAddAnnotations, dataLinkPostProcessor, eventBus } = usePanelContext();
|
||||
|
||||
const enableAnnotationCreation = Boolean(canAddAnnotations && canAddAnnotations());
|
||||
|
||||
@@ -234,6 +241,7 @@ export const StatusHistoryPanel = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<EventBusPlugin config={builder} sync={syncAny} eventBus={eventBus} frame={alignedFrame} />
|
||||
{showNewVizTooltips ? (
|
||||
<>
|
||||
{options.tooltip.mode !== TooltipDisplayMode.None && (
|
||||
|
||||
@@ -3,7 +3,14 @@ import React, { useMemo, useState, useCallback } from 'react';
|
||||
import { PanelProps, DataFrameType, DashboardCursorSync } from '@grafana/data';
|
||||
import { PanelDataErrorView } from '@grafana/runtime';
|
||||
import { TooltipDisplayMode, VizOrientation } from '@grafana/schema';
|
||||
import { KeyboardPlugin, TooltipPlugin, TooltipPlugin2, usePanelContext, ZoomPlugin } from '@grafana/ui';
|
||||
import {
|
||||
EventBusPlugin,
|
||||
KeyboardPlugin,
|
||||
TooltipPlugin,
|
||||
TooltipPlugin2,
|
||||
usePanelContext,
|
||||
ZoomPlugin,
|
||||
} from '@grafana/ui';
|
||||
import { TimeRange2, TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2';
|
||||
import { TimeSeries } from 'app/core/components/TimeSeries/TimeSeries';
|
||||
import { config } from 'app/core/config';
|
||||
@@ -34,8 +41,15 @@ export const TimeSeriesPanel = ({
|
||||
replaceVariables,
|
||||
id,
|
||||
}: TimeSeriesPanelProps) => {
|
||||
const { sync, canAddAnnotations, onThresholdsChange, canEditThresholds, showThresholds, dataLinkPostProcessor } =
|
||||
usePanelContext();
|
||||
const {
|
||||
sync,
|
||||
canAddAnnotations,
|
||||
onThresholdsChange,
|
||||
canEditThresholds,
|
||||
showThresholds,
|
||||
dataLinkPostProcessor,
|
||||
eventBus,
|
||||
} = usePanelContext();
|
||||
// Vertical orientation is not available for users through config.
|
||||
// It is simplified version of horizontal time series panel and it does not support all plugins.
|
||||
const isVerticallyOriented = options.orientation === VizOrientation.Vertical;
|
||||
@@ -64,6 +78,12 @@ export const TimeSeriesPanel = ({
|
||||
[]
|
||||
);
|
||||
|
||||
const syncAny = useCallback(
|
||||
() => sync?.() !== DashboardCursorSync.Off,
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
);
|
||||
|
||||
if (!frames || suggestions) {
|
||||
return (
|
||||
<PanelDataErrorView
|
||||
@@ -99,10 +119,11 @@ export const TimeSeriesPanel = ({
|
||||
replaceVariables={replaceVariables}
|
||||
dataLinkPostProcessor={dataLinkPostProcessor}
|
||||
>
|
||||
{(uplotConfig, alignedDataFrame) => {
|
||||
{(uplotConfig, alignedFrame) => {
|
||||
return (
|
||||
<>
|
||||
<KeyboardPlugin config={uplotConfig} />
|
||||
<EventBusPlugin config={uplotConfig} sync={syncAny} eventBus={eventBus} frame={alignedFrame} />
|
||||
{options.tooltip.mode === TooltipDisplayMode.None || (
|
||||
<>
|
||||
{showNewVizTooltips ? (
|
||||
@@ -132,7 +153,7 @@ export const TimeSeriesPanel = ({
|
||||
// not sure it header time here works for annotations, since it's taken from nearest datapoint index
|
||||
<TimeSeriesTooltip
|
||||
frames={frames}
|
||||
seriesFrame={alignedDataFrame}
|
||||
seriesFrame={alignedFrame}
|
||||
dataIdxs={dataIdxs}
|
||||
seriesIdx={seriesIdx}
|
||||
mode={viaSync ? TooltipDisplayMode.Multi : options.tooltip.mode}
|
||||
@@ -151,7 +172,7 @@ export const TimeSeriesPanel = ({
|
||||
<ZoomPlugin config={uplotConfig} onZoom={onChangeTimeRange} withZoomY={true} />
|
||||
<TooltipPlugin
|
||||
frames={frames}
|
||||
data={alignedDataFrame}
|
||||
data={alignedFrame}
|
||||
config={uplotConfig}
|
||||
mode={options.tooltip.mode}
|
||||
sortOrder={options.tooltip.sort}
|
||||
@@ -181,11 +202,11 @@ export const TimeSeriesPanel = ({
|
||||
{/*Enables annotations creation*/}
|
||||
{!showNewVizTooltips ? (
|
||||
enableAnnotationCreation && !isVerticallyOriented ? (
|
||||
<AnnotationEditorPlugin data={alignedDataFrame} timeZone={timeZone} config={uplotConfig}>
|
||||
<AnnotationEditorPlugin data={alignedFrame} timeZone={timeZone} config={uplotConfig}>
|
||||
{({ startAnnotating }) => {
|
||||
return (
|
||||
<ContextMenuPlugin
|
||||
data={alignedDataFrame}
|
||||
data={alignedFrame}
|
||||
config={uplotConfig}
|
||||
timeZone={timeZone}
|
||||
replaceVariables={replaceVariables}
|
||||
@@ -212,7 +233,7 @@ export const TimeSeriesPanel = ({
|
||||
</AnnotationEditorPlugin>
|
||||
) : (
|
||||
<ContextMenuPlugin
|
||||
data={alignedDataFrame}
|
||||
data={alignedFrame}
|
||||
frames={frames}
|
||||
config={uplotConfig}
|
||||
timeZone={timeZone}
|
||||
|
||||
Reference in New Issue
Block a user