@niivue/niivue 0.44.1 → 0.44.2-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,333 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
+ <meta name="viewport" content="width=device-width,initial-scale=1.0" />
7
+ <title>Bidirectional Sync</title>
8
+ <style>
9
+ html {
10
+ height: auto;
11
+ min-height: 100%;
12
+ margin: 0;
13
+ }
14
+ body {
15
+ display: flex;
16
+ flex-direction: column;
17
+ margin: 0;
18
+ min-height: 100%;
19
+ width: 100%;
20
+ position: absolute;
21
+ font-family: system-ui, Arial, Helvetica, sans-serif;
22
+ user-select: none; /* Standard syntax */
23
+ color: white;
24
+ background: #202020;
25
+ }
26
+ header {
27
+ margin: 10px;
28
+ }
29
+ footer {
30
+ margin: 5px;
31
+ }
32
+ .page-wrapper {
33
+ margin: 2px;
34
+ }
35
+ .row {
36
+ display: flex;
37
+ flex-direction: row;
38
+ flex-wrap: wrap;
39
+ width: 100%;
40
+ min-height: 100%;
41
+ margin: 2px;
42
+ }
43
+ .column {
44
+ display: flex;
45
+ flex-direction: column;
46
+ flex-basis: 100%;
47
+ flex: 1;
48
+ background: #404040;
49
+ }
50
+ canvas:focus {
51
+ outline: red 1px solid;
52
+ }
53
+ </style>
54
+ </head>
55
+ <body>
56
+ <noscript>niivue requires JavaScript.</noscript>
57
+ <header>
58
+ <label for="layout">Layout</label>
59
+ <select id="layout">
60
+ <option value="0" selected>Auto</option>
61
+ <option value="1">Column</option>
62
+ <option value="2">Grid</option>
63
+ <option value="3">Row</option>
64
+ </select>
65
+ <label for="canvasHeight">Height</label>
66
+ <select id="canvasHeight">
67
+ <option value="256">256</option>
68
+ <option value="640" selected>512</option>
69
+ <option value="768">768</option>
70
+ </select>
71
+ <label for="syncDrop"> Broadcast</label>
72
+ <select id="syncDrop">
73
+ <option value="disabled">Sync Disabled</option>
74
+ <option value="2d">Sync 2D</option>
75
+ <option value="3d">Sync 3D</option>
76
+ <option value="crosshair" selected>crosshair</option>
77
+ <option value="zoomPan">zoomPan</option>
78
+ <option value="gamma">gamma</option>
79
+ <option value="sliceType">sliceType</option>
80
+ <option value="clipPlane">clipPlane</option>
81
+ <option value="cal_min">cal_min</option>
82
+ <option value="cal_max">cal_max</option>
83
+ <!-- everything -->
84
+ <option value="all">all except intensity</option>
85
+ </select>
86
+ <!-- slider for gamma -->
87
+ <label for="gammaSlider">Gamma</label>
88
+ <input
89
+ type="range"
90
+ min="10"
91
+ max="400"
92
+ value="100"
93
+ class="slider"
94
+ id="gammaSlider"
95
+ />
96
+ <!-- sliceType select -->
97
+ <label for="sliceType">Slice Type</label>
98
+ <select id="sliceType">
99
+ <option value="0">Axial</option>
100
+ <option value="1">Coronal</option>
101
+ <option value="2">Sagittal</option>
102
+ <option value="3" selected>Multi</option>
103
+ </select>
104
+
105
+ <!-- slider for cal_min -->
106
+ <label for="calMin">min</label>
107
+ <input
108
+ type="range"
109
+ min="0"
110
+ max="100"
111
+ value="0"
112
+ class="slider"
113
+ id="calMin"
114
+ />
115
+ <!-- slider for cal_max -->
116
+ <label for="calMax">max</label>
117
+ <input
118
+ type="range"
119
+ min="0"
120
+ max="100"
121
+ value="100"
122
+ class="slider"
123
+ id="calMax"
124
+ />
125
+ </header>
126
+ <main>
127
+ <div class='page-wrapper'>
128
+ <div class='row'>
129
+ <div class='column'>
130
+ <div>
131
+ <canvas id="gl1" height="512">
132
+ </div>
133
+ </div>
134
+ <div class='column'>
135
+ <div>
136
+ <canvas id="gl2" height="512">
137
+ </div>
138
+ </div>
139
+ <div class='column'>
140
+ <div>
141
+ <canvas id="gl3" height="512">
142
+ </div>
143
+ </div>
144
+ </div>
145
+ </div>
146
+ </main>
147
+ <footer>
148
+ <x id="intensity"> &nbsp;</x>
149
+ <x id="intensity2"> &nbsp;</x>
150
+ <x id="intensity3"> &nbsp;</x>
151
+ </footer>
152
+ <script type="module" async>
153
+ import {
154
+ Niivue,
155
+ NVImage,
156
+ NVMesh,
157
+ NVMeshLoaders,
158
+ SHOW_RENDER
159
+ } from "./niivue/index.ts";
160
+ layout.onchange = function () {
161
+ nv1.setMultiplanarLayout(parseInt(this.value));
162
+ nv2.setMultiplanarLayout(parseInt(this.value));
163
+ nv3.setMultiplanarLayout(parseInt(this.value));
164
+ }
165
+ canvasHeight.onchange = function () {
166
+ gl1.height = this.value;
167
+ gl2.height = this.value;
168
+ gl3.height = this.value;
169
+ nv1.resizeListener();
170
+ nv2.resizeListener();
171
+ nv3.resizeListener();
172
+ }
173
+
174
+ gammaSlider.onchange = function() {
175
+ const v = parseFloat(gammaSlider.value) * 0.01
176
+ nv1.setGamma(v)
177
+ nv1.gl.canvas.focus()
178
+ nv1.sync()
179
+ nv1.gl.canvas.blur()
180
+ }
181
+
182
+ syncDrop.onchange = function(e) {
183
+ const v = e.target.value
184
+ // let is2D = false
185
+ // let is3D = false
186
+ // if (v % 2) {
187
+ // is2D = true
188
+ // }
189
+ // if (v > 1) {
190
+ // is3D = true
191
+ // }
192
+
193
+ // check if v === "all", if so, add everything
194
+ if (v === "all") {
195
+ nv1.broadcastTo([nv2, nv3], {
196
+ ['3d']: true,
197
+ crosshair: true,
198
+ zoomPan: true,
199
+ gamma: true,
200
+ sliceType: true,
201
+ clipPlane: true,
202
+ // cal_min: true,
203
+ // cal_max: true,
204
+ })
205
+ nv2.broadcastTo([nv1, nv3], {
206
+ ['3d']: true,
207
+ crosshair: true,
208
+ zoomPan: true,
209
+ gamma: true,
210
+ sliceType: true,
211
+ clipPlane: true,
212
+ // cal_min: true,
213
+ // cal_max: true,
214
+ })
215
+ nv3.broadcastTo([nv1, nv2], {
216
+ ['3d']: true,
217
+ crosshair: true,
218
+ zoomPan: true,
219
+ gamma: true,
220
+ sliceType: true,
221
+ clipPlane: true,
222
+ // cal_min: true,
223
+ // cal_max: true,
224
+ })
225
+ return
226
+ }
227
+ nv1.broadcastTo([nv2, nv3], { [v]: true })
228
+ nv2.broadcastTo([nv1, nv3], { [v]: true })
229
+ nv3.broadcastTo([nv1, nv2], { [v]: true })
230
+ }
231
+
232
+ calMin.onchange = function() {
233
+ const v = parseFloat(calMin.value)
234
+ nv2.volumes[0].cal_min = v
235
+ // set focus to the canvas
236
+ nv2.gl.canvas.focus()
237
+ nv2.updateGLVolume()
238
+ // remove focus from the canvas
239
+ nv2.gl.canvas.blur()
240
+ }
241
+
242
+ calMax.onchange = function() {
243
+ const v = parseFloat(calMax.value)
244
+ nv2.volumes[0].cal_max = v
245
+ // set focus to the canvas
246
+ nv2.gl.canvas.focus()
247
+ nv2.updateGLVolume()
248
+ // remove focus from the canvas
249
+ nv2.gl.canvas.blur()
250
+ }
251
+
252
+ sliceType.onchange = function() {
253
+ const v = parseInt(sliceType.value)
254
+ nv1.setSliceType(v)
255
+ nv2.setSliceType(v)
256
+ nv3.setSliceType(v)
257
+ }
258
+
259
+ function handleIntensityChange(data) {
260
+ document.getElementById("intensity").innerHTML =
261
+ "&nbsp;&nbsp;" + data.string;
262
+ }
263
+ function handleIntensityChange2(data) {
264
+ document.getElementById("intensity2").innerHTML =
265
+ "&nbsp;&nbsp;" + data.string;
266
+ }
267
+ function handleIntensityChange3(data) {
268
+ document.getElementById("intensity3").innerHTML =
269
+ "&nbsp;&nbsp;" + data.string;
270
+ }
271
+ var nv1 = new Niivue({
272
+ show3Dcrosshair: true,
273
+ onLocationChange: handleIntensityChange,
274
+ backColor: [1, 1, 1, 1],
275
+ dragMode: 3,
276
+ sliceType: 3,
277
+ multiplanarShowRender: SHOW_RENDER.ALWAYS,
278
+ isRadiologicalConvention: true
279
+ });
280
+ nv1.attachTo("gl1");
281
+ var volumeList1 = [{ url: "../demos/images/pcasl.nii.gz" }];
282
+ await nv1.loadVolumes(volumeList1);
283
+ var nv2 = new Niivue({
284
+ show3Dcrosshair: true,
285
+ onLocationChange: handleIntensityChange2,
286
+ backColor: [1, 1, 1, 1],
287
+ dragMode: 3,
288
+ sliceType: 3,
289
+ multiplanarShowRender: SHOW_RENDER.ALWAYS
290
+ });
291
+ nv2.attachTo("gl2");
292
+ var nv3 = new Niivue({
293
+ show3Dcrosshair: true,
294
+ onLocationChange: handleIntensityChange3,
295
+ backColor: [1, 1, 1, 1],
296
+ dragMode: 0,
297
+ sliceType: 3,
298
+ multiplanarShowRender: SHOW_RENDER.ALWAYS
299
+ });
300
+ nv3.attachTo("gl3");
301
+ var volumeList2 = [{ url: "../demos/images/mni152.nii.gz" }];
302
+ var volumeList3 = [{ url: "../demos/images/mni152.nii.gz" }];
303
+ await nv2.loadVolumes(volumeList2);
304
+ // once the volumes are loaded for nv2, set the min and max values for
305
+ // the calMin and calMax sliders to the min and max values of the volume
306
+ calMin.min = nv2.volumes[0].global_min
307
+ calMin.max = nv2.volumes[0].global_max
308
+ calMin.value = nv2.volumes[0].cal_min
309
+ calMax.min = nv2.volumes[0].global_min
310
+ calMax.max = nv2.volumes[0].global_max
311
+ calMax.value = nv2.volumes[0].cal_max
312
+
313
+ await nv3.loadVolumes(volumeList3);
314
+ const syncOpts = {
315
+ // "2d": true, // legacy option
316
+ // "3d": true, // legacy option
317
+ // new options allowing more fine-grained control below.
318
+ crosshair: true,
319
+ zoomPan: true,
320
+ gamma: true,
321
+ sliceType: true,
322
+ clipPlane: true,
323
+ cal_min: false,
324
+ cal_max: false,
325
+ }
326
+ // make sure all views can control each other
327
+ nv1.broadcastTo([nv2, nv3], syncOpts);
328
+ nv2.broadcastTo([nv1, nv3], syncOpts);
329
+ nv3.broadcastTo([nv1, nv2], syncOpts);
330
+
331
+ </script>
332
+ </body>
333
+ </html>