diff --git a/package-lock.json b/package-lock.json
index 7a2ffc7..fca0bf6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,7 +16,7 @@
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
- "@kitware/vtk.js": "^24.3.1",
+ "@kitware/vtk.js": "^24.7.1",
"@rollup/plugin-babel": "^5.2.2",
"@rollup/plugin-commonjs": "17.0.0",
"@rollup/plugin-eslint": "^8.0.1",
@@ -46,7 +46,7 @@
"semantic-release": "17.3.1"
},
"peerDependencies": {
- "@kitware/vtk.js": "^24.3.1",
+ "@kitware/vtk.js": "^24.7.1",
"react": "^16.0.0"
}
},
@@ -2128,9 +2128,9 @@
"dev": true
},
"node_modules/@kitware/vtk.js": {
- "version": "24.3.1",
- "resolved": "https://registry.npmjs.org/@kitware/vtk.js/-/vtk.js-24.3.1.tgz",
- "integrity": "sha512-SLDjDPohq1esh4MIYBqMQQYGu/Um4x5bbnuLyFo9l0bg1KmgLqC1IGnCtWecG5w0LR62JbSAHCcp/m9Zd4GaAw==",
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@kitware/vtk.js/-/vtk.js-24.7.1.tgz",
+ "integrity": "sha512-geOFGGpLFertWHu1oo23kScpd4fduBetOWtxFPWf1wlTHw/vxQNnp7+razqBIALOSYjFVftj8zplFAWW58cHhQ==",
"dev": true,
"dependencies": {
"@babel/runtime": "7.16.7",
@@ -16905,9 +16905,9 @@
"dev": true
},
"@kitware/vtk.js": {
- "version": "24.3.1",
- "resolved": "https://registry.npmjs.org/@kitware/vtk.js/-/vtk.js-24.3.1.tgz",
- "integrity": "sha512-SLDjDPohq1esh4MIYBqMQQYGu/Um4x5bbnuLyFo9l0bg1KmgLqC1IGnCtWecG5w0LR62JbSAHCcp/m9Zd4GaAw==",
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@kitware/vtk.js/-/vtk.js-24.7.1.tgz",
+ "integrity": "sha512-geOFGGpLFertWHu1oo23kScpd4fduBetOWtxFPWf1wlTHw/vxQNnp7+razqBIALOSYjFVftj8zplFAWW58cHhQ==",
"dev": true,
"requires": {
"@babel/runtime": "7.16.7",
diff --git a/package.json b/package.json
index c7b69d3..ff2700b 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,7 @@
"dev": "rollup ./src/index.js -c --watch"
},
"peerDependencies": {
- "@kitware/vtk.js": "^24.3.1",
+ "@kitware/vtk.js": "^24.7.1",
"react": "^16.0.0"
},
"devDependencies": {
@@ -36,7 +36,7 @@
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
- "@kitware/vtk.js": "^24.3.1",
+ "@kitware/vtk.js": "^24.7.1",
"@rollup/plugin-babel": "^5.2.2",
"@rollup/plugin-commonjs": "17.0.0",
"@rollup/plugin-eslint": "^8.0.1",
diff --git a/src/core/MultiViewRoot.js b/src/core/MultiViewRoot.js
new file mode 100644
index 0000000..c83f7bf
--- /dev/null
+++ b/src/core/MultiViewRoot.js
@@ -0,0 +1,183 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+import vtkRenderWindow from '@kitware/vtk.js/Rendering/Core/RenderWindow';
+import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor';
+import vtkOpenGLRenderWindow from '@kitware/vtk.js/Rendering/OpenGL/RenderWindow';
+
+// ----------------------------------------------------------------------------
+// Context to pass parent variables to children
+// ----------------------------------------------------------------------------
+
+export const MultiViewRootContext = React.createContext(null);
+
+export function removeKeys(props, propNames) {
+ const cleanedProps = { ...props };
+ propNames.forEach((name) => {
+ delete cleanedProps[name];
+ });
+ return cleanedProps;
+}
+
+// ----------------------------------------------------------------------------
+// Helper constants
+// ----------------------------------------------------------------------------
+
+const RENDERER_STYLE = {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ pointerEvents: 'none',
+};
+
+export default class MultiViewRoot extends Component {
+ constructor(props) {
+ super(props);
+ this.containerRef = React.createRef();
+
+ // Create vtk.js view
+ this.renderWindow = vtkRenderWindow.newInstance();
+ this.interactor = null;
+
+ this.renderWindowView = vtkOpenGLRenderWindow.newInstance();
+ this.renderWindow.addView(this.renderWindowView);
+
+ this.resizeObserver = new ResizeObserver((entries) => {
+ this.onResize();
+ });
+
+ this.interactor = vtkRenderWindowInteractor.newInstance();
+ this.interactor.setView(this.renderWindowView);
+
+ this.onResize = this.onResize.bind(this);
+
+ this.initialized = false;
+ }
+
+ componentDidMount() {
+ // TODO support runtime toggling of this flag?
+ if (!this.props.disabled) {
+ const container = this.containerRef.current;
+ this.renderWindowView.setContainer(container);
+
+ this.interactor.initialize();
+
+ this.resizeObserver.observe(container);
+ this.onResize();
+
+ this.initialized = true;
+
+ this.update(this.props);
+ }
+ }
+
+ componentDidUpdate(prevProps) {
+ this.update(this.props, prevProps);
+ }
+
+ componentWillUnmount() {
+ if (this.initialized) {
+ // Stop size listening
+ this.resizeObserver.disconnect();
+
+ if (this.interactor.getContainer()) {
+ this.interactor.unbindEvents();
+ }
+
+ this.renderWindowView.setContainer(null);
+ }
+
+ this.renderWindow.removeView(this.renderWindowView);
+
+ this.interactor.delete();
+ this.renderWindow.delete();
+ this.renderWindowView.delete();
+
+ this.interactor = null;
+ this.renderWindow = null;
+ this.renderWindowView = null;
+ }
+
+ render() {
+ const { id, children, style, disabled } = this.props;
+
+ return (
+
+ );
+ }
+
+ bindInteractorEvents(container) {
+ if (this.interactor) {
+ if (this.interactor.getContainer()) {
+ this.interactor.unbindEvents();
+ }
+ if (container) {
+ this.interactor.bindEvents(container);
+ }
+ }
+ }
+
+ onResize() {
+ const container = this.containerRef.current;
+ if (container) {
+ const devicePixelRatio = window.devicePixelRatio || 1;
+ const { width, height } = container.getBoundingClientRect();
+ const w = Math.floor(width * devicePixelRatio);
+ const h = Math.floor(height * devicePixelRatio);
+ this.renderWindowView.setSize(Math.max(w, 10), Math.max(h, 10));
+ this.renderWindow.render();
+ }
+ }
+
+ update(props, previous) {
+ const { triggerRender } = props;
+ // Allow to trigger method call from property change
+ if (previous && triggerRender !== previous.triggerRender) {
+ this.renderViewTimeout = setTimeout(this.renderWindow.render, 0);
+ }
+ }
+}
+
+MultiViewRoot.defaultProps = {
+ triggerRender: 0,
+ disabled: false,
+};
+
+export const propTypes = {
+ /**
+ * The ID used to identify this component.
+ */
+ id: PropTypes.string,
+
+ /**
+ * Property use to trigger a render when changing.
+ */
+ triggerRender: PropTypes.number,
+
+ /**
+ * Disables or enables the multi-renderer root.
+ */
+ disabled: PropTypes.bool,
+
+ /**
+ * List of representation to show
+ */
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ ]),
+};
+
+MultiViewRoot.propTypes = propTypes;
diff --git a/src/core/View.js b/src/core/View.js
index 8f29ce4..86503d0 100644
--- a/src/core/View.js
+++ b/src/core/View.js
@@ -7,17 +7,12 @@ import PropTypes from 'prop-types';
import { debounce } from '@kitware/vtk.js/macros.js';
-import vtkOpenGLRenderWindow from '@kitware/vtk.js/Rendering/OpenGL/RenderWindow.js';
-import vtkRenderWindow from '@kitware/vtk.js/Rendering/Core/RenderWindow.js';
-import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor.js';
-import vtkRenderer from '@kitware/vtk.js/Rendering/Core/Renderer.js';
-import vtkInteractorStyleManipulator from '@kitware/vtk.js/Interaction/Style/InteractorStyleManipulator.js';
-
import vtkBoundingBox from '@kitware/vtk.js/Common/DataModel/BoundingBox.js';
import vtkCubeAxesActor from '@kitware/vtk.js/Rendering/Core/CubeAxesActor.js';
import vtkAxesActor from '@kitware/vtk.js/Rendering/Core/AxesActor';
import vtkOrientationMarkerWidget from '@kitware/vtk.js/Interaction/Widgets/OrientationMarkerWidget';
+import vtkInteractorStyleManipulator from '@kitware/vtk.js/Interaction/Style/InteractorStyleManipulator.js';
// Style modes
import vtkMouseCameraTrackballMultiRotateManipulator from '@kitware/vtk.js/Interaction/Manipulators/MouseCameraTrackballMultiRotateManipulator.js';
@@ -132,22 +127,16 @@ export default class View extends Component {
this.containerRef = React.createRef();
// Create vtk.js view
- this.renderWindow = vtkRenderWindow.newInstance();
- this.renderer = vtkRenderer.newInstance();
- this.renderWindow.addRenderer(this.renderer);
+ this.renderWindow = props.renderWindow;
+ this.renderer = props.renderer;
this.camera = this.renderer.getActiveCamera();
- this.openglRenderWindow = vtkOpenGLRenderWindow.newInstance();
- this.renderWindow.addView(this.openglRenderWindow);
+ this.openglRenderWindow = props.renderWindowView;
if (props.interactive) {
- this.interactor = vtkRenderWindowInteractor.newInstance();
- this.interactor.setView(this.openglRenderWindow);
- this.interactor.initialize();
-
- // Interactor style
- this.style = vtkInteractorStyleManipulator.newInstance();
- this.interactor.setInteractorStyle(this.style);
+ this.interactor = props.interactor;
+ this.defaultStyle = vtkInteractorStyleManipulator.newInstance();
+ this.style = this.defaultStyle;
}
// Create orientation widget
@@ -155,8 +144,8 @@ export default class View extends Component {
this.orientationWidget = vtkOrientationMarkerWidget.newInstance({
actor: this.axesActor,
interactor: this.interactor,
+ parentRenderer: this.renderer,
});
- this.orientationWidget.setEnabled(true);
this.orientationWidget.setViewportCorner(
vtkOrientationMarkerWidget.Corners.BOTTOM_LEFT
);
@@ -204,6 +193,11 @@ export default class View extends Component {
};
this.debouncedCubeBounds = debounce(this.updateCubeBounds, 50);
+ this.setInteractorStyle = (style) => {
+ this.style = style;
+ this.interactor.setInteractorStyle(style);
+ };
+
// Internal functions
this.hasFocus = false;
this.handleKey = (e) => {
@@ -345,7 +339,7 @@ export default class View extends Component {
}
getScreenEventPositionFor(source) {
- const bounds = this.containerRef.current.getBoundingClientRect();
+ const bounds = this.openglRenderWindow.getCanvas().getBoundingClientRect();
const [canvasWidth, canvasHeight] = this.openglRenderWindow.getSize();
const scaleX = canvasWidth / bounds.width;
const scaleY = canvasHeight / bounds.height;
@@ -357,6 +351,10 @@ export default class View extends Component {
return position;
}
+ onResize() {
+ this.props.onResize();
+ }
+
render() {
const { id, children, style, className } = this.props;
@@ -373,35 +371,22 @@ export default class View extends Component {
onMouseMove={this.onMouseMove}
>
-
- {children}
-
+ {children}
);
}
- onResize() {
- const container = this.containerRef.current;
- if (container) {
- const devicePixelRatio = window.devicePixelRatio || 1;
- const { width, height } = container.getBoundingClientRect();
- const w = Math.floor(width * devicePixelRatio);
- const h = Math.floor(height * devicePixelRatio);
- this.openglRenderWindow.setSize(Math.max(w, 10), Math.max(h, 10));
- this.renderWindow.render();
- }
- }
-
componentDidMount() {
const container = this.containerRef.current;
- this.openglRenderWindow.setContainer(container);
- if (this.props.interactive) {
- this.interactor.bindEvents(container);
- }
this.onResize();
this.resizeObserver.observe(container);
- this.update(this.props);
document.addEventListener('keyup', this.handleKey);
+
+ // Assign the mouseDown event, we can't use the React event system
+ // because the mouseDown event is swallowed by other logic
+ container.addEventListener('mousedown', this.onMouseDown);
+
+ this.update(this.props);
this.resetCamera();
// Give a chance for the first layout to properly reset the camera
@@ -423,34 +408,23 @@ export default class View extends Component {
this.subscriptions.pop().unsubscribe();
}
+ const container = this.containerRef.current;
+ container.removeEventListener('mousedown', this.onMouseDown);
+
document.removeEventListener('keyup', this.handleKey);
// Stop size listening
this.resizeObserver.disconnect();
this.resizeObserver = null;
- // Detatch from DOM
- if (this.interactor) {
- this.interactor.unbindEvents();
- }
- this.openglRenderWindow.setContainer(null);
+ this.selector.delete();
+ this.orientationWidget.delete();
+ this.defaultStyle.delete();
- // Free memory
- this.renderWindow.removeRenderer(this.renderer);
- this.renderWindow.removeView(this.openglRenderWindow);
-
- if (this.interactor) {
- this.interactor.delete();
- this.interactor = null;
- }
-
- this.renderer.delete();
+ this.defaultStyle = null;
+ this.style = null;
this.renderer = null;
-
- this.renderWindow.delete();
- this.renderWindow = null;
-
- this.openglRenderWindow.delete();
- this.openglRenderWindow = null;
+ this.selector = null;
+ this.orientationWidget = null;
}
update(props, previous) {
@@ -527,11 +501,6 @@ export default class View extends Component {
if (previous && triggerResetCamera !== previous.triggerResetCamera) {
this.resetCameraTimeout = setTimeout(this.resetCamera, 0);
}
-
- // Assign the mouseDown event, we can't use the React event system
- // because the mouseDown event is swallowed by other logic
- const canvas = this.openglRenderWindow.getCanvas();
- canvas.addEventListener('mousedown', this.onMouseDown);
}
resetCamera() {
diff --git a/src/core/ViewContainer.js b/src/core/ViewContainer.js
new file mode 100644
index 0000000..90bee5b
--- /dev/null
+++ b/src/core/ViewContainer.js
@@ -0,0 +1,170 @@
+import React, { Component } from 'react';
+
+import vtkOpenGLRenderWindow from '@kitware/vtk.js/Rendering/OpenGL/RenderWindow.js';
+import vtkRenderWindow from '@kitware/vtk.js/Rendering/Core/RenderWindow.js';
+import vtkRenderWindowInteractor from '@kitware/vtk.js/Rendering/Core/RenderWindowInteractor.js';
+import vtkRenderer from '@kitware/vtk.js/Rendering/Core/Renderer.js';
+
+import View from './View';
+import { MultiViewRootContext } from './MultiViewRoot';
+
+class ViewController extends Component {
+ constructor(props) {
+ super(props);
+
+ this.renderer = vtkRenderer.newInstance();
+ this.viewRef = React.createRef();
+
+ if (props.root) {
+ this.renderWindow = props.root.renderWindow;
+ this.openglRenderWindow = props.root.renderWindowView;
+ this.interactor = props.root.interactor;
+ } else {
+ this.renderWindow = vtkRenderWindow.newInstance();
+ this.openglRenderWindow = vtkOpenGLRenderWindow.newInstance();
+ }
+
+ this.onEnter = this.onEnter.bind(this);
+ this.onResize = this.onResize.bind(this);
+ }
+
+ componentDidMount() {
+ if (!this.props.root) {
+ this.renderWindow.addView(this.openglRenderWindow);
+
+ this.interactor = vtkRenderWindowInteractor.newInstance();
+ if (this.props.interactive) {
+ this.interactor.setView(this.openglRenderWindow);
+ this.interactor.initialize();
+ }
+ }
+ this.renderWindow.addRenderer(this.renderer);
+
+ const view = this.viewRef.current;
+ const container = view.containerRef.current;
+ container.addEventListener('pointerenter', this.onEnter);
+
+ if (!this.props.root) {
+ this.openglRenderWindow.setContainer(container);
+ if (this.props.interactive) {
+ this.interactor.bindEvents(container);
+ }
+ this.interactor.setInteractorStyle(view.style);
+ }
+ }
+
+ componentWillUnmount() {
+ const view = this.viewRef.current;
+ const container = view.containerRef.current;
+ container.removeEventListener('pointerenter', this.onEnter);
+
+ // MultiViewRoot parent may delete the render window first in WillUnmount.
+ if (!this.renderWindow.isDeleted()) {
+ this.renderWindow.removeRenderer(this.renderer);
+ }
+
+ if (this.props.root) {
+ this.bindInteractorEvents(null);
+ } else {
+ // Detatch from DOM
+ if (this.interactor.getContainer()) {
+ this.interactor.unbindEvents();
+ }
+ this.openglRenderWindow.setContainer(null);
+
+ if (!this.renderWindow.isDeleted()) {
+ this.renderWindow.removeView(this.openglRenderWindow);
+ this.renderWindow.delete();
+ }
+
+ this.interactor.delete();
+ this.openglRenderWindow.delete();
+ }
+
+ this.renderer.delete();
+
+ this.interactor = null;
+ this.renderWindow = null;
+ this.openglRenderWindow = null;
+ }
+
+ render() {
+ const filteredProps = { ...this.props };
+ delete filteredProps.root;
+
+ return (
+
+ );
+ }
+
+ bindInteractorEvents(el) {
+ const oldContainer = this.interactor.getContainer();
+ if (oldContainer !== el) {
+ if (oldContainer) {
+ this.interactor.unbindEvents();
+ }
+ if (el) {
+ this.interactor.bindEvents(el);
+ }
+ }
+ }
+
+ onEnter() {
+ const view = this.viewRef.current;
+ const container = view?.containerRef.current;
+ if (this.props.root && container) {
+ this.bindInteractorEvents(container);
+ this.interactor.setCurrentRenderer(this.renderer);
+ this.interactor.setInteractorStyle(view.style);
+ }
+ }
+
+ onResize() {
+ const container = this.viewRef.current?.containerRef.current;
+ if (container) {
+ if (this.props.root) {
+ const containerBox = container.getBoundingClientRect();
+ const canvasBox = this.openglRenderWindow
+ .getCanvas()
+ .getBoundingClientRect();
+
+ // relative to canvas
+ const top = containerBox.top - canvasBox.top;
+ const left = containerBox.left - canvasBox.left;
+
+ const xmin = left / canvasBox.width;
+ const xmax = (left + containerBox.width) / canvasBox.width;
+ const ymin = 1 - (top + containerBox.height) / canvasBox.height;
+ const ymax = 1 - top / canvasBox.height;
+
+ this.renderer.setViewport(xmin, ymin, xmax, ymax);
+ } else {
+ const devicePixelRatio = window.devicePixelRatio || 1;
+ const { width, height } = container.getBoundingClientRect();
+ const w = Math.floor(width * devicePixelRatio);
+ const h = Math.floor(height * devicePixelRatio);
+ this.openglRenderWindow.setSize(Math.max(w, 10), Math.max(h, 10));
+ this.renderWindow.render();
+ }
+ }
+ }
+}
+
+ViewController.defaultProps = View.defaultProps;
+ViewController.propTypes = View.propTypes;
+
+export default function ViewContainer(props) {
+ return (
+
+ {(root) => }
+
+ );
+}
diff --git a/src/core/index.js b/src/core/index.js
index e646c07..bc371ed 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -5,7 +5,7 @@ import vtkPointData from './PointData';
import vtkPolyData from './PolyData';
import vtkReader from './Reader';
import vtkShareDataSet from './ShareDataSet';
-import vtkView from './View';
+import vtkView from './ViewContainer';
import vtkGeometryRepresentation from './GeometryRepresentation';
import vtkGeometry2DRepresentation from './Geometry2DRepresentation';
import vtkGlyphRepresentation from './GlyphRepresentation';
@@ -15,6 +15,7 @@ import vtkFieldData from './FieldData';
import vtkAlgorithm from './Algorithm';
import vtkCalculator from './Calculator';
import vtkCellData from './CellData';
+import vtkMultiViewRoot from './MultiViewRoot';
export const VolumeRepresentation = vtkVolumeRepresentation;
export const SliceRepresentation = vtkSliceRepresentation;
@@ -33,6 +34,7 @@ export const FieldData = vtkFieldData;
export const Algorithm = vtkAlgorithm;
export const Calculator = vtkCalculator;
export const CellData = vtkCellData;
+export const MultiViewRoot = vtkMultiViewRoot;
export default {
VolumeRepresentation: vtkVolumeRepresentation,
@@ -52,4 +54,5 @@ export default {
Algorithm: vtkAlgorithm,
Calculator: vtkCalculator,
CellData: vtkCellData,
+ MultiViewRoot: vtkMultiViewRoot,
};
diff --git a/src/index.js b/src/index.js
index c077c6c..9b99d12 100644
--- a/src/index.js
+++ b/src/index.js
@@ -31,6 +31,7 @@ export const FieldData = Core.FieldData;
export const Algorithm = Core.Algorithm;
export const Calculator = Core.Calculator;
export const CellData = Core.CellData;
+export const MultiViewRoot = Core.MultiViewRoot;
// Representations
export const PointCloudRepresentation =
diff --git a/usage/src/App.jsx b/usage/src/App.jsx
index 8401802..2d435b7 100644
--- a/usage/src/App.jsx
+++ b/usage/src/App.jsx
@@ -17,6 +17,7 @@ const SyntheticVolumeRendering = lazy(() =>
);
const VolumeRendering = lazy(() => import('./Volume/VolumeRendering'));
const DynamicUpdate = lazy(() => import('./Volume/DynamicUpdate'));
+const MultiView = lazy(() => import('./MultiView'));
const demos = [
'Geometry/Picking',
@@ -32,6 +33,7 @@ const demos = [
'Volume/SyntheticVolumeRendering',
'Volume/VolumeRendering',
'Volume/DynamicUpdate',
+ 'MultiView',
];
function App() {
@@ -93,6 +95,7 @@ function App() {
)}
{example === 'Volume/VolumeRendering' && }
{example === 'Volume/DynamicUpdate' && }
+ {example === 'MultiView' && }
>
diff --git a/usage/src/Geometry/CubeAxes.jsx b/usage/src/Geometry/CubeAxes.jsx
index 530d3b8..cc4f90b 100644
--- a/usage/src/Geometry/CubeAxes.jsx
+++ b/usage/src/Geometry/CubeAxes.jsx
@@ -30,7 +30,7 @@ function Example(props) {
zIndex: 1,
};
return (
-
+
diff --git a/usage/src/Geometry/CutterExample.jsx b/usage/src/Geometry/CutterExample.jsx
index fa654bc..cf0faa2 100644
--- a/usage/src/Geometry/CutterExample.jsx
+++ b/usage/src/Geometry/CutterExample.jsx
@@ -11,7 +11,7 @@ function Example(props) {
});
return (
-
+
+
+
+
+
+
+
+
+
diff --git a/usage/src/Geometry/TubeExample.jsx b/usage/src/Geometry/TubeExample.jsx
index 5a0e06e..e4d3f9c 100644
--- a/usage/src/Geometry/TubeExample.jsx
+++ b/usage/src/Geometry/TubeExample.jsx
@@ -8,7 +8,7 @@ import {
function Example(props) {
return (
-
+
+
+
+ );
+}
+
+export default Example;
diff --git a/usage/src/Volume/DynamicRepUpdate.jsx b/usage/src/Volume/DynamicRepUpdate.jsx
index 85fb07d..429fff1 100644
--- a/usage/src/Volume/DynamicRepUpdate.jsx
+++ b/usage/src/Volume/DynamicRepUpdate.jsx
@@ -76,7 +76,7 @@ function Example(props) {
const colorLevel = fieldIdx ? 5 : 0.5;
return (
-
+
diff --git a/usage/src/Volume/DynamicUpdate.jsx b/usage/src/Volume/DynamicUpdate.jsx
index b453a8b..7d109b6 100644
--- a/usage/src/Volume/DynamicUpdate.jsx
+++ b/usage/src/Volume/DynamicUpdate.jsx
@@ -76,7 +76,7 @@ function Example(props) {
const colorLevel = fieldIdx ? 5 : 0.5;
return (
-
+
diff --git a/usage/src/Volume/SliceRendering.jsx b/usage/src/Volume/SliceRendering.jsx
index 7bf4b8e..b0c3d75 100644
--- a/usage/src/Volume/SliceRendering.jsx
+++ b/usage/src/Volume/SliceRendering.jsx
@@ -116,8 +116,8 @@ function Example(props) {
const [useLookupTableScalarRange, setUseLookupTableScalarRange] =
useState(false);
return (
-