Skip to content

Commit 3bd0d3f

Browse files
authored
added zoom in zoom out for DAGs. #774 (#899)
1 parent 6c1a2d9 commit 3bd0d3f

File tree

2 files changed

+84
-17
lines changed

2 files changed

+84
-17
lines changed

Diff for: ui/src/components/atoms/Mermaid.tsx

+24-15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
55
type Props = {
66
def: string;
77
style?: CSSProperties;
8+
scale: number;
89
};
910

1011
// Mermaidの初期設定
@@ -23,7 +24,7 @@ mermaid.initialize({
2324
logLevel: 4, // ERROR
2425
});
2526

26-
function Mermaid({ def, style = {} }: Props) {
27+
function Mermaid({ def, style = {}, scale }: Props) {
2728
const ref = React.useRef<HTMLDivElement>(null);
2829
const [uniqueId] = React.useState(
2930
() => `mermaid-${Math.random().toString(36).substr(2, 9)}`
@@ -36,6 +37,7 @@ function Mermaid({ def, style = {} }: Props) {
3637
const dStyle: CSSProperties = {
3738
overflowX: 'auto',
3839
padding: '2em',
40+
position: 'relative',
3941
};
4042

4143
const render = async () => {
@@ -76,29 +78,36 @@ function Mermaid({ def, style = {} }: Props) {
7678
}
7779
};
7880

79-
const renderWithRetry = () => {
80-
try {
81-
render();
82-
} catch (error) {
83-
console.error('error rendering mermaid, retrying, error:');
84-
console.error(error);
85-
console.error(def);
86-
setTimeout(renderWithRetry, 1);
87-
}
88-
};
89-
9081
React.useEffect(() => {
91-
renderWithRetry();
82+
render();
9283
}, [def]);
9384

85+
React.useEffect(() => {
86+
if (ref.current) {
87+
const svg = ref.current.querySelector('svg');
88+
if (svg) {
89+
svg.style.transform = `scale(${scale})`;
90+
svg.style.transformOrigin = 'top left';
91+
}
92+
}
93+
}, [scale]);
94+
9495
return (
9596
<div style={dStyle}>
96-
<div className="mermaid" ref={ref} style={mStyle} />
97+
<div
98+
className="mermaid"
99+
ref={ref}
100+
style={{
101+
...mStyle,
102+
overflow: 'auto',
103+
maxHeight: '80vh',
104+
}}
105+
/>
97106
</div>
98107
);
99108
}
100109

101110
// メモ化の条件を維持
102111
export default React.memo(Mermaid, (prev, next) => {
103-
return prev.def === next.def;
112+
return prev.def === next.def && prev.scale === next.scale;
104113
});

Diff for: ui/src/components/molecules/Graph.tsx

+60-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import { Node, NodeStatus } from '../../models';
33
import { Step } from '../../models';
44
import Mermaid from '../atoms/Mermaid';
5+
import { ToggleButton, ToggleButtonGroup } from '@mui/material';
6+
import { ZoomIn, ZoomOut, RestartAlt } from '@mui/icons-material';
57

68
type onClickNode = (name: string) => void;
79
export type FlowchartType = 'TD' | 'LR';
@@ -29,6 +31,20 @@ const Graph: React.FC<Props> = ({
2931
showIcons = true,
3032
animate = true,
3133
}) => {
34+
const [scale, setScale] = useState(1);
35+
36+
const zoomIn = () => {
37+
setScale((prevScale) => Math.min(prevScale + 0.1, 2));
38+
};
39+
40+
const zoomOut = () => {
41+
setScale((prevScale) => Math.max(prevScale - 0.1, 0.5));
42+
};
43+
44+
const resetZoom = () => {
45+
setScale(1);
46+
};
47+
3248
// Calculate width based on flowchart type and graph breadth
3349
const width = React.useMemo(() => {
3450
if (!steps) return '100%';
@@ -59,6 +75,17 @@ const Graph: React.FC<Props> = ({
5975
backgroundSize: '20px 20px',
6076
};
6177

78+
const containerStyle = {
79+
position: 'relative' as const,
80+
};
81+
82+
const toggleButtonStyle = {
83+
position: 'absolute' as const,
84+
top: '10px',
85+
right: '10px',
86+
zIndex: 1,
87+
};
88+
6289
// Define FontAwesome icons for each status with colors and animations
6390
const statusIcons: { [key: number]: string } = {
6491
[NodeStatus.None]:
@@ -171,7 +198,38 @@ const Graph: React.FC<Props> = ({
171198
return dat.join('\n');
172199
}, [steps, onClickNode, flowchart, showIcons]);
173200

174-
return <Mermaid style={mermaidStyle} def={graph} />;
201+
return (
202+
<div style={containerStyle}>
203+
<ToggleButtonGroup
204+
size="small"
205+
sx={{
206+
...toggleButtonStyle,
207+
backgroundColor: 'white',
208+
'& .MuiToggleButton-root': {
209+
border: '1px solid rgba(0, 0, 0, 0.12)',
210+
borderRadius: '4px !important',
211+
marginRight: '8px',
212+
padding: '4px 8px',
213+
color: 'rgba(0, 0, 0, 0.54)',
214+
'&:hover': {
215+
backgroundColor: 'rgba(0, 0, 0, 0.04)',
216+
},
217+
},
218+
}}
219+
>
220+
<ToggleButton value="zoomin" onClick={zoomIn}>
221+
<ZoomIn fontSize="small" />
222+
</ToggleButton>
223+
<ToggleButton value="zoomout" onClick={zoomOut}>
224+
<ZoomOut fontSize="small" />
225+
</ToggleButton>
226+
<ToggleButton value="reset" onClick={resetZoom}>
227+
<RestartAlt fontSize="small" />
228+
</ToggleButton>
229+
</ToggleButtonGroup>
230+
<Mermaid style={mermaidStyle} def={graph} scale={scale} />
231+
</div>
232+
);
175233
};
176234

177235
// Function to calculate the maximum breadth of the graph

0 commit comments

Comments
 (0)