@niivue/niivue 0.44.0 → 0.44.2-dev.1
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/README.md +9 -0
- package/build/index.d.ts +132 -18
- package/build/index.js +1088 -178
- package/build/index.js.map +1 -1
- package/build/index.min.js +1 -1
- package/dist/index.d.ts +132 -18
- package/dist/index.js +26585 -30810
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/niivue.umd.js +111 -32
- package/package.json +18 -17
- package/src/index.html +46 -7
- package/src/index_segment.html +165 -0
- package/src/index_sync.html +289 -0
- package/src/niivue/index.ts +857 -137
- package/src/nvdocument.ts +36 -5
- package/src/nvimage/index.ts +29 -3
- package/src/nvimage/utils.ts +61 -42
- package/src/nvlabel.ts +34 -1
- package/src/nvmesh-loaders.ts +50 -6
- package/src/nvmesh-utilities.ts +139 -0
- package/src/nvmesh.ts +96 -0
- package/src/shader-srcs.ts +84 -3
- package/src/types.ts +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@niivue/niivue",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.2-dev.1",
|
|
4
4
|
"description": "minimal webgl2 nifti image viewer",
|
|
5
5
|
"types": "./build/index.d.ts",
|
|
6
6
|
"main": "./build/index.js",
|
|
@@ -72,31 +72,32 @@
|
|
|
72
72
|
"rxjs": "^7.8.1"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@playwright/test": "^1.
|
|
76
|
-
"@rollup/plugin-commonjs": "^
|
|
75
|
+
"@playwright/test": "^1.45.2",
|
|
76
|
+
"@rollup/plugin-commonjs": "^26.0.1",
|
|
77
77
|
"@types/array-equal": "^1.0.2",
|
|
78
|
-
"@types/node": "^20.
|
|
78
|
+
"@types/node": "^20.14.11",
|
|
79
79
|
"@types/ungap__structured-clone": "^1.2.0",
|
|
80
|
-
"@typescript-eslint/eslint-plugin": "^7.
|
|
81
|
-
"@typescript-eslint/parser": "^7.
|
|
82
|
-
"@vitest/coverage-v8": "^
|
|
80
|
+
"@typescript-eslint/eslint-plugin": "^7.16.1",
|
|
81
|
+
"@typescript-eslint/parser": "^7.16.1",
|
|
82
|
+
"@vitest/coverage-v8": "^2.0.3",
|
|
83
83
|
"eslint": "^8.57.0",
|
|
84
84
|
"eslint-config-prettier": "^9.1.0",
|
|
85
85
|
"eslint-config-standard": "^17.1.0",
|
|
86
|
-
"eslint-plugin-prettier": "^5.1
|
|
87
|
-
"eslint-plugin-tsdoc": "^0.
|
|
86
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
87
|
+
"eslint-plugin-tsdoc": "^0.3.0",
|
|
88
88
|
"express": "^4.19.2",
|
|
89
|
-
"happy-dom": "^14.3
|
|
89
|
+
"happy-dom": "^14.12.3",
|
|
90
90
|
"http-server": "^14.1.1",
|
|
91
|
-
"prettier": "^3.
|
|
91
|
+
"prettier": "^3.3.3",
|
|
92
92
|
"regenerator-runtime": "^0.14.1",
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
93
|
+
"terser": "^5.31.3",
|
|
94
|
+
"tsup": "^8.1.2",
|
|
95
|
+
"typedoc": "^0.26.4",
|
|
96
|
+
"typescript": "^5.5.3",
|
|
97
|
+
"vite": "^5.3.4",
|
|
98
|
+
"vitest": "^2.0.3"
|
|
98
99
|
},
|
|
99
100
|
"optionalDependencies": {
|
|
100
|
-
"@rollup/rollup-linux-x64-gnu": "^4.
|
|
101
|
+
"@rollup/rollup-linux-x64-gnu": "^4.18.1"
|
|
101
102
|
}
|
|
102
103
|
}
|
package/src/index.html
CHANGED
|
@@ -58,7 +58,30 @@
|
|
|
58
58
|
class="slider"
|
|
59
59
|
id="fiberCalMin"
|
|
60
60
|
/>
|
|
61
|
-
<
|
|
61
|
+
<label for="layoutSelect">Layout</label>
|
|
62
|
+
<select id="layoutSelect">
|
|
63
|
+
<option value="0" selected>Auto</option>
|
|
64
|
+
<option value="1">Column</option>
|
|
65
|
+
<option value="2">Grid</option>
|
|
66
|
+
<option value="3">Row</option>
|
|
67
|
+
</select>
|
|
68
|
+
<label for="renderingSelect">MultiplanarRendering</label>
|
|
69
|
+
<select id="renderingSelect">
|
|
70
|
+
<option value="0">Never</option>
|
|
71
|
+
<option value="1">Always</option>
|
|
72
|
+
<option value="2" selected>Auto</option>
|
|
73
|
+
</select>
|
|
74
|
+
<select id="sliceType">
|
|
75
|
+
<option value="0">Axial</option>
|
|
76
|
+
<option value="1">Coronal</option>
|
|
77
|
+
<option value="2">Sagittal</option>
|
|
78
|
+
<option value="4">Render</option>
|
|
79
|
+
<option value="3" selected>Multiplanar</option>
|
|
80
|
+
</select>
|
|
81
|
+
<label for="equalCheck">EqualSize</label>
|
|
82
|
+
<input type="checkbox" id="equalCheck" checked />
|
|
83
|
+
<label for="cornerCheck">CornerText</label>
|
|
84
|
+
<input type="checkbox" id="cornerCheck" unchecked />
|
|
62
85
|
</header>
|
|
63
86
|
<main id="canvas-container">
|
|
64
87
|
<canvas id="gl1"></canvas>
|
|
@@ -107,16 +130,31 @@
|
|
|
107
130
|
nv1.meshes[0].dpv[0].cal_min = this.value * 1; //*1 converts string to number
|
|
108
131
|
nv1.setMeshProperty(nv1.meshes[0].id, "colormap", fiberColormap.value);
|
|
109
132
|
};
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
133
|
+
layoutSelect.onchange = function () {
|
|
134
|
+
nv1.setMultiplanarLayout(Number(this.value));
|
|
135
|
+
}
|
|
136
|
+
renderingSelect.onchange = function () {
|
|
137
|
+
nv1.opts.multiplanarShowRender = Number(this.value);
|
|
138
|
+
nv1.drawScene();
|
|
139
|
+
}
|
|
140
|
+
equalCheck.onchange = function () {
|
|
141
|
+
nv1.opts.multiplanarEqualSize = this.checked
|
|
142
|
+
nv1.drawScene()
|
|
143
|
+
}
|
|
144
|
+
cornerCheck.onchange = function () {
|
|
145
|
+
//nv1.opts.isCornerOrientationText = this.checked\
|
|
146
|
+
nv1.setCornerOrientationText(this.checked)
|
|
147
|
+
}
|
|
148
|
+
sliceType.onchange = function () {
|
|
149
|
+
let st = parseInt(document.getElementById("sliceType").value);
|
|
150
|
+
nv1.setSliceType(st)
|
|
151
|
+
}
|
|
115
152
|
var volumeList1 = [{ url: "../demos/images/mni152.nii.gz" }];
|
|
116
153
|
let defaults = {
|
|
117
154
|
backColor: [0, 0, 0, 1],
|
|
118
155
|
show3Dcrosshair: true,
|
|
119
|
-
loglevel: 'debug'
|
|
156
|
+
loglevel: 'debug',
|
|
157
|
+
isRuler: true
|
|
120
158
|
};
|
|
121
159
|
var nv1 = new Niivue(defaults);
|
|
122
160
|
nv1.attachToCanvas(gl1);
|
|
@@ -152,6 +190,7 @@
|
|
|
152
190
|
};
|
|
153
191
|
cmapEl.appendChild(btn);
|
|
154
192
|
}
|
|
193
|
+
equalCheck.onchange()
|
|
155
194
|
</script>
|
|
156
195
|
</body>
|
|
157
196
|
</html>
|
|
@@ -0,0 +1,165 @@
|
|
|
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>
|
|
@@ -0,0 +1,289 @@
|
|
|
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>
|