Skip to content

Commit 7ff0eaa

Browse files
committed
refactor(View): split for readability
1 parent ab47f69 commit 7ff0eaa

File tree

6 files changed

+178
-142
lines changed

6 files changed

+178
-142
lines changed

src/core-ts/View.tsx renamed to src/core-ts/View/index.tsx

Lines changed: 25 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,22 @@
1-
import vtkRenderer from '@kitware/vtk.js/Rendering/Core/Renderer';
2-
import vtkRenderWindow from '@kitware/vtk.js/Rendering/Core/RenderWindow';
3-
import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor';
4-
import vtkOpenGLRenderWindow from '@kitware/vtk.js/Rendering/OpenGL/RenderWindow';
51
import { Nullable, Vector3 } from '@kitware/vtk.js/types';
62
import {
73
CSSProperties,
84
forwardRef,
95
PropsWithChildren,
10-
useCallback,
116
useEffect,
127
useImperativeHandle,
138
useMemo,
149
useRef,
1510
useState,
1611
} from 'react';
17-
import { IView } from '../types';
18-
import useGetterRef from '../utils-ts/useGetterRef';
19-
import useMount from '../utils-ts/useMount';
20-
import { useOrderedUnmountContext } from '../utils-ts/useOrderedUnmountEffect';
21-
import useResizeObserver from '../utils-ts/useResizeObserver';
22-
import useUnmount from '../utils-ts/useUnmount';
23-
import { ViewContext } from './contexts';
12+
import { IView } from '../../types';
13+
import { useOrderedUnmountContext } from '../../utils-ts/useOrderedUnmountEffect';
14+
import { ViewContext } from '../contexts';
15+
import useInteractor from './useInteractor';
16+
import useRenderer from './useRenderer';
17+
import useRenderWindow from './useRenderWindow';
18+
import useRenderWindowView from './useRenderWindowView';
19+
import { useViewResize } from './useViewResize';
2420

2521
const RENDERER_STYLE: CSSProperties = {
2622
position: 'absolute',
@@ -164,147 +160,37 @@ interface Props extends PropsWithChildren {
164160
const DefaultProps = {
165161
interactive: true,
166162
autoResetCamera: true,
167-
background: [0.2, 0.3, 0.4],
163+
background: [0.2, 0.3, 0.4] as Vector3,
168164
style: {
169165
width: '100%',
170166
height: '100%',
171167
} as CSSProperties,
172168
};
173169

174-
function useRenderWindowView(container: Nullable<HTMLElement>) {
175-
const [viewRef, getView] = useGetterRef(() => {
176-
return vtkOpenGLRenderWindow.newInstance();
177-
});
178-
179-
useEffect(() => {
180-
const view = getView();
181-
// FIXME setContainer API should allow null
182-
view.setContainer(container as HTMLElement);
183-
}, [container, getView]);
184-
185-
useUnmount(() => {
186-
if (viewRef.current) {
187-
viewRef.current.delete();
188-
viewRef.current = null;
189-
}
190-
});
191-
192-
return getView;
193-
}
194-
195-
function useInteractor(
196-
getRWView: () => vtkOpenGLRenderWindow,
197-
container: Nullable<HTMLElement>,
198-
props: Props
199-
) {
200-
const [interactorRef, getInteractor] = useGetterRef(() => {
201-
return vtkRenderWindowInteractor.newInstance();
202-
});
203-
const { interactive = DefaultProps.interactive } = props;
204-
205-
useEffect(() => {
206-
if (!container || !interactive) return;
207-
const interactor = getInteractor();
208-
const rwView = getRWView();
209-
210-
interactor.setView(rwView);
211-
interactor.initialize();
212-
interactor.bindEvents(container);
213-
}, [interactive, container, getRWView, getInteractor]);
214-
215-
useUnmount(() => {
216-
if (interactorRef.current) {
217-
interactorRef.current.delete();
218-
interactorRef.current = null;
219-
}
220-
});
221-
222-
return getInteractor;
223-
}
224-
225-
function useRenderWindow(
226-
getRWView: () => vtkOpenGLRenderWindow,
227-
getRenderer: () => vtkRenderer
228-
) {
229-
const [rwRef, getRenderWindow] = useGetterRef(() => {
230-
return vtkRenderWindow.newInstance();
231-
});
232-
233-
useEffect(() => {
234-
const rwView = getRWView();
235-
const renderWindow = getRenderWindow();
236-
renderWindow.addView(rwView);
237-
return () => {
238-
renderWindow.removeView(rwView);
239-
};
240-
}, [getRWView, getRenderWindow]);
241-
242-
useEffect(() => {
243-
const renderWindow = getRenderWindow();
244-
const renderer = getRenderer();
245-
renderWindow.addRenderer(renderer);
246-
return () => {
247-
renderWindow.removeRenderer(renderer);
248-
};
249-
}, [getRenderer, getRenderWindow]);
250-
251-
useUnmount(() => {
252-
if (rwRef.current) {
253-
rwRef.current.delete();
254-
rwRef.current = null;
255-
}
256-
});
257-
258-
return getRenderWindow;
259-
}
260-
261-
function useRenderer(props: Props) {
262-
const [renRef, getRenderer] = useGetterRef(() => vtkRenderer.newInstance());
263-
const { background = DefaultProps.background } = props;
264-
265-
useEffect(() => {
266-
const renderer = getRenderer();
267-
renderer.setBackground(background);
268-
}, [background, getRenderer]);
269-
270-
useUnmount(() => {
271-
if (renRef.current) {
272-
renRef.current.delete();
273-
renRef.current = null;
274-
}
275-
});
276-
277-
return getRenderer;
278-
}
279-
280170
export default forwardRef(function View(props: Props, fwdRef) {
281171
const OrderedUnmountContext = useOrderedUnmountContext();
282172

173+
const {
174+
background = DefaultProps.background,
175+
interactive = DefaultProps.interactive,
176+
autoResetCamera = DefaultProps.autoResetCamera,
177+
} = props;
178+
283179
const containerRef = useRef<Nullable<HTMLDivElement>>(null);
284180

285181
const getRWView = useRenderWindowView(containerRef.current);
286-
const getRenderer = useRenderer(props);
182+
const getRenderer = useRenderer(background);
287183
// We need to attach the renderWindowView to the renderWindow
288184
// before setting the view onto the interactor.
289185
const getRenderWindow = useRenderWindow(getRWView, getRenderer);
290-
const getInteractor = useInteractor(getRWView, containerRef.current, props);
291-
292-
const updateViewSize = useCallback(() => {
293-
const container = containerRef.current;
294-
if (!container) return;
295-
296-
const renderWindowView = getRWView();
297-
const renderWindow = getRenderWindow();
298-
const devicePixelRatio = window.devicePixelRatio || 1;
299-
const { width, height } = container.getBoundingClientRect();
300-
const w = Math.floor(width * devicePixelRatio);
301-
const h = Math.floor(height * devicePixelRatio);
302-
renderWindowView.setSize(Math.max(w, 10), Math.max(h, 10));
303-
renderWindow.render();
304-
}, [getRWView, getRenderWindow]);
186+
const getInteractor = useInteractor(
187+
getRWView,
188+
containerRef.current,
189+
interactive
190+
);
305191

306192
const [renderRequested, setRenderRequested] = useState(false);
307-
const { autoResetCamera = DefaultProps.autoResetCamera } = props;
193+
const requestRender = () => setRenderRequested(true);
308194

309195
useEffect(() => {
310196
if (renderRequested) {
@@ -329,24 +215,21 @@ export default forwardRef(function View(props: Props, fwdRef) {
329215
This will batch render requests, triggering a single
330216
* vtk.js render once after a react render.
331217
*/
332-
requestRender: () => {
333-
setRenderRequested(true);
334-
},
218+
requestRender,
335219
/**
336220
* Resets the camera.
337221
*/
338222
resetCamera: () => {
339223
getRenderer().resetCamera();
340-
getRenderWindow().render();
224+
requestRender();
341225
},
342226
};
343227
}, [getRWView, getRenderer, getRenderWindow, getInteractor]);
344228

345229
// expose the view as a ref for imperative control
346230
useImperativeHandle(fwdRef, () => view);
347231

348-
useResizeObserver(containerRef.current, updateViewSize);
349-
useMount(() => updateViewSize());
232+
useViewResize(containerRef, view);
350233

351234
const { style = DefaultProps.style } = props;
352235
const containerStyle = useMemo<CSSProperties>(

src/core-ts/View/useInteractor.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor';
2+
import vtkOpenGLRenderWindow from '@kitware/vtk.js/Rendering/OpenGL/RenderWindow';
3+
import { Nullable } from '@kitware/vtk.js/types';
4+
import { useEffect } from 'react';
5+
import useGetterRef from '../../utils-ts/useGetterRef';
6+
import useUnmount from '../../utils-ts/useUnmount';
7+
8+
export default function useInteractor(
9+
getRWView: () => vtkOpenGLRenderWindow,
10+
container: Nullable<HTMLElement>,
11+
interactive: boolean
12+
) {
13+
const [interactorRef, getInteractor] = useGetterRef(() => {
14+
return vtkRenderWindowInteractor.newInstance();
15+
});
16+
17+
useEffect(() => {
18+
if (!container || !interactive) return;
19+
const interactor = getInteractor();
20+
const rwView = getRWView();
21+
22+
interactor.setView(rwView);
23+
interactor.initialize();
24+
interactor.bindEvents(container);
25+
}, [interactive, container, getRWView, getInteractor]);
26+
27+
useUnmount(() => {
28+
if (interactorRef.current) {
29+
interactorRef.current.delete();
30+
interactorRef.current = null;
31+
}
32+
});
33+
34+
return getInteractor;
35+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import vtkRenderer from '@kitware/vtk.js/Rendering/Core/Renderer';
2+
import vtkRenderWindow from '@kitware/vtk.js/Rendering/Core/RenderWindow';
3+
import vtkOpenGLRenderWindow from '@kitware/vtk.js/Rendering/OpenGL/RenderWindow';
4+
import { useEffect } from 'react';
5+
import useGetterRef from '../../utils-ts/useGetterRef';
6+
import useUnmount from '../../utils-ts/useUnmount';
7+
8+
export default function useRenderWindow(
9+
getRWView: () => vtkOpenGLRenderWindow,
10+
getRenderer: () => vtkRenderer
11+
) {
12+
const [rwRef, getRenderWindow] = useGetterRef(() => {
13+
return vtkRenderWindow.newInstance();
14+
});
15+
16+
useEffect(() => {
17+
const rwView = getRWView();
18+
const renderWindow = getRenderWindow();
19+
renderWindow.addView(rwView);
20+
return () => {
21+
renderWindow.removeView(rwView);
22+
};
23+
}, [getRWView, getRenderWindow]);
24+
25+
useEffect(() => {
26+
const renderWindow = getRenderWindow();
27+
const renderer = getRenderer();
28+
renderWindow.addRenderer(renderer);
29+
return () => {
30+
renderWindow.removeRenderer(renderer);
31+
};
32+
}, [getRenderer, getRenderWindow]);
33+
34+
useUnmount(() => {
35+
if (rwRef.current) {
36+
rwRef.current.delete();
37+
rwRef.current = null;
38+
}
39+
});
40+
41+
return getRenderWindow;
42+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import vtkOpenGLRenderWindow from '@kitware/vtk.js/Rendering/OpenGL/RenderWindow';
2+
import { Nullable } from '@kitware/vtk.js/types';
3+
import { useEffect } from 'react';
4+
import useGetterRef from '../../utils-ts/useGetterRef';
5+
import useUnmount from '../../utils-ts/useUnmount';
6+
7+
export default function useRenderWindowView(container: Nullable<HTMLElement>) {
8+
const [viewRef, getView] = useGetterRef(() => {
9+
return vtkOpenGLRenderWindow.newInstance();
10+
});
11+
12+
useEffect(() => {
13+
const view = getView();
14+
// FIXME setContainer API should allow null
15+
view.setContainer(container as HTMLElement);
16+
}, [container, getView]);
17+
18+
useUnmount(() => {
19+
if (viewRef.current) {
20+
viewRef.current.delete();
21+
viewRef.current = null;
22+
}
23+
});
24+
25+
return getView;
26+
}

src/core-ts/View/useRenderer.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import vtkRenderer from '@kitware/vtk.js/Rendering/Core/Renderer';
2+
import { Vector3, Vector4 } from '@kitware/vtk.js/types';
3+
import { useEffect } from 'react';
4+
import useGetterRef from '../../utils-ts/useGetterRef';
5+
import useUnmount from '../../utils-ts/useUnmount';
6+
7+
export default function useRenderer(background: Vector3 | Vector4) {
8+
const [renRef, getRenderer] = useGetterRef(() => vtkRenderer.newInstance());
9+
10+
useEffect(() => {
11+
const renderer = getRenderer();
12+
renderer.setBackground(background);
13+
}, [background, getRenderer]);
14+
15+
useUnmount(() => {
16+
if (renRef.current) {
17+
renRef.current.delete();
18+
renRef.current = null;
19+
}
20+
});
21+
22+
return getRenderer;
23+
}

src/core-ts/View/useViewResize.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Nullable } from '@kitware/vtk.js/types';
2+
import { RefObject, useCallback } from 'react';
3+
import { IView } from '../../types';
4+
import useMount from '../../utils-ts/useMount';
5+
import useResizeObserver from '../../utils-ts/useResizeObserver';
6+
7+
export function useViewResize(
8+
containerRef: RefObject<Nullable<Element>>,
9+
view: IView
10+
) {
11+
const updateViewSize = useCallback(() => {
12+
const container = containerRef.current;
13+
if (!container) return;
14+
15+
const renderWindowView = view.getAPISpecificRenderWindow();
16+
const renderWindow = view.getRenderWindow();
17+
const devicePixelRatio = window.devicePixelRatio || 1;
18+
const { width, height } = container.getBoundingClientRect();
19+
const w = Math.floor(width * devicePixelRatio);
20+
const h = Math.floor(height * devicePixelRatio);
21+
renderWindowView.setSize(Math.max(w, 10), Math.max(h, 10));
22+
renderWindow.render();
23+
}, [containerRef, view]);
24+
25+
useResizeObserver(containerRef.current, updateViewSize);
26+
useMount(() => updateViewSize());
27+
}

0 commit comments

Comments
 (0)