Files
grafana/public/app/features/canvas/runtime/SceneTransformWrapper.tsx
Ashley Harrison 47f8717149 React: Use new JSX transform (#88802)
* update eslint, tsconfig + esbuild to handle new jsx transform

* remove thing that breaks the new jsx transform

* remove react imports

* adjust grafana-icons build

* is this the correct syntax?

* try this

* well this was much easier than expected...

* change grafana-plugin-configs webpack config

* fixes

* fix lockfile

* fix 2 more violations

* use path.resolve instead of require.resolve

* remove react import

* fix react imports

* more fixes

* remove React import

* remove import React from docs

* remove another react import
2024-06-25 12:43:47 +01:00

115 lines
3.7 KiB
TypeScript

import * as React from 'react';
import { TransformWrapper, TransformComponent, ReactZoomPanPinchRef } from 'react-zoom-pan-pinch';
import { config } from '@grafana/runtime';
import { Scene } from './scene';
type SceneTransformWrapperProps = {
scene: Scene;
children: React.ReactNode;
};
export const SceneTransformWrapper = ({ scene, children: sceneDiv }: SceneTransformWrapperProps) => {
const onZoom = (zoomPanPinchRef: ReactZoomPanPinchRef) => {
const scale = zoomPanPinchRef.state.scale;
scene.scale = scale;
if (scene.shouldInfinitePan) {
const isScaleZoomedOut = scale < 1;
if (isScaleZoomedOut) {
scene.updateSize(scene.width / scale, scene.height / scale);
scene.panel.forceUpdate();
}
}
};
const onZoomStop = (zoomPanPinchRef: ReactZoomPanPinchRef) => {
const scale = zoomPanPinchRef.state.scale;
scene.scale = scale;
updateMoveable(scale);
};
const onTransformed = (
_: ReactZoomPanPinchRef,
state: {
scale: number;
positionX: number;
positionY: number;
}
) => {
const scale = state.scale;
scene.scale = scale;
updateMoveable(scale);
};
const updateMoveable = (scale: number) => {
if (scene.moveable && scale > 0) {
scene.moveable.zoom = 1 / scale;
if (scale === 1) {
scene.moveable.snappable = true;
} else {
scene.moveable.snappable = false;
}
}
};
const onPanning = (_: ReactZoomPanPinchRef, event: MouseEvent | TouchEvent) => {
if (scene.shouldInfinitePan && event instanceof MouseEvent) {
// Get deltaX and deltaY from pan event and add it to current canvas dimensions
let deltaX = event.movementX;
let deltaY = event.movementY;
if (deltaX > 0) {
deltaX = 0;
}
if (deltaY > 0) {
deltaY = 0;
}
// TODO: Consider bounding to the scene elements instead of allowing "infinite" panning
// TODO: Consider making scene grow in all directions vs just down to the right / bottom
scene.updateSize(scene.width - deltaX, scene.height - deltaY);
scene.panel.forceUpdate();
}
};
const onSceneContainerMouseDown = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
// If pan and zoom is disabled or context menu is visible, don't pan
if ((!scene.shouldPanZoom || scene.contextMenuVisible) && (e.button === 1 || (e.button === 2 && e.ctrlKey))) {
e.preventDefault();
e.stopPropagation();
}
// If context menu is hidden, ignore left mouse or non-ctrl right mouse for pan
if (!scene.contextMenuVisible && !scene.isPanelEditing && e.button === 2 && !e.ctrlKey) {
e.preventDefault();
e.stopPropagation();
}
};
// Set panel content overflow to hidden to prevent canvas content from overflowing
scene.div?.parentElement?.parentElement?.parentElement?.parentElement?.setAttribute('style', `overflow: hidden`);
return (
<TransformWrapper
doubleClick={{ mode: 'reset' }}
ref={scene.transformComponentRef}
onZoom={onZoom}
onZoomStop={onZoomStop}
onTransformed={onTransformed}
disabled={!config.featureToggles.canvasPanelPanZoom || !scene.shouldPanZoom}
panning={{ allowLeftClickPan: false }}
limitToBounds={!scene.shouldInfinitePan}
minScale={scene.shouldInfinitePan ? 0.1 : undefined}
onPanning={onPanning}
>
<TransformComponent>
{/* The <div> element has child elements that allow for mouse events, so we need to disable the linter rule */}
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
<div onMouseDown={onSceneContainerMouseDown}>{sceneDiv}</div>
</TransformComponent>
</TransformWrapper>
);
};