@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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@niivue/niivue",
3
- "version": "0.44.1",
3
+ "version": "0.44.2-dev.2",
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.42.1",
76
- "@rollup/plugin-commonjs": "^25.0.7",
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.12.2",
78
+ "@types/node": "^20.14.11",
79
79
  "@types/ungap__structured-clone": "^1.2.0",
80
- "@typescript-eslint/eslint-plugin": "^7.5.0",
81
- "@typescript-eslint/parser": "^7.5.0",
82
- "@vitest/coverage-v8": "^1.4.0",
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.3",
87
- "eslint-plugin-tsdoc": "^0.2.17",
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.10",
89
+ "happy-dom": "^14.12.3",
90
90
  "http-server": "^14.1.1",
91
- "prettier": "^3.2.5",
91
+ "prettier": "^3.3.3",
92
92
  "regenerator-runtime": "^0.14.1",
93
- "tsup": "^8.0.2",
94
- "typedoc": "^0.25.12",
95
- "typescript": "^5.4.3",
96
- "vite": "^5.2.7",
97
- "vitest": "^1.4.0"
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.13.2"
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
- <button id="about">About</button>
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
- about.onclick = function () {
111
- window.alert(
112
- "The `Per Vertex` colors visualize a tsf format overlay created with tcksample",
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,233 @@
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.drawOpacity = 0.4
108
+ nv1.opts.clickToSegment = true;
109
+ nv1.setPenValue(penColor, false) // red and filled
110
+ // hide the crosshair
111
+ nv1.opts.crosshairWidth = 0;
112
+ // hide the mouse cursor
113
+ nv1.canvas.style.cursor = "none";
114
+ } else {
115
+ nv1.opts.clickToSegment = false;
116
+ // show the crosshair
117
+ nv1.opts.crosshairWidth = 1;
118
+ // show the mouse cursor
119
+ nv1.canvas.style.cursor = "default";
120
+ }
121
+ }
122
+ growBtn.onclick = function () {
123
+ nv1.drawingBinaryDilationWithSeed(
124
+ nv1.frac2vox(nv1.scene.crosshairPos)
125
+ )
126
+ }
127
+ penColorBtn.onclick = function () {
128
+ penColor = penColor % 4 + 1;
129
+ nv1.setPenValue(penColor, false)
130
+ }
131
+
132
+ const onDragRelease = (data) => {
133
+ // if there is a div with the id dragReleaseDiv, remove it
134
+ const divToRemove = document.getElementById("dragReleaseDiv");
135
+ if (divToRemove) {
136
+ divToRemove.remove();
137
+ }
138
+
139
+ console.log("drag release", data);
140
+ let obj = nv1.getDescriptives({
141
+ layer: 0,
142
+ startVox: data.voxStart,
143
+ endVox: data.voxEnd,
144
+ roiIsMask: true,
145
+ });
146
+ console.log(obj);
147
+ // get dpr
148
+ const dpr = window.devicePixelRatio;
149
+ // get mouse x,y. Divide by dpr to get the correct position
150
+ const x = nv1.uiData.dragEnd[0] / dpr;
151
+ const y = nv1.uiData.dragEnd[1] / dpr;
152
+ console.log(x, y);
153
+ const pad = 5;
154
+ const div = document.createElement("div");
155
+ // set id for removal on the next pass
156
+ div.id = "dragReleaseDiv";
157
+ div.style.color = "red";
158
+ div.style.position = "absolute";
159
+ div.style.backgroundColor = "black";
160
+ div.style.opacity = 0.8;
161
+ div.style.padding = "5px";
162
+ // set z-index to be well above the canvas
163
+ div.style.zIndex = 1000;
164
+ div.innerHTML = `Mean: ${obj.mean}<br>Area: ${obj.area}<br>Stdev: ${obj.stdev}`;
165
+ // set position to be at the mouse x,y relative to the canvas
166
+ div.style.left = x + pad + "px";
167
+ div.style.top = y + pad + "px";
168
+ // get the canvas element reference from niivue
169
+ const canvas = nv1.gl.canvas;
170
+ // niivue should always be in a container, so get the parent of the canvas
171
+ const parentDiv = canvas.parentElement;
172
+ parentDiv.appendChild(div);
173
+ };
174
+
175
+ const onLocationChange = (data) => {
176
+ // remove the stats div if it exists when the user clicks away
177
+ const divToRemove = document.getElementById("dragReleaseDiv");
178
+ if (divToRemove) {
179
+ divToRemove.remove();
180
+ }
181
+ // console.log(data.string)
182
+ };
183
+
184
+
185
+ var volumeList1 = [
186
+ { url: "../demos/images/FLAIR.nii.gz" },
187
+ ];
188
+ let clicks = 0;
189
+ const defaultPercent = 0.02;
190
+ let defaults = {
191
+ backColor: [0, 0, 0, 1],
192
+ show3Dcrosshair: true,
193
+ loglevel: 'debug',
194
+ isRuler: true,
195
+ clickToSegmentRadius: 3, // in mm
196
+ clickToSegmentPercent: defaultPercent,
197
+ clickToSegmentAutoIntensity: true,
198
+ clickToSegmentMaxDistanceMM: 50,
199
+ clickToSegmentIs2D: true,
200
+ floodFillNeighbors: 6,
201
+ penSize: 3, // in voxels, but overridden by clickToSegmentRadius
202
+ maxDrawUndoBitmaps: 100, // large number for undo
203
+ onDragRelease: onDragRelease,
204
+ onLocationChange: onLocationChange,
205
+ selectionBoxColor: [1, 0, 0, 0.5],
206
+ dragMode: DRAG_MODE.roiSelection,
207
+ selectionBoxIsOutline: true,
208
+ scrollRequiresFocus: false
209
+ };
210
+ var nv1 = new Niivue(defaults);
211
+ nv1.attachToCanvas(gl1);
212
+ nv1.opts.multiplanarShowRender = SHOW_RENDER.AUTO
213
+ nv1.setSliceType(0)
214
+ nv1.setInterpolation(false)
215
+ await nv1.loadVolumes(volumeList1);
216
+ equalCheck.onchange()
217
+
218
+ // store mouse position
219
+ const mouse = { x: 0, y: 0 };
220
+
221
+ // when the user presses "t" toggle the overlay opacity between 0 and 1
222
+ document.addEventListener("keydown", (e) => {
223
+ if (e.key === "t") {
224
+ if (nv1.volumes.length < 2) {
225
+ return;
226
+ }
227
+ const currentOpacity = nv1.volumes[1].opacity;
228
+ nv1.setOpacity(1, currentOpacity === 0 ? 0.5 : 0);
229
+ }
230
+ });
231
+ </script>
232
+ </body>
233
+ </html>