Skip to content

Commit f6e5f27

Browse files
authored
Merge pull request #59 from Kitware/multi-view-root
Multi view root
2 parents aee6ace + 527d6c8 commit f6e5f27

25 files changed

+481
-97
lines changed

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@
2828
"dev": "rollup ./src/index.js -c --watch"
2929
},
3030
"peerDependencies": {
31-
"@kitware/vtk.js": "^24.3.1",
31+
"@kitware/vtk.js": "^24.7.1",
3232
"react": "^16.0.0"
3333
},
3434
"devDependencies": {
3535
"@babel/core": "^7.12.10",
3636
"@babel/plugin-transform-runtime": "^7.12.10",
3737
"@babel/preset-env": "^7.12.11",
3838
"@babel/preset-react": "^7.12.10",
39-
"@kitware/vtk.js": "^24.3.1",
39+
"@kitware/vtk.js": "^24.7.1",
4040
"@rollup/plugin-babel": "^5.2.2",
4141
"@rollup/plugin-commonjs": "17.0.0",
4242
"@rollup/plugin-eslint": "^8.0.1",

src/core/MultiViewRoot.js

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
import vtkRenderWindow from '@kitware/vtk.js/Rendering/Core/RenderWindow';
5+
import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor';
6+
import vtkOpenGLRenderWindow from '@kitware/vtk.js/Rendering/OpenGL/RenderWindow';
7+
8+
// ----------------------------------------------------------------------------
9+
// Context to pass parent variables to children
10+
// ----------------------------------------------------------------------------
11+
12+
export const MultiViewRootContext = React.createContext(null);
13+
14+
export function removeKeys(props, propNames) {
15+
const cleanedProps = { ...props };
16+
propNames.forEach((name) => {
17+
delete cleanedProps[name];
18+
});
19+
return cleanedProps;
20+
}
21+
22+
// ----------------------------------------------------------------------------
23+
// Helper constants
24+
// ----------------------------------------------------------------------------
25+
26+
const RENDERER_STYLE = {
27+
position: 'absolute',
28+
top: 0,
29+
left: 0,
30+
right: 0,
31+
bottom: 0,
32+
pointerEvents: 'none',
33+
};
34+
35+
export default class MultiViewRoot extends Component {
36+
constructor(props) {
37+
super(props);
38+
this.containerRef = React.createRef();
39+
40+
// Create vtk.js view
41+
this.renderWindow = vtkRenderWindow.newInstance();
42+
this.interactor = null;
43+
44+
this.renderWindowView = vtkOpenGLRenderWindow.newInstance();
45+
this.renderWindow.addView(this.renderWindowView);
46+
47+
this.resizeObserver = new ResizeObserver((entries) => {
48+
this.onResize();
49+
});
50+
51+
this.interactor = vtkRenderWindowInteractor.newInstance();
52+
this.interactor.setView(this.renderWindowView);
53+
54+
this.onResize = this.onResize.bind(this);
55+
56+
this.initialized = false;
57+
}
58+
59+
componentDidMount() {
60+
// TODO support runtime toggling of this flag?
61+
if (!this.props.disabled) {
62+
const container = this.containerRef.current;
63+
this.renderWindowView.setContainer(container);
64+
65+
this.interactor.initialize();
66+
67+
this.resizeObserver.observe(container);
68+
this.onResize();
69+
70+
this.initialized = true;
71+
72+
this.update(this.props);
73+
}
74+
}
75+
76+
componentDidUpdate(prevProps) {
77+
this.update(this.props, prevProps);
78+
}
79+
80+
componentWillUnmount() {
81+
if (this.initialized) {
82+
// Stop size listening
83+
this.resizeObserver.disconnect();
84+
85+
if (this.interactor.getContainer()) {
86+
this.interactor.unbindEvents();
87+
}
88+
89+
this.renderWindowView.setContainer(null);
90+
}
91+
92+
this.renderWindow.removeView(this.renderWindowView);
93+
94+
this.interactor.delete();
95+
this.renderWindow.delete();
96+
this.renderWindowView.delete();
97+
98+
this.interactor = null;
99+
this.renderWindow = null;
100+
this.renderWindowView = null;
101+
}
102+
103+
render() {
104+
const { id, children, style, disabled } = this.props;
105+
106+
return (
107+
<div
108+
key={id}
109+
id={id}
110+
style={{ position: 'relative', ...style }}
111+
{...removeKeys(this.props, Object.keys(propTypes))}
112+
>
113+
<div style={RENDERER_STYLE} ref={this.containerRef} />
114+
<MultiViewRootContext.Provider value={disabled ? null : this}>
115+
{children}
116+
</MultiViewRootContext.Provider>
117+
</div>
118+
);
119+
}
120+
121+
bindInteractorEvents(container) {
122+
if (this.interactor) {
123+
if (this.interactor.getContainer()) {
124+
this.interactor.unbindEvents();
125+
}
126+
if (container) {
127+
this.interactor.bindEvents(container);
128+
}
129+
}
130+
}
131+
132+
onResize() {
133+
const container = this.containerRef.current;
134+
if (container) {
135+
const devicePixelRatio = window.devicePixelRatio || 1;
136+
const { width, height } = container.getBoundingClientRect();
137+
const w = Math.floor(width * devicePixelRatio);
138+
const h = Math.floor(height * devicePixelRatio);
139+
this.renderWindowView.setSize(Math.max(w, 10), Math.max(h, 10));
140+
this.renderWindow.render();
141+
}
142+
}
143+
144+
update(props, previous) {
145+
const { triggerRender } = props;
146+
// Allow to trigger method call from property change
147+
if (previous && triggerRender !== previous.triggerRender) {
148+
this.renderViewTimeout = setTimeout(this.renderWindow.render, 0);
149+
}
150+
}
151+
}
152+
153+
MultiViewRoot.defaultProps = {
154+
triggerRender: 0,
155+
disabled: false,
156+
};
157+
158+
export const propTypes = {
159+
/**
160+
* The ID used to identify this component.
161+
*/
162+
id: PropTypes.string,
163+
164+
/**
165+
* Property use to trigger a render when changing.
166+
*/
167+
triggerRender: PropTypes.number,
168+
169+
/**
170+
* Disables or enables the multi-renderer root.
171+
*/
172+
disabled: PropTypes.bool,
173+
174+
/**
175+
* List of representation to show
176+
*/
177+
children: PropTypes.oneOfType([
178+
PropTypes.arrayOf(PropTypes.node),
179+
PropTypes.node,
180+
]),
181+
};
182+
183+
MultiViewRoot.propTypes = propTypes;

0 commit comments

Comments
 (0)