Skip to content

Commit a1fe1ea

Browse files
committed
docs(usage): add ImageSeriesRendering example
1 parent 9aff778 commit a1fe1ea

2 files changed

Lines changed: 58 additions & 38 deletions

File tree

usage/src/App.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ const demos = new Map([
2929
// ],
3030
// ['Volume/VolumeRendering', lazy(() => import('./Volume/VolumeRendering'))],
3131
// ['Volume/DynamicUpdate', lazy(() => import('./Volume/DynamicUpdate'))],
32+
[
33+
'Volume/ImageSeriesRendering',
34+
lazy(() => import('./Volume/ImageSeriesRendering')),
35+
],
3236
['Tests/PropertyUpdate', lazy(() => import('./Tests/PropertyUpdate'))],
3337
['Tests/CameraTest', lazy(() => import('./Tests/CameraTest'))],
3438
['Tests/ShareGeometry', lazy(() => import('./Tests/ShareGeometry'))],

usage/src/Volume/ImageSeriesRendering.jsx

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
import React, { useState, useContext, useEffect } from 'react';
2-
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps.js';
31
import vtkCollection from '@kitware/vtk.js/Common/DataModel/Collection';
4-
import vtkImageArrayMapper from '@kitware/vtk.js/Rendering/Core/ImageArrayMapper.js';
5-
import vtkResourceLoader from '@kitware/vtk.js/IO/Core/ResourceLoader';
2+
import vtkITKHelper from '@kitware/vtk.js/Common/DataModel/ITKHelper';
63
import vtkLiteHttpDataAccessHelper from '@kitware/vtk.js/IO/Core/DataAccessHelper/LiteHttpDataAccessHelper';
4+
import vtkResourceLoader from '@kitware/vtk.js/IO/Core/ResourceLoader';
5+
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps.js';
6+
import vtkImageArrayMapper from '@kitware/vtk.js/Rendering/Core/ImageArrayMapper.js';
77
import { unzipSync } from 'fflate';
8-
import vtkITKHelper from '@kitware/vtk.js/Common/DataModel/ITKHelper';
8+
import { useContext, useEffect, useMemo, useState } from 'react';
99

1010
import {
11-
View,
11+
Contexts,
1212
Dataset,
13-
ShareDataSet,
13+
RegisterDataSet,
14+
ShareDataSetRoot,
1415
SliceRepresentation,
15-
Contexts,
16+
UseDataSet,
17+
View,
1618
} from 'react-vtk-js';
1719

1820
function Slider(props) {
@@ -110,13 +112,11 @@ function CheckBox(props) {
110112
);
111113
}
112114

113-
114115
const loadData = async () => {
115116
console.log('Loading itk module...');
116117
loadData.setStatusText('Loading itk module...');
117-
if(!window.itk) {
118-
await vtkResourceLoader
119-
.loadScript(
118+
if (!window.itk) {
119+
await vtkResourceLoader.loadScript(
120120
'https://cdn.jsdelivr.net/npm/itk-wasm@1.0.0-b.8/dist/umd/itk-wasm.js'
121121
);
122122
}
@@ -144,7 +144,7 @@ const loadData = async () => {
144144

145145
// Read individual dcm files into an array of vtkImageData.
146146
const imageArray = [];
147-
if(window.itk) {
147+
if (window.itk) {
148148
await Promise.all(
149149
dcmFiles.map(async (filename, index) => {
150150
const { image: itkImage, webWorker } =
@@ -167,12 +167,13 @@ const loadData = async () => {
167167
collection.addItem(img);
168168
}
169169
const totalSlices = imageArray.reduce(
170-
(accumulator, currImage) => currImage.getDimensions()[2] + accumulator, 0
170+
(accumulator, currImage) => currImage.getDimensions()[2] + accumulator,
171+
0
171172
);
172173
loadData.setMaxSlicingValue(totalSlices - 1);
173174
loadData.setStatusText('');
174175
return collection;
175-
}
176+
};
176177

177178
function Example(props) {
178179
const [statusText, setStatusText] = useState('Loading data, please wait ...');
@@ -187,34 +188,50 @@ function Example(props) {
187188
loadData.setMaxSlicingValue = setMaxKSlice;
188189
loadData.setStatusText = setStatusText;
189190

190-
useEffect(
191-
() => {
192-
const img = mapper.getImage(kSlice);
193-
const range = img?.getPointData()?.getScalars()?.getRange();
194-
if(range && range.length == 2) {
195-
const maxWidth = range[1] - range[0];
196-
setColorWindow(maxWidth);
197-
const center = Math.round((range[0] + range[1]) / 2);
198-
setColorLevel(center);
199-
}
200-
},
201-
[kSlice]
191+
const [imageCollection, setImageCollection] = useState(null);
192+
193+
useEffect(() => {
194+
loadData().then((ds) => {
195+
window.ds = ds;
196+
setImageCollection(ds);
197+
});
198+
}, []);
199+
200+
useEffect(() => {
201+
const img = mapper.getImage(kSlice);
202+
const range = img?.getPointData()?.getScalars()?.getRange();
203+
if (range && range.length == 2) {
204+
const maxWidth = range[1] - range[0];
205+
setColorWindow(maxWidth);
206+
const center = Math.round((range[0] + range[1]) / 2);
207+
setColorLevel(center);
208+
}
209+
}, [kSlice, mapper]);
210+
211+
const cameraParams = useMemo(
212+
() => ({
213+
position: [400, 400, -1000],
214+
viewUp: [0, -1, 0],
215+
viewAngle: 75,
216+
directionOfProjection: [0, 0, 1],
217+
clippingRange: [-100, 100],
218+
parallelProjection: false,
219+
}),
220+
[]
202221
);
203222

204223
return (
205224
<div style={{ width: '100%', height: '100%' }}>
225+
<ShareDataSetRoot>
226+
<RegisterDataSet id='mixedImages'>
227+
<Dataset dataset={imageCollection} />
228+
</RegisterDataSet>
206229
<View
207230
id='0'
208-
cameraPosition={[0, 0, -1]}
209-
cameraViewUp={[0, -1, 0]}
210-
cameraParallelProjection={false}
231+
autoResetCamera={false}
232+
camera={cameraParams}
211233
background={[65 / 255, 86 / 255, 122 / 255]}
212234
>
213-
<ShareDataSet
214-
name='mixedImages'
215-
>
216-
<Dataset fetchData={loadData} />
217-
</ShareDataSet>
218235
<label
219236
style={{
220237
position: 'absolute',
@@ -269,11 +286,10 @@ function Example(props) {
269286
}}
270287
colorMapPreset={colorPreset}
271288
>
272-
<ShareDataSet
273-
name='mixedImages'
274-
/>
289+
<UseDataSet id='mixedImages' />
275290
</SliceRepresentation>
276291
</View>
292+
</ShareDataSetRoot>
277293
</div>
278294
);
279295
}

0 commit comments

Comments
 (0)