Skip to content

Commit

Permalink
refactor: d3 zoom centering
Browse files Browse the repository at this point in the history
Uses patch from d3/d3-zoom#212
  • Loading branch information
kris7t committed Aug 23, 2023
1 parent 0e54d39 commit 4cce842
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 71 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@
"devDependencies": {
"eslint": "^8.47.0",
"typescript": "5.1.6"
},
"resolutions": {
"d3-zoom@npm:^3.0.0": "[email protected]:d3/d3-zoom.git#commit=3afbe2ae2dfb3129231c5567db56dafb2d6a56a6"
}
}
83 changes: 27 additions & 56 deletions subprojects/frontend/src/graph/GraphArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import Box from '@mui/material/Box';
import * as d3 from 'd3';
import { type Graphviz, graphviz } from 'd3-graphviz';
import type { BaseType, Selection } from 'd3-selection';
import { zoom as d3Zoom } from 'd3-zoom';
import { reaction, type IReactionDisposer } from 'mobx';
import { useCallback, useRef, useState } from 'react';
import { useResizeDetector } from 'react-resize-detector';

import { useRootStore } from '../RootStoreProvider';
import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults';
Expand Down Expand Up @@ -88,59 +88,30 @@ export default function GraphArea(): JSX.Element {
d3.ZoomBehavior<HTMLDivElement, unknown> | undefined
>();
const [zoom, setZoom] = useState<Transform>({ x: 0, y: 0, k: 1 });
const widthRef = useRef<number | undefined>();
const heightRef = useRef<number | undefined>();

const onResize = useCallback(
(width: number | undefined, height: number | undefined) => {
if (canvasRef.current === undefined || zoomRef.current === undefined) {
return;
}
let moveX = 0;
let moveY = 0;
if (widthRef.current !== undefined && width !== undefined) {
moveX = (width - widthRef.current) / 2;
}
if (heightRef.current !== undefined && height !== undefined) {
moveY = (height - heightRef.current) / 2;
}
widthRef.current = width;
heightRef.current = height;
if (moveX === 0 && moveY === 0) {
return;
}
const currentTransform = d3.zoomTransform(canvasRef.current);
zoomRef.current.translateBy(
d3.select(canvasRef.current),
moveX / currentTransform.k - moveX,
moveY / currentTransform.k - moveY,
);
},
[],
);

const { ref: setCanvasResize } = useResizeDetector({
onResize,
});

const setCanvas = useCallback(
(element: HTMLDivElement | null) => {
canvasRef.current = element ?? undefined;
setCanvasResize(element);
if (element === null) {
return;
const setCanvas = useCallback((element: HTMLDivElement | null) => {
canvasRef.current = element ?? undefined;
if (element === null) {
return;
}
const zoomBehavior = d3Zoom<HTMLDivElement, unknown>();
// `@types/d3-zoom` does not contain the `center` function, because it is
// only available as a pull request for `d3-zoom`.
(
zoomBehavior as unknown as {
center(callback: (event: MouseEvent) => [number, number]): unknown;
}
const zoomBehavior = d3.zoom<HTMLDivElement, unknown>();
zoomBehavior.on(
'zoom',
(event: d3.D3ZoomEvent<HTMLDivElement, unknown>) =>
setZoom(event.transform),
);
d3.select(element).call(zoomBehavior);
zoomRef.current = zoomBehavior;
},
[setCanvasResize],
);
).center((event: MouseEvent) => {
const { width, height } = element.getBoundingClientRect();
const [x, y] = d3.pointer(event, element);
return [x - width / 2, y - height / 2];
});
zoomBehavior.on('zoom', (event: d3.D3ZoomEvent<HTMLDivElement, unknown>) =>
setZoom(event.transform),
);
d3.select(element).call(zoomBehavior);
zoomRef.current = zoomBehavior;
}, []);

const setElement = useCallback(
(element: HTMLDivElement | null) => {
Expand Down Expand Up @@ -210,8 +181,8 @@ export default function GraphArea(): JSX.Element {
rect.setAttribute('width', String(xmax - xmin));
rect.setAttribute('height', String(ymax - ymin));
rect.setAttribute('height', String(ymax - ymin));
rect.setAttribute('rx', '12');
rect.setAttribute('ry', '12');
rect.setAttribute('rx', '8');
rect.setAttribute('ry', '8');
node.replaceChild(rect, path);
});
});
Expand Down Expand Up @@ -302,8 +273,8 @@ export default function GraphArea(): JSX.Element {
<Box
sx={{
position: 'absolute',
top: `${50 * zoom.k}%`,
left: `${50 * zoom.k}%`,
top: '50%',
left: '50%',
transform: `
translate(${zoom.x}px, ${zoom.y}px)
scale(${zoom.k})
Expand Down
33 changes: 18 additions & 15 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2663,13 +2663,13 @@ __metadata:
languageName: node
linkType: hard

"@types/d3-zoom@npm:*":
version: 3.0.3
resolution: "@types/d3-zoom@npm:3.0.3"
"@types/d3-zoom@npm:*, @types/d3-zoom@npm:^3.0.4":
version: 3.0.4
resolution: "@types/d3-zoom@npm:3.0.4"
dependencies:
"@types/d3-interpolate": "npm:*"
"@types/d3-selection": "npm:*"
checksum: 7b48870cadf18ba1104613605fc6157dc230f71ecac7f2f0d7e689b44a62ab29377edf98e935a6eee8b87c32456effe3cf6aab321cc20bb31695d21f62fdb311
checksum: 52d1b5f2a1490c25c69b03dcd71601f908ea1e3dedf79e379be4ff23e3a6be85d0694d04c1b23686343a74117e86683a61433ed926637aea545268fd55aa634f
languageName: node
linkType: hard

Expand All @@ -2683,16 +2683,6 @@ __metadata:
languageName: node
linkType: hard

"@types/d3-zoom@npm:^3.0.4":
version: 3.0.4
resolution: "@types/d3-zoom@npm:3.0.4"
dependencies:
"@types/d3-interpolate": "npm:*"
"@types/d3-selection": "npm:*"
checksum: 52d1b5f2a1490c25c69b03dcd71601f908ea1e3dedf79e379be4ff23e3a6be85d0694d04c1b23686343a74117e86683a61433ed926637aea545268fd55aa634f
languageName: node
linkType: hard

"@types/d3@npm:^7.4.0":
version: 7.4.0
resolution: "@types/d3@npm:7.4.0"
Expand Down Expand Up @@ -4154,7 +4144,20 @@ __metadata:
languageName: node
linkType: hard

"d3-zoom@npm:3, d3-zoom@npm:^3.0.0":
"d3-zoom@[email protected]:d3/d3-zoom.git#commit=3afbe2ae2dfb3129231c5567db56dafb2d6a56a6":
version: 3.0.0
resolution: "d3-zoom@[email protected]:d3/d3-zoom.git#commit=3afbe2ae2dfb3129231c5567db56dafb2d6a56a6"
dependencies:
d3-dispatch: "npm:1 - 3"
d3-drag: "npm:2 - 3"
d3-interpolate: "npm:1 - 3"
d3-selection: "npm:2 - 3"
d3-transition: "npm:2 - 3"
checksum: 0cca9382fd9cf7383ecd89ae2f4a828b5088e7801eb89da0656c1d3512cda03bfade727db936721b8004a3142dbbf955a408c99cf370539e3a985da9161c6d54
languageName: node
linkType: hard

"d3-zoom@npm:3":
version: 3.0.0
resolution: "d3-zoom@npm:3.0.0"
dependencies:
Expand Down

0 comments on commit 4cce842

Please sign in to comment.