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' ;
51import { Nullable , Vector3 } from '@kitware/vtk.js/types' ;
62import {
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
2521const RENDERER_STYLE : CSSProperties = {
2622 position : 'absolute' ,
@@ -164,147 +160,37 @@ interface Props extends PropsWithChildren {
164160const 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-
280170export 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 > (
0 commit comments