diff --git a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx index fd691d5b84f..1a072900c35 100644 --- a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx +++ b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx @@ -19,6 +19,7 @@ import { AxisProps } from '@grafana/ui/src/components/uPlot/config/UPlotAxisBuil import { prepareCandlestickFields } from './fields'; import uPlot from 'uplot'; import { PanelDataErrorView } from '@grafana/runtime'; +import { OutsideRangePlugin } from '../timeseries/plugins/OutsideRangePlugin'; interface CandlestickPanelProps extends PanelProps {} @@ -311,6 +312,8 @@ export const CandlestickPanel: React.FC = ({ onThresholdsChange={onThresholdsChange} /> )} + + ); }} diff --git a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx index 265b3b3d86c..eab594d6d89 100755 --- a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx +++ b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx @@ -6,6 +6,7 @@ import { TimelineChart } from './TimelineChart'; import { prepareTimelineFields, prepareTimelineLegendItems } from './utils'; import { StateTimelineTooltip } from './StateTimelineTooltip'; import { getLastStreamingDataFramePacket } from 'app/features/live/data/StreamingDataFrame'; +import { OutsideRangePlugin } from '../timeseries/plugins/OutsideRangePlugin'; interface TimelinePanelProps extends PanelProps {} @@ -114,6 +115,7 @@ export const StateTimelinePanel: React.FC = ({ timeZone={timeZone} renderTooltip={renderCustomTooltip} /> + ); }} diff --git a/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx b/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx index 4552ac8477e..4c62207981e 100755 --- a/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx +++ b/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx @@ -5,6 +5,7 @@ import { StatusPanelOptions } from './types'; import { TimelineChart } from '../state-timeline/TimelineChart'; import { TimelineMode } from '../state-timeline/types'; import { prepareTimelineFields, prepareTimelineLegendItems } from '../state-timeline/utils'; +import { OutsideRangePlugin } from '../timeseries/plugins/OutsideRangePlugin'; interface TimelinePanelProps extends PanelProps {} @@ -68,6 +69,7 @@ export const StatusHistoryPanel: React.FC = ({ <> + ); }} diff --git a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx index 5eb7e489b41..06c19a7a434 100644 --- a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx +++ b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx @@ -12,6 +12,7 @@ import { AnnotationEditorPlugin } from './plugins/AnnotationEditorPlugin'; import { ThresholdControlsPlugin } from './plugins/ThresholdControlsPlugin'; import { config } from 'app/core/config'; import { PanelDataErrorView } from '@grafana/runtime'; +import { OutsideRangePlugin } from './plugins/OutsideRangePlugin'; interface TimeSeriesPanelProps extends PanelProps {} @@ -134,6 +135,8 @@ export const TimeSeriesPanel: React.FC = ({ onThresholdsChange={onThresholdsChange} /> )} + + ); }} diff --git a/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx b/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx new file mode 100644 index 00000000000..c8f37bf5aa5 --- /dev/null +++ b/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx @@ -0,0 +1,57 @@ +import React, { useLayoutEffect, useRef } from 'react'; +import { TimeRange, AbsoluteTimeRange } from '@grafana/data'; +import { UPlotConfigBuilder, Button } from '@grafana/ui'; +import uPlot from 'uplot'; + +interface ThresholdControlsPluginProps { + config: UPlotConfigBuilder; + range: TimeRange; + onChangeTimeRange: (timeRange: AbsoluteTimeRange) => void; +} + +export const OutsideRangePlugin: React.FC = ({ config, range, onChangeTimeRange }) => { + const plotInstance = useRef(); + + useLayoutEffect(() => { + config.addHook('init', (u) => { + plotInstance.current = u; + }); + }, [config]); + + const timevalues = plotInstance.current?.data?.[0]; + if (!timevalues || !plotInstance.current || timevalues.length < 2 || !onChangeTimeRange) { + return null; + } + + // Time values are always sorted for uPlot to work + const first = timevalues[0]; + const last = timevalues[timevalues.length - 1]; + const fromX = range.from.valueOf(); + const toX = range.to.valueOf(); + + // (StartA <= EndB) and (EndA >= StartB) + if (first <= toX && last >= fromX) { + return null; + } + + return ( +
+
+
Data outside time range
+ +
+
+ ); +}; + +OutsideRangePlugin.displayName = 'OutsideRangePlugin';