diff --git a/packages/grafana-ui/src/components/uPlot/plugins/ZoomPlugin.tsx b/packages/grafana-ui/src/components/uPlot/plugins/ZoomPlugin.tsx
index d0697334379..415d000d303 100644
--- a/packages/grafana-ui/src/components/uPlot/plugins/ZoomPlugin.tsx
+++ b/packages/grafana-ui/src/components/uPlot/plugins/ZoomPlugin.tsx
@@ -1,10 +1,10 @@
import { useLayoutEffect } from 'react';
import { UPlotConfigBuilder } from '../config/UPlotConfigBuilder';
-import { pluginLog } from '../utils';
interface ZoomPluginProps {
onZoom: (range: { from: number; to: number }) => void;
+ withZoomY?: boolean;
config: UPlotConfigBuilder;
}
@@ -14,41 +14,86 @@ const MIN_ZOOM_DIST = 5;
/**
* @alpha
*/
-export const ZoomPlugin = ({ onZoom, config }: ZoomPluginProps) => {
+export const ZoomPlugin = ({ onZoom, config, withZoomY = false }: ZoomPluginProps) => {
useLayoutEffect(() => {
- config.addHook('setSelect', (u) => {
- const min = u.posToVal(u.select.left, 'x');
- const max = u.posToVal(u.select.left + u.select.width, 'x');
+ let yZoomed = false;
+ let yDrag = false;
- if (u.select.width >= MIN_ZOOM_DIST) {
- pluginLog('ZoomPlugin', false, 'selected', {
- min,
- max,
- bbox: {
- left: u.bbox.left / window.devicePixelRatio + u.select.left,
- top: u.bbox.top / window.devicePixelRatio,
- height: u.bbox.height / window.devicePixelRatio,
- width: u.select.width,
+ if (withZoomY) {
+ config.addHook('init', (u) => {
+ u.root!.addEventListener(
+ 'mousedown',
+ (e) => {
+ if (e.button === 0 && e.shiftKey) {
+ yDrag = true;
+
+ u.cursor!.drag!.x = false;
+ u.cursor!.drag!.y = true;
+
+ let onUp = (e: MouseEvent) => {
+ u.cursor!.drag!.x = true;
+ u.cursor!.drag!.y = false;
+ document.removeEventListener('mouseup', onUp, true);
+ };
+
+ document.addEventListener('mouseup', onUp, true);
+ }
},
- });
- onZoom({ from: min, to: max });
+ true
+ );
+ });
+ }
+
+ config.addHook('setSelect', (u) => {
+ if (withZoomY && yDrag) {
+ if (u.select.height >= MIN_ZOOM_DIST) {
+ for (let key in u.scales!) {
+ if (key !== 'x') {
+ const maxY = u.posToVal(u.select.top, key);
+ const minY = u.posToVal(u.select.top + u.select.height, key);
+
+ u.setScale(key, { min: minY, max: maxY });
+ }
+ }
+
+ yZoomed = true;
+ }
+
+ yDrag = false;
+ } else {
+ if (u.select.width >= MIN_ZOOM_DIST) {
+ const minX = u.posToVal(u.select.left, 'x');
+ const maxX = u.posToVal(u.select.left + u.select.width, 'x');
+
+ onZoom({ from: minX, to: maxX });
+ }
}
// manually hide selected region (since cursor.drag.setScale = false)
- /* @ts-ignore */
- u.setSelect({ left: 0, width: 0 }, false);
+ u.setSelect({ left: 0, width: 0, top: 0, height: 0 }, false);
});
config.setCursor({
bind: {
dblclick: (u) => () => {
- let xScale = u.scales.x;
+ if (withZoomY && yZoomed) {
+ for (let key in u.scales!) {
+ if (key !== 'x') {
+ // @ts-ignore (this is not typed correctly in uPlot, assigning nulls means auto-scale / reset)
+ u.setScale(key, { min: null, max: null });
+ }
+ }
- const frTs = xScale.min!;
- const toTs = xScale.max!;
- const pad = (toTs - frTs) / 2;
+ yZoomed = false;
+ } else {
+ let xScale = u.scales.x;
- onZoom({ from: frTs - pad, to: toTs + pad });
+ const frTs = xScale.min!;
+ const toTs = xScale.max!;
+ const pad = (toTs - frTs) / 2;
+
+ onZoom({ from: frTs - pad, to: toTs + pad });
+ }
return null;
},
diff --git a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx
index 2611c40d823..e0707a3820f 100644
--- a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx
+++ b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx
@@ -254,7 +254,7 @@ export const CandlestickPanel = ({
return (
<>
-
+
-
+
{options.tooltip.mode === TooltipDisplayMode.None || (