@niivue/niivue 0.44.2-dev.1 → 0.45.0
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.
- package/build/index.d.ts +15 -71
- package/build/index.js +197 -459
- package/build/index.js.map +1 -1
- package/build/index.min.js +1 -1
- package/dist/index.d.ts +15 -71
- package/dist/index.js +198 -460
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/niivue.umd.js +27 -66
- package/package.json +1 -1
- package/src/cow.iwm.cbor +0 -0
- package/src/fslmean.iwi.cbor +0 -0
- package/src/index.html +1 -1
- package/src/niivue/index.ts +266 -532
- package/src/nvdocument.ts +5 -25
- package/src/shader-srcs.ts +0 -41
- package/src/types.ts +0 -13
- package/src/index_segment.html +0 -165
- package/src/index_sync.html +0 -289
package/src/nvdocument.ts
CHANGED
|
@@ -46,8 +46,7 @@ export enum DRAG_MODE {
|
|
|
46
46
|
measurement = 2,
|
|
47
47
|
pan = 3,
|
|
48
48
|
slicer3D = 4,
|
|
49
|
-
callbackOnly = 5
|
|
50
|
-
roiSelection = 6
|
|
49
|
+
callbackOnly = 5
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
// make mutable type
|
|
@@ -141,18 +140,10 @@ export type NVConfigOptions = {
|
|
|
141
140
|
renderOverlayBlend: number
|
|
142
141
|
sliceMosaicString: string
|
|
143
142
|
centerMosaic: boolean
|
|
144
|
-
penSize: number
|
|
145
143
|
clickToSegment: boolean
|
|
146
144
|
clickToSegmentRadius: number
|
|
145
|
+
clickToSegmentSteps: number
|
|
147
146
|
clickToSegmentBright: boolean
|
|
148
|
-
clickToSegmentAutoIntensity: boolean // new option, but keep clickToSegmentBright for backwards compatibility
|
|
149
|
-
clickToSegmentIntensityMax: number // also covers NaN
|
|
150
|
-
clickToSegmentIntensityMin: number // also covers NaN
|
|
151
|
-
clickToSegmentPercent: number
|
|
152
|
-
clickToSegmentMaxDistanceMM: number // max distance in mm to consider for click to segment flood fill
|
|
153
|
-
// selection box outline thickness
|
|
154
|
-
selectionBoxLineThickness: number
|
|
155
|
-
selectionBoxIsOutline: boolean
|
|
156
147
|
}
|
|
157
148
|
|
|
158
149
|
export const DEFAULT_OPTIONS: NVConfigOptions = {
|
|
@@ -221,21 +212,10 @@ export const DEFAULT_OPTIONS: NVConfigOptions = {
|
|
|
221
212
|
renderOverlayBlend: 1.0,
|
|
222
213
|
sliceMosaicString: '',
|
|
223
214
|
centerMosaic: false,
|
|
224
|
-
penSize: 1, // in voxels, since all drawing is done using bitmap indices
|
|
225
215
|
clickToSegment: false,
|
|
226
|
-
clickToSegmentRadius:
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
clickToSegmentIntensityMax: NaN, // NaN will use auto threshold (default flood fill behavior from before)
|
|
230
|
-
clickToSegmentIntensityMin: NaN, // NaN will use auto threshold (default flood fill behavior from before)
|
|
231
|
-
// 0 will use auto threshold (default flood fill behavior from before)
|
|
232
|
-
// Take the voxel intensity at the click point and use this percentage +/- to threshold the flood fill operation.
|
|
233
|
-
// If greater than 0, clickedVoxelIntensity +/- clickedVoxelIntensity * clickToSegmentPercent will be used
|
|
234
|
-
// for the clickToSegmentIntensityMin and clickToSegmentIntensityMax values.
|
|
235
|
-
clickToSegmentPercent: 0,
|
|
236
|
-
clickToSegmentMaxDistanceMM: Number.POSITIVE_INFINITY, // default value is infinity for backwards compatibility with flood fill routine.
|
|
237
|
-
selectionBoxLineThickness: 4,
|
|
238
|
-
selectionBoxIsOutline: false
|
|
216
|
+
clickToSegmentRadius: 2,
|
|
217
|
+
clickToSegmentSteps: 10,
|
|
218
|
+
clickToSegmentBright: true
|
|
239
219
|
}
|
|
240
220
|
|
|
241
221
|
type SceneData = {
|
package/src/shader-srcs.ts
CHANGED
|
@@ -719,47 +719,6 @@ void main() {
|
|
|
719
719
|
color = lineColor;
|
|
720
720
|
}`
|
|
721
721
|
|
|
722
|
-
export const fragRectOutlineShader = `#version 300 es
|
|
723
|
-
#line 723
|
|
724
|
-
precision highp int;
|
|
725
|
-
precision highp float;
|
|
726
|
-
|
|
727
|
-
uniform vec4 lineColor;
|
|
728
|
-
uniform vec4 leftTopWidthHeight;
|
|
729
|
-
uniform float thickness; // line thickness in pixels
|
|
730
|
-
uniform vec2 canvasWidthHeight;
|
|
731
|
-
|
|
732
|
-
out vec4 color;
|
|
733
|
-
|
|
734
|
-
void main() {
|
|
735
|
-
// fragment position in screen coordinates
|
|
736
|
-
vec2 fragCoord = gl_FragCoord.xy;
|
|
737
|
-
|
|
738
|
-
// canvas height
|
|
739
|
-
float canvasHeight = canvasWidthHeight.y;
|
|
740
|
-
|
|
741
|
-
// 'top' and 'bottom' to match gl_FragCoord.y coordinate system
|
|
742
|
-
float top = canvasHeight - leftTopWidthHeight.y;
|
|
743
|
-
float bottom = top - leftTopWidthHeight.w;
|
|
744
|
-
|
|
745
|
-
// left and right edges
|
|
746
|
-
float left = leftTopWidthHeight.x;
|
|
747
|
-
float right = left + leftTopWidthHeight.z;
|
|
748
|
-
|
|
749
|
-
bool withinLeft = fragCoord.x >= left && fragCoord.x <= left + thickness;
|
|
750
|
-
bool withinRight = fragCoord.x <= right && fragCoord.x >= right - thickness;
|
|
751
|
-
bool withinTop = fragCoord.y <= top && fragCoord.y >= top - thickness;
|
|
752
|
-
bool withinBottom = fragCoord.y >= bottom && fragCoord.y <= bottom + thickness;
|
|
753
|
-
|
|
754
|
-
bool isOutline = withinLeft || withinRight || withinTop || withinBottom;
|
|
755
|
-
|
|
756
|
-
if (isOutline) {
|
|
757
|
-
color = lineColor;
|
|
758
|
-
} else {
|
|
759
|
-
discard;
|
|
760
|
-
}
|
|
761
|
-
}`
|
|
762
|
-
|
|
763
722
|
export const vertColorbarShader = `#version 300 es
|
|
764
723
|
#line 490
|
|
765
724
|
layout(location=0) in vec3 pos;
|
package/src/types.ts
CHANGED
|
@@ -152,16 +152,3 @@ export type NiiVueLocation = {
|
|
|
152
152
|
vox: vec3
|
|
153
153
|
xy: [number, number]
|
|
154
154
|
}
|
|
155
|
-
|
|
156
|
-
export type SyncOpts = {
|
|
157
|
-
'3d'?: boolean
|
|
158
|
-
'2d'?: boolean
|
|
159
|
-
zoomPan?: boolean
|
|
160
|
-
cal_min?: boolean
|
|
161
|
-
cal_max?: boolean
|
|
162
|
-
gamma?: boolean
|
|
163
|
-
useSliceOffset?: boolean
|
|
164
|
-
sliceType?: boolean
|
|
165
|
-
crosshair?: boolean
|
|
166
|
-
clipPlane?: boolean
|
|
167
|
-
}
|
package/src/index_segment.html
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
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>NiiVue</title>
|
|
8
|
-
<link rel="stylesheet" href="niivue.css" />
|
|
9
|
-
<link rel="icon" href="data:;base64,iVBORw0KGgo=" />
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<noscript>
|
|
13
|
-
<strong>niivue requires JavaScript.</strong>
|
|
14
|
-
</noscript>
|
|
15
|
-
<header>
|
|
16
|
-
<button id="openBtn">Choose an image or mesh with a dialog</button>
|
|
17
|
-
<label for="layoutSelect">Layout</label>
|
|
18
|
-
<select id="layoutSelect">
|
|
19
|
-
<option value="0" selected>Auto</option>
|
|
20
|
-
<option value="1">Column</option>
|
|
21
|
-
<option value="2">Grid</option>
|
|
22
|
-
<option value="3">Row</option>
|
|
23
|
-
</select>
|
|
24
|
-
<label for="renderingSelect">MultiplanarRendering</label>
|
|
25
|
-
<select id="renderingSelect">
|
|
26
|
-
<option value="0">Never</option>
|
|
27
|
-
<option value="1">Always</option>
|
|
28
|
-
<option value="2" selected>Auto</option>
|
|
29
|
-
</select>
|
|
30
|
-
<select id="sliceType">
|
|
31
|
-
<option value="0">Axial</option>
|
|
32
|
-
<option value="1">Coronal</option>
|
|
33
|
-
<option value="2">Sagittal</option>
|
|
34
|
-
<option value="4">Render</option>
|
|
35
|
-
<option value="3" selected>Multiplanar</option>
|
|
36
|
-
</select>
|
|
37
|
-
<label for="equalCheck">EqualSize</label>
|
|
38
|
-
<input type="checkbox" id="equalCheck" checked />
|
|
39
|
-
<label for="cornerCheck">CornerText</label>
|
|
40
|
-
<input type="checkbox" id="cornerCheck" unchecked />
|
|
41
|
-
<!-- undo button for drawing -->
|
|
42
|
-
<button id="undoBtn">Undo</button>
|
|
43
|
-
<!-- draw toggle button -->
|
|
44
|
-
<button id="drawBtn">Draw</button>
|
|
45
|
-
<!-- grow button -->
|
|
46
|
-
<button id="growBtn">Grow</button>
|
|
47
|
-
<!-- pen color button cycler -->
|
|
48
|
-
<button id="penColorBtn">Pen color</button>
|
|
49
|
-
</header>
|
|
50
|
-
<main id="canvas-container">
|
|
51
|
-
<canvas id="gl1"></canvas>
|
|
52
|
-
</main>
|
|
53
|
-
|
|
54
|
-
<script type="module" async>
|
|
55
|
-
import {
|
|
56
|
-
Niivue,
|
|
57
|
-
NVImage,
|
|
58
|
-
NVMesh,
|
|
59
|
-
NVMeshLoaders,
|
|
60
|
-
SHOW_RENDER,
|
|
61
|
-
DRAG_MODE
|
|
62
|
-
} from "./niivue/index.ts";
|
|
63
|
-
async function addVolumeFromFiles(f) {
|
|
64
|
-
console.log("attempting to open ", f[0].name);
|
|
65
|
-
console.log("details", f[0]);
|
|
66
|
-
nv1.loadFromFile(f[0]);
|
|
67
|
-
}
|
|
68
|
-
openBtn.onclick = function () {
|
|
69
|
-
let input = document.createElement("input");
|
|
70
|
-
input.style.display = "none";
|
|
71
|
-
input.type = "file";
|
|
72
|
-
document.body.appendChild(input);
|
|
73
|
-
input.onchange = function (event) {
|
|
74
|
-
addVolumeFromFiles(event.target.files);
|
|
75
|
-
};
|
|
76
|
-
input.click();
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
// pen colors can be 1, 2, 3, 4
|
|
80
|
-
let penColor = 1;
|
|
81
|
-
|
|
82
|
-
layoutSelect.onchange = function () {
|
|
83
|
-
nv1.setMultiplanarLayout(Number(this.value));
|
|
84
|
-
}
|
|
85
|
-
renderingSelect.onchange = function () {
|
|
86
|
-
nv1.opts.multiplanarShowRender = Number(this.value);
|
|
87
|
-
nv1.drawScene();
|
|
88
|
-
}
|
|
89
|
-
equalCheck.onchange = function () {
|
|
90
|
-
nv1.opts.multiplanarEqualSize = this.checked
|
|
91
|
-
nv1.drawScene()
|
|
92
|
-
}
|
|
93
|
-
cornerCheck.onchange = function () {
|
|
94
|
-
//nv1.opts.isCornerOrientationText = this.checked\
|
|
95
|
-
nv1.setCornerOrientationText(this.checked)
|
|
96
|
-
}
|
|
97
|
-
sliceType.onchange = function () {
|
|
98
|
-
let st = parseInt(document.getElementById("sliceType").value);
|
|
99
|
-
nv1.setSliceType(st)
|
|
100
|
-
}
|
|
101
|
-
undoBtn.onclick = function () {
|
|
102
|
-
nv1.drawUndo()
|
|
103
|
-
}
|
|
104
|
-
drawBtn.onclick = function () {
|
|
105
|
-
nv1.setDrawingEnabled(!nv1.opts.drawingEnabled)
|
|
106
|
-
if (nv1.opts.drawingEnabled) {
|
|
107
|
-
nv1.opts.clickToSegment = true;
|
|
108
|
-
nv1.setPenValue(penColor, false) // red and filled
|
|
109
|
-
} else {
|
|
110
|
-
nv1.opts.clickToSegment = false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
growBtn.onclick = function () {
|
|
114
|
-
nv1.drawingBinaryDilationWithSeed(
|
|
115
|
-
nv1.frac2vox(nv1.scene.crosshairPos)
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
penColorBtn.onclick = function () {
|
|
119
|
-
penColor = penColor % 4 + 1;
|
|
120
|
-
nv1.setPenValue(penColor, false)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const onDragRelease = (data) => {
|
|
124
|
-
console.log("drag release", data);
|
|
125
|
-
let obj = nv1.getDescriptives({
|
|
126
|
-
layer: 0,
|
|
127
|
-
startVox: data.voxStart,
|
|
128
|
-
endVox: data.voxEnd,
|
|
129
|
-
roiIsMask: true,
|
|
130
|
-
});
|
|
131
|
-
console.log(obj);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
var volumeList1 = [{ url: "../demos/images/FLAIR.nii.gz" }];
|
|
135
|
-
let defaults = {
|
|
136
|
-
backColor: [0, 0, 0, 1],
|
|
137
|
-
show3Dcrosshair: true,
|
|
138
|
-
loglevel: 'debug',
|
|
139
|
-
isRuler: true,
|
|
140
|
-
clickToSegmentRadius: 3, // in mm
|
|
141
|
-
clickToSegmentPercent: 0.2,
|
|
142
|
-
clickToSegmentAutoIntensity: true,
|
|
143
|
-
clickToSegmentMaxDistanceMM: 10,
|
|
144
|
-
penSize: 3, // in voxels, but overridden by clickToSegmentRadius
|
|
145
|
-
maxDrawUndoBitmaps: 30,
|
|
146
|
-
onDragRelease: onDragRelease,
|
|
147
|
-
selectionBoxColor: [1, 0, 0, 0.5],
|
|
148
|
-
dragMode: DRAG_MODE.roiSelection,
|
|
149
|
-
selectionBoxIsOutline: true
|
|
150
|
-
};
|
|
151
|
-
var nv1 = new Niivue(defaults);
|
|
152
|
-
nv1.attachToCanvas(gl1);
|
|
153
|
-
// multiplanarShowRender is the preferred option now,
|
|
154
|
-
// but multiplanarForceRender is still available for backwards compatibility
|
|
155
|
-
// previous use was: nv1.opts.multiplanarForceRender = true;
|
|
156
|
-
nv1.opts.multiplanarShowRender = SHOW_RENDER.AUTO
|
|
157
|
-
await nv1.loadVolumes(volumeList1);
|
|
158
|
-
equalCheck.onchange()
|
|
159
|
-
|
|
160
|
-
// set drawing enabled
|
|
161
|
-
// nv1.setDrawingEnabled(true);
|
|
162
|
-
// nv1.setPenValue(1, true) // red and filled
|
|
163
|
-
</script>
|
|
164
|
-
</body>
|
|
165
|
-
</html>
|
package/src/index_sync.html
DELETED
|
@@ -1,289 +0,0 @@
|
|
|
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="0">Sync Disabled</option>
|
|
74
|
-
<option value="1">Sync 2D</option>
|
|
75
|
-
<option value="2">Sync 3D</option>
|
|
76
|
-
<option value="3" selected>Sync 2D and 3D</option>
|
|
77
|
-
</select>
|
|
78
|
-
<!-- slider for gamma -->
|
|
79
|
-
<label for="gammaSlider">Gamma</label>
|
|
80
|
-
<input
|
|
81
|
-
type="range"
|
|
82
|
-
min="10"
|
|
83
|
-
max="400"
|
|
84
|
-
value="100"
|
|
85
|
-
class="slider"
|
|
86
|
-
id="gammaSlider"
|
|
87
|
-
/>
|
|
88
|
-
<!-- sliceType select -->
|
|
89
|
-
<label for="sliceType">Slice Type</label>
|
|
90
|
-
<select id="sliceType">
|
|
91
|
-
<option value="0">Axial</option>
|
|
92
|
-
<option value="1">Coronal</option>
|
|
93
|
-
<option value="2">Sagittal</option>
|
|
94
|
-
<option value="3" selected>Multi</option>
|
|
95
|
-
</select>
|
|
96
|
-
|
|
97
|
-
<!-- slider for cal_min -->
|
|
98
|
-
<label for="calMin">min</label>
|
|
99
|
-
<input
|
|
100
|
-
type="range"
|
|
101
|
-
min="0"
|
|
102
|
-
max="100"
|
|
103
|
-
value="0"
|
|
104
|
-
class="slider"
|
|
105
|
-
id="calMin"
|
|
106
|
-
/>
|
|
107
|
-
<!-- slider for cal_max -->
|
|
108
|
-
<label for="calMax">max</label>
|
|
109
|
-
<input
|
|
110
|
-
type="range"
|
|
111
|
-
min="0"
|
|
112
|
-
max="100"
|
|
113
|
-
value="100"
|
|
114
|
-
class="slider"
|
|
115
|
-
id="calMax"
|
|
116
|
-
/>
|
|
117
|
-
</header>
|
|
118
|
-
<main>
|
|
119
|
-
<div class='page-wrapper'>
|
|
120
|
-
<div class='row'>
|
|
121
|
-
<div class='column'>
|
|
122
|
-
<div>
|
|
123
|
-
<canvas id="gl1" height="512">
|
|
124
|
-
</div>
|
|
125
|
-
</div>
|
|
126
|
-
<div class='column'>
|
|
127
|
-
<div>
|
|
128
|
-
<canvas id="gl2" height="512">
|
|
129
|
-
</div>
|
|
130
|
-
</div>
|
|
131
|
-
<div class='column'>
|
|
132
|
-
<div>
|
|
133
|
-
<canvas id="gl3" height="512">
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
</main>
|
|
139
|
-
<footer>
|
|
140
|
-
<x id="intensity"> </x>
|
|
141
|
-
<x id="intensity2"> </x>
|
|
142
|
-
<x id="intensity3"> </x>
|
|
143
|
-
</footer>
|
|
144
|
-
<script type="module" async>
|
|
145
|
-
import {
|
|
146
|
-
Niivue,
|
|
147
|
-
NVImage,
|
|
148
|
-
NVMesh,
|
|
149
|
-
NVMeshLoaders,
|
|
150
|
-
SHOW_RENDER
|
|
151
|
-
} from "./niivue/index.ts";
|
|
152
|
-
layout.onchange = function () {
|
|
153
|
-
nv1.setMultiplanarLayout(parseInt(this.value));
|
|
154
|
-
nv2.setMultiplanarLayout(parseInt(this.value));
|
|
155
|
-
nv3.setMultiplanarLayout(parseInt(this.value));
|
|
156
|
-
}
|
|
157
|
-
canvasHeight.onchange = function () {
|
|
158
|
-
gl1.height = this.value;
|
|
159
|
-
gl2.height = this.value;
|
|
160
|
-
gl3.height = this.value;
|
|
161
|
-
nv1.resizeListener();
|
|
162
|
-
nv2.resizeListener();
|
|
163
|
-
nv3.resizeListener();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
gammaSlider.onchange = function() {
|
|
167
|
-
const v = parseFloat(gammaSlider.value) * 0.01
|
|
168
|
-
nv1.setGamma(v)
|
|
169
|
-
nv1.gl.canvas.focus()
|
|
170
|
-
nv1.sync()
|
|
171
|
-
nv1.gl.canvas.blur()
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
syncDrop.onchange = function() {
|
|
175
|
-
const v = parseInt(syncDrop.value)
|
|
176
|
-
let is2D = false
|
|
177
|
-
let is3D = false
|
|
178
|
-
if (v % 2) {
|
|
179
|
-
is2D = true
|
|
180
|
-
}
|
|
181
|
-
if (v > 1) {
|
|
182
|
-
is3D = true
|
|
183
|
-
}
|
|
184
|
-
nv1.broadcastTo([nv2, nv3], { "2d": is2D, "3d": is3D })
|
|
185
|
-
nv2.broadcastTo([nv1, nv3], { "2d": is2D, "3d": is3D })
|
|
186
|
-
nv3.broadcastTo([nv1, nv2], { "2d": is2D, "3d": is3D })
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
calMin.onchange = function() {
|
|
190
|
-
const v = parseFloat(calMin.value)
|
|
191
|
-
nv2.volumes[0].cal_min = v
|
|
192
|
-
// set focus to the canvas
|
|
193
|
-
nv2.gl.canvas.focus()
|
|
194
|
-
nv2.updateGLVolume()
|
|
195
|
-
// remove focus from the canvas
|
|
196
|
-
nv2.gl.canvas.blur()
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
calMax.onchange = function() {
|
|
200
|
-
const v = parseFloat(calMax.value)
|
|
201
|
-
nv2.volumes[0].cal_max = v
|
|
202
|
-
// set focus to the canvas
|
|
203
|
-
nv2.gl.canvas.focus()
|
|
204
|
-
nv2.updateGLVolume()
|
|
205
|
-
// remove focus from the canvas
|
|
206
|
-
nv2.gl.canvas.blur()
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
sliceType.onchange = function() {
|
|
210
|
-
const v = parseInt(sliceType.value)
|
|
211
|
-
nv1.setSliceType(v)
|
|
212
|
-
nv2.setSliceType(v)
|
|
213
|
-
nv3.setSliceType(v)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function handleIntensityChange(data) {
|
|
217
|
-
document.getElementById("intensity").innerHTML =
|
|
218
|
-
" " + data.string;
|
|
219
|
-
}
|
|
220
|
-
function handleIntensityChange2(data) {
|
|
221
|
-
document.getElementById("intensity2").innerHTML =
|
|
222
|
-
" " + data.string;
|
|
223
|
-
}
|
|
224
|
-
function handleIntensityChange3(data) {
|
|
225
|
-
document.getElementById("intensity3").innerHTML =
|
|
226
|
-
" " + data.string;
|
|
227
|
-
}
|
|
228
|
-
var nv1 = new Niivue({
|
|
229
|
-
show3Dcrosshair: true,
|
|
230
|
-
onLocationChange: handleIntensityChange,
|
|
231
|
-
backColor: [1, 1, 1, 1],
|
|
232
|
-
// dragMode: 3,
|
|
233
|
-
sliceType: 3,
|
|
234
|
-
multiplanarShowRender: SHOW_RENDER.ALWAYS
|
|
235
|
-
});
|
|
236
|
-
nv1.attachTo("gl1");
|
|
237
|
-
var volumeList1 = [{ url: "../demos/images/pcasl.nii.gz" }];
|
|
238
|
-
await nv1.loadVolumes(volumeList1);
|
|
239
|
-
var nv2 = new Niivue({
|
|
240
|
-
show3Dcrosshair: true,
|
|
241
|
-
onLocationChange: handleIntensityChange2,
|
|
242
|
-
backColor: [1, 1, 1, 1],
|
|
243
|
-
// dragMode: 3,
|
|
244
|
-
sliceType: 3,
|
|
245
|
-
multiplanarShowRender: SHOW_RENDER.ALWAYS
|
|
246
|
-
});
|
|
247
|
-
nv2.attachTo("gl2");
|
|
248
|
-
var nv3 = new Niivue({
|
|
249
|
-
show3Dcrosshair: true,
|
|
250
|
-
onLocationChange: handleIntensityChange3,
|
|
251
|
-
backColor: [1, 1, 1, 1],
|
|
252
|
-
// dragMode: 0,
|
|
253
|
-
sliceType: 3,
|
|
254
|
-
multiplanarShowRender: SHOW_RENDER.ALWAYS
|
|
255
|
-
});
|
|
256
|
-
nv3.attachTo("gl3");
|
|
257
|
-
var volumeList2 = [{ url: "../demos/images/mni152.nii.gz" }];
|
|
258
|
-
var volumeList3 = [{ url: "../demos/images/mni152.nii.gz" }];
|
|
259
|
-
await nv2.loadVolumes(volumeList2);
|
|
260
|
-
// once the volumes are loaded for nv2, set the min and max values for
|
|
261
|
-
// the calMin and calMax sliders to the min and max values of the volume
|
|
262
|
-
calMin.min = nv2.volumes[0].global_min
|
|
263
|
-
calMin.max = nv2.volumes[0].global_max
|
|
264
|
-
calMin.value = nv2.volumes[0].cal_min
|
|
265
|
-
calMax.min = nv2.volumes[0].global_min
|
|
266
|
-
calMax.max = nv2.volumes[0].global_max
|
|
267
|
-
calMax.value = nv2.volumes[0].cal_max
|
|
268
|
-
|
|
269
|
-
await nv3.loadVolumes(volumeList3);
|
|
270
|
-
const syncOpts = {
|
|
271
|
-
// "2d": true, // legacy option
|
|
272
|
-
// "3d": true, // legacy option
|
|
273
|
-
// new options allowing more fine-grained control below.
|
|
274
|
-
crosshair: true,
|
|
275
|
-
zoomPan: true,
|
|
276
|
-
gamma: true,
|
|
277
|
-
sliceType: true,
|
|
278
|
-
clipPlane: true,
|
|
279
|
-
cal_min: false,
|
|
280
|
-
cal_max: false,
|
|
281
|
-
}
|
|
282
|
-
// make sure all views can control each other
|
|
283
|
-
nv1.broadcastTo([nv2, nv3], syncOpts);
|
|
284
|
-
nv2.broadcastTo([nv1, nv3], syncOpts);
|
|
285
|
-
nv3.broadcastTo([nv1, nv2], syncOpts);
|
|
286
|
-
|
|
287
|
-
</script>
|
|
288
|
-
</body>
|
|
289
|
-
</html>
|