mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
StateTimeline: Share cursor with rest of the panels (#41038)
* First working version of shared cursor for state timeline * Only publish x value for time series * Don't send legacy graph event * Don't add y scale to cursor sync * Snap cursor to the bottom of the canvas when sync is out of bounds * Fix snapshot
This commit is contained in:
parent
d69ffe0e44
commit
af61839a26
@ -95,7 +95,7 @@ Object {
|
||||
],
|
||||
"scales": Array [
|
||||
"x",
|
||||
"__fixed",
|
||||
null,
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -363,7 +363,8 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
|
||||
},
|
||||
},
|
||||
// ??? setSeries: syncMode === DashboardCursorSync.Tooltip,
|
||||
scales: builder.scaleKeys,
|
||||
//TODO: remove any once https://github.com/leeoniya/uPlot/pull/611 got merged or the typing is fixed
|
||||
scales: [xScaleKey, null as any],
|
||||
match: [() => true, () => true],
|
||||
};
|
||||
}
|
||||
|
@ -181,6 +181,11 @@ export function findMidPointYPosition(u: uPlot, idx: number) {
|
||||
y = u.valToPos((min || max)!, u.series[(sMaxIdx || sMinIdx)!].scale!);
|
||||
}
|
||||
|
||||
// if y is out of canvas bounds, snap it to the bottom
|
||||
if (y !== undefined && y < 0) {
|
||||
y = u.bbox.height / devicePixelRatio;
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { DataFrame, PanelProps } from '@grafana/data';
|
||||
import { TooltipPlugin, useTheme2, ZoomPlugin } from '@grafana/ui';
|
||||
import { TooltipPlugin, useTheme2, ZoomPlugin, usePanelContext } from '@grafana/ui';
|
||||
import { TimelineMode, TimelineOptions } from './types';
|
||||
import { TimelineChart } from './TimelineChart';
|
||||
import { prepareTimelineFields, prepareTimelineLegendItems } from './utils';
|
||||
@ -22,6 +22,7 @@ export const StateTimelinePanel: React.FC<TimelinePanelProps> = ({
|
||||
onChangeTimeRange,
|
||||
}) => {
|
||||
const theme = useTheme2();
|
||||
const { sync } = usePanelContext();
|
||||
|
||||
const { frames, warn } = useMemo(() => prepareTimelineFields(data?.series, options.mergeValues ?? true, theme), [
|
||||
data,
|
||||
@ -103,6 +104,7 @@ export const StateTimelinePanel: React.FC<TimelinePanelProps> = ({
|
||||
<ZoomPlugin config={config} onZoom={onChangeTimeRange} />
|
||||
<TooltipPlugin
|
||||
data={alignedFrame}
|
||||
sync={sync}
|
||||
config={config}
|
||||
mode={options.tooltip.mode}
|
||||
timeZone={timeZone}
|
||||
|
@ -36,12 +36,13 @@ export class TimelineChart extends React.Component<TimelineProps> {
|
||||
|
||||
prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
|
||||
this.panelContext = this.context as PanelContext;
|
||||
const { eventBus } = this.panelContext;
|
||||
const { eventBus, sync } = this.panelContext;
|
||||
|
||||
return preparePlotConfigBuilder({
|
||||
frame: alignedFrame,
|
||||
getTimeRange,
|
||||
eventBus,
|
||||
sync,
|
||||
allFrames: this.props.frames,
|
||||
...this.props,
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { OptionsWithTooltip, OptionsWithLegend, HideableFieldConfig, VisibilityMode } from '@grafana/schema';
|
||||
import { DashboardCursorSync } from '@grafana/data';
|
||||
import { HideableFieldConfig, OptionsWithLegend, OptionsWithTooltip, VisibilityMode } from '@grafana/schema';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
@ -15,6 +16,8 @@ export interface TimelineOptions extends OptionsWithLegend, OptionsWithTooltip {
|
||||
mergeValues?: boolean;
|
||||
// only used in "changes" mode (state-timeline)
|
||||
alignValue?: TimelineValueAlignment;
|
||||
|
||||
sync?: DashboardCursorSync;
|
||||
}
|
||||
|
||||
export type TimelineValueAlignment = 'center' | 'left' | 'right';
|
||||
|
@ -3,6 +3,10 @@ import { XYFieldMatchers } from '@grafana/ui/src/components/GraphNG/types';
|
||||
import {
|
||||
ArrayVector,
|
||||
DataFrame,
|
||||
DashboardCursorSync,
|
||||
DataHoverPayload,
|
||||
DataHoverEvent,
|
||||
DataHoverClearEvent,
|
||||
FALLBACK_COLOR,
|
||||
Field,
|
||||
FieldColorModeId,
|
||||
@ -58,6 +62,8 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({
|
||||
timeZone,
|
||||
getTimeRange,
|
||||
mode,
|
||||
eventBus,
|
||||
sync,
|
||||
rowHeight,
|
||||
colWidth,
|
||||
showValue,
|
||||
@ -65,6 +71,9 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({
|
||||
}) => {
|
||||
const builder = new UPlotConfigBuilder(timeZone);
|
||||
|
||||
const xScaleUnit = 'time';
|
||||
const xScaleKey = 'x';
|
||||
|
||||
const isDiscrete = (field: Field) => {
|
||||
const mode = field.config?.color?.mode;
|
||||
return !(mode && field.display && mode.startsWith('continuous-'));
|
||||
@ -116,6 +125,13 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({
|
||||
let hoveredDataIdx: number | null = null;
|
||||
|
||||
const coreConfig = getConfig(opts);
|
||||
const payload: DataHoverPayload = {
|
||||
point: {
|
||||
[xScaleUnit]: null,
|
||||
[FIXED_UNIT]: null,
|
||||
},
|
||||
data: frame,
|
||||
};
|
||||
|
||||
builder.addHook('init', coreConfig.init);
|
||||
builder.addHook('drawClear', coreConfig.drawClear);
|
||||
@ -148,7 +164,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({
|
||||
builder.setCursor(coreConfig.cursor);
|
||||
|
||||
builder.addScale({
|
||||
scaleKey: 'x',
|
||||
scaleKey: xScaleKey,
|
||||
isTime: true,
|
||||
orientation: ScaleOrientation.Horizontal,
|
||||
direction: ScaleDirection.Right,
|
||||
@ -164,7 +180,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({
|
||||
});
|
||||
|
||||
builder.addAxis({
|
||||
scaleKey: 'x',
|
||||
scaleKey: xScaleKey,
|
||||
isTime: true,
|
||||
splits: coreConfig.xSplits!,
|
||||
placement: AxisPlacement.Bottom,
|
||||
@ -219,6 +235,34 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({
|
||||
});
|
||||
}
|
||||
|
||||
if (sync !== DashboardCursorSync.Off) {
|
||||
let cursor: Partial<uPlot.Cursor> = {};
|
||||
|
||||
cursor.sync = {
|
||||
key: '__global_',
|
||||
filters: {
|
||||
pub: (type: string, src: uPlot, x: number, y: number, w: number, h: number, dataIdx: number) => {
|
||||
payload.rowIndex = dataIdx;
|
||||
if (x < 0 && y < 0) {
|
||||
payload.point[xScaleUnit] = null;
|
||||
payload.point[FIXED_UNIT] = null;
|
||||
eventBus.publish(new DataHoverClearEvent());
|
||||
} 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(new DataHoverEvent(payload));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
//TODO: remove any once https://github.com/leeoniya/uPlot/pull/611 got merged or the typing is fixed
|
||||
scales: [xScaleKey, null as any],
|
||||
};
|
||||
builder.setSync();
|
||||
builder.setCursor(cursor);
|
||||
}
|
||||
|
||||
return builder;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user