Skip to content

Commit 6de3536

Browse files
committed
Add propTypes, sliceNormal prop
1 parent 8d1a0b1 commit 6de3536

File tree

7 files changed

+211
-50
lines changed

7 files changed

+211
-50
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ npm-debug.log*
1818
yarn-debug.log*
1919
yarn-error.log*
2020
.idea
21+
.yalc
22+
yalc.lock
23+
package-lock.json

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,6 @@
8484
"dependencies": {
8585
"cornerstone-core": "^2.2.8",
8686
"cornerstone-math": "^0.1.8",
87-
"vtk.js": "^8.3.10"
87+
"vtk.js": "^8.3.11"
8888
}
8989
}

src/Custom/VTKMPRViewport.js

+65-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React from 'react';
2-
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
33
import vtkGenericRenderWindow from 'vtk.js/Sources/Rendering/Misc/GenericRenderWindow';
44
import vtkWidgetManager from 'vtk.js/Sources/Widgets/Core/WidgetManager';
55
import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume';
@@ -10,16 +10,19 @@ import vtkPaintWidget from 'vtk.js/Sources/Widgets/Widgets3D/PaintWidget';
1010
import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction';
1111
import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction';
1212

13+
import ViewportOverlay from '../ViewportOverlay/ViewportOverlay.js';
1314
import { ViewTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants';
14-
1515
import { createSub } from './util';
1616

1717
function createPipeline() {
18-
const mapper = vtkVolumeMapper.newInstance();
19-
const actor = vtkVolume.newInstance();
20-
actor.setMapper(mapper);
18+
const data = {
19+
mapper: vtkVolumeMapper.newInstance(),
20+
actor: vtkVolume.newInstance()
21+
};
22+
23+
data.actor.setMapper(data.mapper);
2124

22-
return { mapper, actor };
25+
return data;
2326
}
2427

2528
function createLabelPipeline() {
@@ -44,7 +47,23 @@ function createLabelPipeline() {
4447
return labelMap;
4548
}
4649

47-
export default class VtkMpr extends React.Component {
50+
export default class VtkMpr extends Component {
51+
static propTypes = {
52+
data: PropTypes.object.isRequired,
53+
painting: PropTypes.bool.isRequired,
54+
labelmap: PropTypes.object,
55+
onPaint: PropTypes.func,
56+
onPaintStart: PropTypes.func,
57+
onPaintEnd: PropTypes.func,
58+
sliceNormal: PropTypes.array.isRequired,
59+
dataDetails: PropTypes.object
60+
};
61+
62+
static defaultProps = {
63+
painting: false,
64+
sliceNormal: [0, 0, 1]
65+
};
66+
4867
constructor(props) {
4968
super(props);
5069

@@ -99,6 +118,7 @@ export default class VtkMpr extends React.Component {
99118
this.renderWindow = this.genericRenderer.getRenderWindow();
100119

101120
const istyle = vtkInteractorStyleMPRSlice.newInstance();
121+
this.istyle = istyle;
102122
this.renderWindow.getInteractor().setInteractorStyle(istyle);
103123

104124
this.pipeline = createPipeline();
@@ -143,6 +163,7 @@ export default class VtkMpr extends React.Component {
143163

144164
if (!prevProps.data && this.props.data) {
145165
this.renderer.addVolume(this.pipeline.actor);
166+
146167
// re-render if data has updated
147168
this.subs.data.sub(
148169
this.props.data.onModified(() => this.renderWindow.render())
@@ -221,6 +242,16 @@ export default class VtkMpr extends React.Component {
221242
this.viewWidget = null;
222243
}
223244
}
245+
246+
if (prevProps.sliceNormal !== this.props.sliceNormal) {
247+
const istyle = this.istyle;
248+
istyle.setSliceNormal(...this.props.sliceNormal);
249+
250+
const range = istyle.getSliceRange();
251+
istyle.setSlice((range[0] + range[1]) / 2);
252+
253+
this.renderWindow.render();
254+
}
224255
}
225256

226257
componentWillUnmount() {
@@ -231,6 +262,31 @@ export default class VtkMpr extends React.Component {
231262

232263
render() {
233264
const style = { width: '100%', height: '100%' };
234-
return <div ref={this.container} style={style} />;
265+
266+
let voi = {
267+
windowCenter: 0,
268+
windowWidth: 0
269+
};
270+
if (this.pipeline) {
271+
const actor = this.pipeline.actor;
272+
273+
// Note: This controls window/level
274+
const rgbTransferFunction = actor.getProperty().getRGBTransferFunction(0);
275+
const range = rgbTransferFunction.getMappingRange();
276+
const windowWidth = range[0] + range[1];
277+
const windowCenter = range[0] + windowWidth / 2;
278+
279+
voi = {
280+
windowCenter,
281+
windowWidth
282+
};
283+
}
284+
285+
return (
286+
<div style={style}>
287+
<div ref={this.container} style={style} />
288+
<ViewportOverlay {...this.props.dataDetails} voi={voi} />
289+
</div>
290+
);
235291
}
236292
}
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
:root {
2+
--viewport-tag-padding: 20px;
3+
}
4+
5+
.ViewportOverlay {
6+
color: #9ccef9;
7+
8+
.overlay-element {
9+
position: absolute;
10+
font-weight: 400;
11+
text-shadow: 1px 1px black;
12+
pointer-events: none;
13+
}
14+
15+
.top-left {
16+
top: var(--viewport-tag-padding);
17+
left: var(--viewport-tag-padding);
18+
}
19+
20+
.top-center {
21+
top: var(--viewport-tag-padding);
22+
padding-top: var(--viewport-tag-padding);
23+
width: 100%;
24+
text-align: center;
25+
}
26+
27+
.top-right {
28+
top: var(--viewport-tag-padding);
29+
right: var(--viewport-tag-padding);
30+
text-align: right;
31+
}
32+
33+
.bottom-left {
34+
bottom: var(--viewport-tag-padding);
35+
left: var(--viewport-tag-padding);
36+
}
37+
38+
.bottom-right {
39+
bottom: var(--viewport-tag-padding);
40+
right: var(--viewport-tag-padding);
41+
text-align: right;
42+
}
43+
44+
svg {
45+
color: #9ccef9;
46+
fill: #9ccef9;
47+
stroke: #9ccef9;
48+
background-color: transparent;
49+
margin: 2px;
50+
width: 18px;
51+
height: 18px;
52+
}
53+
}
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { PureComponent } from 'react';
2+
import React from 'react';
3+
import PropTypes from 'prop-types';
4+
import { helpers } from '../helpers/index.js';
5+
import './ViewportOverlay.css';
6+
7+
const {
8+
formatPN,
9+
formatDA,
10+
formatNumberPrecision,
11+
formatTM,
12+
isValidNumber
13+
} = helpers;
14+
15+
class ViewportOverlay extends PureComponent {
16+
static propTypes = {
17+
voi: PropTypes.object.isRequired,
18+
studyDate: PropTypes.string,
19+
studyTime: PropTypes.string,
20+
studyDescription: PropTypes.string,
21+
patientName: PropTypes.string,
22+
patientId: PropTypes.string,
23+
seriesNumber: PropTypes.string,
24+
seriesDescription: PropTypes.string
25+
};
26+
27+
static defaultProps = {
28+
voi: {
29+
windowWidth: 0,
30+
windowCenter: 0
31+
}
32+
};
33+
34+
render() {
35+
const {
36+
studyDate,
37+
studyTime,
38+
studyDescription,
39+
patientName,
40+
patientId,
41+
seriesNumber,
42+
seriesDescription,
43+
voi
44+
} = this.props;
45+
const { windowWidth, windowCenter } = voi;
46+
const wwwc = `W: ${windowWidth.toFixed(0)} L: ${windowCenter.toFixed(0)}`;
47+
48+
return (
49+
<div className="ViewportOverlay">
50+
<div className="top-left overlay-element">
51+
<div>{formatPN(patientName)}</div>
52+
<div>{patientId}</div>
53+
</div>
54+
<div className="top-right overlay-element">
55+
<div>{studyDescription}</div>
56+
<div>
57+
{formatDA(studyDate)} {formatTM(studyTime)}
58+
</div>
59+
</div>
60+
<div className="bottom-right overlay-element">
61+
<div>{wwwc}</div>
62+
</div>
63+
<div className="bottom-left overlay-element">
64+
<div>{seriesNumber >= 0 ? `Ser: ${seriesNumber}` : ''}</div>
65+
<div>
66+
<div>{seriesDescription}</div>
67+
</div>
68+
</div>
69+
</div>
70+
);
71+
}
72+
}
73+
74+
export default ViewportOverlay;

src/index.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
import VTKViewport from './VTKViewport/VTKViewport';
2+
import ViewportOverlay from './ViewportOverlay/ViewportOverlay.js';
23
import VTKMPRViewport from './Custom/VTKMPRViewport';
34
import getImageData from './lib/getImageData.js';
45
import loadImageData from './lib/loadImageData.js';
56

6-
export { VTKViewport, VTKMPRViewport, getImageData, loadImageData };
7+
export {
8+
VTKViewport,
9+
VTKMPRViewport,
10+
ViewportOverlay,
11+
getImageData,
12+
loadImageData
13+
};
714

815
export default VTKViewport;

yarn.lock

+7-39
Original file line numberDiff line numberDiff line change
@@ -3719,7 +3719,7 @@ debug@~4.1.0:
37193719
dependencies:
37203720
ms "^2.1.1"
37213721

3722-
debuglog@*, debuglog@^1.0.1:
3722+
debuglog@^1.0.1:
37233723
version "1.0.1"
37243724
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
37253725
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
@@ -6373,7 +6373,7 @@ import-local@^2.0.0:
63736373
pkg-dir "^3.0.0"
63746374
resolve-cwd "^2.0.0"
63756375

6376-
imurmurhash@*, imurmurhash@^0.1.4:
6376+
imurmurhash@^0.1.4:
63776377
version "0.1.4"
63786378
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
63796379
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
@@ -7644,11 +7644,6 @@ lockfile@^1.0.4:
76447644
dependencies:
76457645
signal-exit "^3.0.2"
76467646

7647-
lodash._baseindexof@*:
7648-
version "3.1.0"
7649-
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
7650-
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=
7651-
76527647
lodash._baseuniq@~4.6.0:
76537648
version "4.6.0"
76547649
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
@@ -7657,33 +7652,11 @@ lodash._baseuniq@~4.6.0:
76577652
lodash._createset "~4.0.0"
76587653
lodash._root "~3.0.0"
76597654

7660-
lodash._bindcallback@*:
7661-
version "3.0.1"
7662-
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
7663-
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
7664-
7665-
lodash._cacheindexof@*:
7666-
version "3.0.2"
7667-
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
7668-
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=
7669-
7670-
lodash._createcache@*:
7671-
version "3.1.2"
7672-
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
7673-
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
7674-
dependencies:
7675-
lodash._getnative "^3.0.0"
7676-
76777655
lodash._createset@~4.0.0:
76787656
version "4.0.3"
76797657
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
76807658
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
76817659

7682-
lodash._getnative@*, lodash._getnative@^3.0.0:
7683-
version "3.9.1"
7684-
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
7685-
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
7686-
76877660
lodash._reinterpolate@~3.0.0:
76887661
version "3.0.0"
76897662
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
@@ -7754,11 +7727,6 @@ lodash.map@^4.5.1:
77547727
resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
77557728
integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=
77567729

7757-
lodash.restparam@*:
7758-
version "3.6.1"
7759-
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
7760-
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
7761-
77627730
lodash.set@^4.3.2:
77637731
version "4.3.2"
77647732
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
@@ -10704,7 +10672,7 @@ readable-stream@~2.0.6:
1070410672
string_decoder "~0.10.x"
1070510673
util-deprecate "~1.0.1"
1070610674

10707-
readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0:
10675+
readdir-scoped-modules@^1.0.0:
1070810676
version "1.0.2"
1070910677
resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747"
1071010678
integrity sha1-n6+jfShr5dksuuve4DDcm19AZ0c=
@@ -13079,10 +13047,10 @@ [email protected]:
1307913047
dependencies:
1308013048
indexof "0.0.1"
1308113049

13082-
vtk.js@^8.3.10:
13083-
version "8.3.10"
13084-
resolved "https://registry.yarnpkg.com/vtk.js/-/vtk.js-8.3.10.tgz#d5f99940ea46b7f54de49bce3482b9afb7c3ca83"
13085-
integrity sha512-pF71oKAjfMNKiP3RNw49dgT3Y50zSwAfCqM4Z1+ggx+So8Nf/0XZZe7I8SV+t/QntX8NaSzvbRDxG/fqnRrZ8w==
13050+
vtk.js@^8.3.11:
13051+
version "8.3.11"
13052+
resolved "https://registry.yarnpkg.com/vtk.js/-/vtk.js-8.3.11.tgz#a9fba3995bb4db805ec18a3275428dd857d0a229"
13053+
integrity sha512-XoFbR9KYuk0oSYzmcEQvwIs3L+kN+gny+cqRZV1mP8r7B/5JyQhWKIogYBYSZaGU/fCsROKk/ZtfyqV/idI+HQ==
1308613054
dependencies:
1308713055
base64-js "1.2.1"
1308813056
blueimp-md5 "2.10.0"

0 commit comments

Comments
 (0)