diff options
-rw-r--r-- | package.json | 3 | ||||
-rw-r--r-- | subprojects/frontend/src/graph/GraphArea.tsx | 83 | ||||
-rw-r--r-- | yarn.lock | 33 |
3 files changed, 48 insertions, 71 deletions
diff --git a/package.json b/package.json index 5515a3cd..bdac68a6 100644 --- a/package.json +++ b/package.json | |||
@@ -27,5 +27,8 @@ | |||
27 | "devDependencies": { | 27 | "devDependencies": { |
28 | "eslint": "^8.47.0", | 28 | "eslint": "^8.47.0", |
29 | "typescript": "5.1.6" | 29 | "typescript": "5.1.6" |
30 | }, | ||
31 | "resolutions": { | ||
32 | "d3-zoom@npm:^3.0.0": "git@github.com:d3/d3-zoom.git#commit=3afbe2ae2dfb3129231c5567db56dafb2d6a56a6" | ||
30 | } | 33 | } |
31 | } | 34 | } |
diff --git a/subprojects/frontend/src/graph/GraphArea.tsx b/subprojects/frontend/src/graph/GraphArea.tsx index b55245d8..1da7eaef 100644 --- a/subprojects/frontend/src/graph/GraphArea.tsx +++ b/subprojects/frontend/src/graph/GraphArea.tsx | |||
@@ -8,9 +8,9 @@ import Box from '@mui/material/Box'; | |||
8 | import * as d3 from 'd3'; | 8 | import * as d3 from 'd3'; |
9 | import { type Graphviz, graphviz } from 'd3-graphviz'; | 9 | import { type Graphviz, graphviz } from 'd3-graphviz'; |
10 | import type { BaseType, Selection } from 'd3-selection'; | 10 | import type { BaseType, Selection } from 'd3-selection'; |
11 | import { zoom as d3Zoom } from 'd3-zoom'; | ||
11 | import { reaction, type IReactionDisposer } from 'mobx'; | 12 | import { reaction, type IReactionDisposer } from 'mobx'; |
12 | import { useCallback, useRef, useState } from 'react'; | 13 | import { useCallback, useRef, useState } from 'react'; |
13 | import { useResizeDetector } from 'react-resize-detector'; | ||
14 | 14 | ||
15 | import { useRootStore } from '../RootStoreProvider'; | 15 | import { useRootStore } from '../RootStoreProvider'; |
16 | import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults'; | 16 | import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults'; |
@@ -88,59 +88,30 @@ export default function GraphArea(): JSX.Element { | |||
88 | d3.ZoomBehavior<HTMLDivElement, unknown> | undefined | 88 | d3.ZoomBehavior<HTMLDivElement, unknown> | undefined |
89 | >(); | 89 | >(); |
90 | const [zoom, setZoom] = useState<Transform>({ x: 0, y: 0, k: 1 }); | 90 | const [zoom, setZoom] = useState<Transform>({ x: 0, y: 0, k: 1 }); |
91 | const widthRef = useRef<number | undefined>(); | ||
92 | const heightRef = useRef<number | undefined>(); | ||
93 | 91 | ||
94 | const onResize = useCallback( | 92 | const setCanvas = useCallback((element: HTMLDivElement | null) => { |
95 | (width: number | undefined, height: number | undefined) => { | 93 | canvasRef.current = element ?? undefined; |
96 | if (canvasRef.current === undefined || zoomRef.current === undefined) { | 94 | if (element === null) { |
97 | return; | 95 | return; |
98 | } | 96 | } |
99 | let moveX = 0; | 97 | const zoomBehavior = d3Zoom<HTMLDivElement, unknown>(); |
100 | let moveY = 0; | 98 | // `@types/d3-zoom` does not contain the `center` function, because it is |
101 | if (widthRef.current !== undefined && width !== undefined) { | 99 | // only available as a pull request for `d3-zoom`. |
102 | moveX = (width - widthRef.current) / 2; | 100 | ( |
103 | } | 101 | zoomBehavior as unknown as { |
104 | if (heightRef.current !== undefined && height !== undefined) { | 102 | center(callback: (event: MouseEvent) => [number, number]): unknown; |
105 | moveY = (height - heightRef.current) / 2; | ||
106 | } | ||
107 | widthRef.current = width; | ||
108 | heightRef.current = height; | ||
109 | if (moveX === 0 && moveY === 0) { | ||
110 | return; | ||
111 | } | ||
112 | const currentTransform = d3.zoomTransform(canvasRef.current); | ||
113 | zoomRef.current.translateBy( | ||
114 | d3.select(canvasRef.current), | ||
115 | moveX / currentTransform.k - moveX, | ||
116 | moveY / currentTransform.k - moveY, | ||
117 | ); | ||
118 | }, | ||
119 | [], | ||
120 | ); | ||
121 | |||
122 | const { ref: setCanvasResize } = useResizeDetector({ | ||
123 | onResize, | ||
124 | }); | ||
125 | |||
126 | const setCanvas = useCallback( | ||
127 | (element: HTMLDivElement | null) => { | ||
128 | canvasRef.current = element ?? undefined; | ||
129 | setCanvasResize(element); | ||
130 | if (element === null) { | ||
131 | return; | ||
132 | } | 103 | } |
133 | const zoomBehavior = d3.zoom<HTMLDivElement, unknown>(); | 104 | ).center((event: MouseEvent) => { |
134 | zoomBehavior.on( | 105 | const { width, height } = element.getBoundingClientRect(); |
135 | 'zoom', | 106 | const [x, y] = d3.pointer(event, element); |
136 | (event: d3.D3ZoomEvent<HTMLDivElement, unknown>) => | 107 | return [x - width / 2, y - height / 2]; |
137 | setZoom(event.transform), | 108 | }); |
138 | ); | 109 | zoomBehavior.on('zoom', (event: d3.D3ZoomEvent<HTMLDivElement, unknown>) => |
139 | d3.select(element).call(zoomBehavior); | 110 | setZoom(event.transform), |
140 | zoomRef.current = zoomBehavior; | 111 | ); |
141 | }, | 112 | d3.select(element).call(zoomBehavior); |
142 | [setCanvasResize], | 113 | zoomRef.current = zoomBehavior; |
143 | ); | 114 | }, []); |
144 | 115 | ||
145 | const setElement = useCallback( | 116 | const setElement = useCallback( |
146 | (element: HTMLDivElement | null) => { | 117 | (element: HTMLDivElement | null) => { |
@@ -210,8 +181,8 @@ export default function GraphArea(): JSX.Element { | |||
210 | rect.setAttribute('width', String(xmax - xmin)); | 181 | rect.setAttribute('width', String(xmax - xmin)); |
211 | rect.setAttribute('height', String(ymax - ymin)); | 182 | rect.setAttribute('height', String(ymax - ymin)); |
212 | rect.setAttribute('height', String(ymax - ymin)); | 183 | rect.setAttribute('height', String(ymax - ymin)); |
213 | rect.setAttribute('rx', '12'); | 184 | rect.setAttribute('rx', '8'); |
214 | rect.setAttribute('ry', '12'); | 185 | rect.setAttribute('ry', '8'); |
215 | node.replaceChild(rect, path); | 186 | node.replaceChild(rect, path); |
216 | }); | 187 | }); |
217 | }); | 188 | }); |
@@ -302,8 +273,8 @@ export default function GraphArea(): JSX.Element { | |||
302 | <Box | 273 | <Box |
303 | sx={{ | 274 | sx={{ |
304 | position: 'absolute', | 275 | position: 'absolute', |
305 | top: `${50 * zoom.k}%`, | 276 | top: '50%', |
306 | left: `${50 * zoom.k}%`, | 277 | left: '50%', |
307 | transform: ` | 278 | transform: ` |
308 | translate(${zoom.x}px, ${zoom.y}px) | 279 | translate(${zoom.x}px, ${zoom.y}px) |
309 | scale(${zoom.k}) | 280 | scale(${zoom.k}) |
@@ -2663,13 +2663,13 @@ __metadata: | |||
2663 | languageName: node | 2663 | languageName: node |
2664 | linkType: hard | 2664 | linkType: hard |
2665 | 2665 | ||
2666 | "@types/d3-zoom@npm:*": | 2666 | "@types/d3-zoom@npm:*, @types/d3-zoom@npm:^3.0.4": |
2667 | version: 3.0.3 | 2667 | version: 3.0.4 |
2668 | resolution: "@types/d3-zoom@npm:3.0.3" | 2668 | resolution: "@types/d3-zoom@npm:3.0.4" |
2669 | dependencies: | 2669 | dependencies: |
2670 | "@types/d3-interpolate": "npm:*" | 2670 | "@types/d3-interpolate": "npm:*" |
2671 | "@types/d3-selection": "npm:*" | 2671 | "@types/d3-selection": "npm:*" |
2672 | checksum: 7b48870cadf18ba1104613605fc6157dc230f71ecac7f2f0d7e689b44a62ab29377edf98e935a6eee8b87c32456effe3cf6aab321cc20bb31695d21f62fdb311 | 2672 | checksum: 52d1b5f2a1490c25c69b03dcd71601f908ea1e3dedf79e379be4ff23e3a6be85d0694d04c1b23686343a74117e86683a61433ed926637aea545268fd55aa634f |
2673 | languageName: node | 2673 | languageName: node |
2674 | linkType: hard | 2674 | linkType: hard |
2675 | 2675 | ||
@@ -2683,16 +2683,6 @@ __metadata: | |||
2683 | languageName: node | 2683 | languageName: node |
2684 | linkType: hard | 2684 | linkType: hard |
2685 | 2685 | ||
2686 | "@types/d3-zoom@npm:^3.0.4": | ||
2687 | version: 3.0.4 | ||
2688 | resolution: "@types/d3-zoom@npm:3.0.4" | ||
2689 | dependencies: | ||
2690 | "@types/d3-interpolate": "npm:*" | ||
2691 | "@types/d3-selection": "npm:*" | ||
2692 | checksum: 52d1b5f2a1490c25c69b03dcd71601f908ea1e3dedf79e379be4ff23e3a6be85d0694d04c1b23686343a74117e86683a61433ed926637aea545268fd55aa634f | ||
2693 | languageName: node | ||
2694 | linkType: hard | ||
2695 | |||
2696 | "@types/d3@npm:^7.4.0": | 2686 | "@types/d3@npm:^7.4.0": |
2697 | version: 7.4.0 | 2687 | version: 7.4.0 |
2698 | resolution: "@types/d3@npm:7.4.0" | 2688 | resolution: "@types/d3@npm:7.4.0" |
@@ -4154,7 +4144,20 @@ __metadata: | |||
4154 | languageName: node | 4144 | languageName: node |
4155 | linkType: hard | 4145 | linkType: hard |
4156 | 4146 | ||
4157 | "d3-zoom@npm:3, d3-zoom@npm:^3.0.0": | 4147 | "d3-zoom@git@github.com:d3/d3-zoom.git#commit=3afbe2ae2dfb3129231c5567db56dafb2d6a56a6": |
4148 | version: 3.0.0 | ||
4149 | resolution: "d3-zoom@git@github.com:d3/d3-zoom.git#commit=3afbe2ae2dfb3129231c5567db56dafb2d6a56a6" | ||
4150 | dependencies: | ||
4151 | d3-dispatch: "npm:1 - 3" | ||
4152 | d3-drag: "npm:2 - 3" | ||
4153 | d3-interpolate: "npm:1 - 3" | ||
4154 | d3-selection: "npm:2 - 3" | ||
4155 | d3-transition: "npm:2 - 3" | ||
4156 | checksum: 0cca9382fd9cf7383ecd89ae2f4a828b5088e7801eb89da0656c1d3512cda03bfade727db936721b8004a3142dbbf955a408c99cf370539e3a985da9161c6d54 | ||
4157 | languageName: node | ||
4158 | linkType: hard | ||
4159 | |||
4160 | "d3-zoom@npm:3": | ||
4158 | version: 3.0.0 | 4161 | version: 3.0.0 |
4159 | resolution: "d3-zoom@npm:3.0.0" | 4162 | resolution: "d3-zoom@npm:3.0.0" |
4160 | dependencies: | 4163 | dependencies: |