From f8d75726e706315937a383eae3e6ed03905abec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Bedi?= Date: Wed, 3 Nov 2021 11:49:37 +0100 Subject: [PATCH] Graph panel: listen to events from timeseries panel (#41033) * TimeSeries: share cursor with old graph * Typo fix * Fix typecheck errors * Revert "TimeSeries: share cursor with old graph" This reverts commit 1e7dd4f6270612ceb391f8ae9687ad4b64a5ac7e. * Graph: subscribe to DataHoverEvent * Revert "Fix typecheck errors" This reverts commit 737c8ea8c1f972fd806061842b2985b8dac96214. --- .../src/components/TimeSeries/utils.ts | 1 + .../grafana-ui/src/components/uPlot/utils.ts | 4 +-- public/app/plugins/panel/graph/graph.ts | 25 ++++++++++++++++--- public/app/plugins/panel/graph/utils.ts | 14 ++++++++++- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/packages/grafana-ui/src/components/TimeSeries/utils.ts b/packages/grafana-ui/src/components/TimeSeries/utils.ts index 666402e2a9f..8ccea19c698 100644 --- a/packages/grafana-ui/src/components/TimeSeries/utils.ts +++ b/packages/grafana-ui/src/components/TimeSeries/utils.ts @@ -355,6 +355,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor // 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; } diff --git a/packages/grafana-ui/src/components/uPlot/utils.ts b/packages/grafana-ui/src/components/uPlot/utils.ts index 58f8ae37517..3d7c20ce740 100755 --- a/packages/grafana-ui/src/components/uPlot/utils.ts +++ b/packages/grafana-ui/src/components/uPlot/utils.ts @@ -134,7 +134,7 @@ export function collectStackingGroups(f: Field, groups: Map, s } /** - * Finds y axis midpoind for point at given idx (css pixels relative to uPlot canvas) + * Finds y axis midpoint for point at given idx (css pixels relative to uPlot canvas) * @internal **/ @@ -177,7 +177,7 @@ export function findMidPointYPosition(u: uPlot, idx: number) { // find median position y = (u.valToPos(min, u.series[sMinIdx].scale!) + u.valToPos(max, u.series[sMaxIdx].scale!)) / 2; } else { - // snap tooltip to min OR max point, one of thos is not null :) + // snap tooltip to min OR max point, one of those is not null :) y = u.valToPos((min || max)!, u.series[(sMaxIdx || sMinIdx)!].scale!); } diff --git a/public/app/plugins/panel/graph/graph.ts b/public/app/plugins/panel/graph/graph.ts index bd1897557dc..7c6cd2e76d0 100644 --- a/public/app/plugins/panel/graph/graph.ts +++ b/public/app/plugins/panel/graph/graph.ts @@ -29,6 +29,9 @@ import { provideTheme } from 'app/core/utils/ConfigProvider'; import { DataFrame, DataFrameView, + DataHoverClearEvent, + DataHoverEvent, + DataHoverPayload, FieldDisplay, FieldType, formattedValueToString, @@ -40,6 +43,7 @@ import { LegacyEventHandler, LegacyGraphHoverClearEvent, LegacyGraphHoverEvent, + LegacyGraphHoverEventPayload, LinkModelSupplier, PanelEvents, toUtc, @@ -49,6 +53,7 @@ import { TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { ContextSrv } from 'app/core/services/context_srv'; import { getFieldLinksSupplier } from 'app/angular/panel/panellinks/linkSuppliers'; import { DashboardModel } from '../../../features/dashboard/state'; +import { isLegacyGraphHoverEvent } from './utils'; const LegendWithThemeProvider = provideTheme(Legend); @@ -99,6 +104,9 @@ class GraphElement { this.ctrl.dashboard.events.on(LegacyGraphHoverEvent.type, this.onGraphHover.bind(this), this.scope); this.ctrl.dashboard.events.on(LegacyGraphHoverClearEvent.type, this.onGraphHoverClear.bind(this), this.scope); + this.ctrl.dashboard.events.on(DataHoverEvent.type, this.onGraphHover.bind(this), this.scope); + this.ctrl.dashboard.events.on(DataHoverClearEvent.type, this.onGraphHoverClear.bind(this), this.scope); + // plot events this.elem.bind('plotselected', this.onPlotSelected.bind(this)); this.elem.bind('plotclick', this.onPlotClick.bind(this)); @@ -147,18 +155,27 @@ class GraphElement { ReactDOM.render(legendReactElem, this.legendElem, () => this.renderPanel()); } - onGraphHover(evt: any) { + onGraphHover(evt: LegacyGraphHoverEventPayload | DataHoverPayload) { // ignore other graph hover events if shared tooltip is disabled if (!this.dashboard.sharedTooltipModeEnabled()) { return; } - // ignore if we are the emitter - if (!this.plot || evt.panel.id === this.panel.id || this.ctrl.otherPanelInFullscreenMode()) { + if (isLegacyGraphHoverEvent(evt)) { + // ignore if we are the emitter + if (!this.plot || evt.panel?.id === this.panel.id || this.ctrl.otherPanelInFullscreenMode()) { + return; + } + + this.tooltip.show(evt.pos); + } + + // DataHoverEvent can come from multiple panels that doesn't include x position + if (!evt.point?.time) { return; } - this.tooltip.show(evt.pos); + this.tooltip.show({ x: evt.point.time, panelRelY: evt.point.panelRelY ?? 1 }); } onPanelTeardown() { diff --git a/public/app/plugins/panel/graph/utils.ts b/public/app/plugins/panel/graph/utils.ts index 4464fbcf650..12b17f6f85a 100644 --- a/public/app/plugins/panel/graph/utils.ts +++ b/public/app/plugins/panel/graph/utils.ts @@ -1,4 +1,11 @@ -import { DataFrame, ReducerID, reduceField, AbsoluteTimeRange, FieldType } from '@grafana/data'; +import { + AbsoluteTimeRange, + DataFrame, + FieldType, + LegacyGraphHoverEventPayload, + reduceField, + ReducerID, +} from '@grafana/data'; /** * Find the min and max time that covers all data @@ -22,3 +29,8 @@ export function getDataTimeRange(frames: DataFrame[]): AbsoluteTimeRange | undef } return found ? range : undefined; } + +// Check wether event is LegacyGraphHoverEvent +export function isLegacyGraphHoverEvent(event: any): event is LegacyGraphHoverEventPayload { + return event.hasOwnProperty('pos'); +}