cloudmr-ux 2.0.7 → 3.0.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.
Files changed (206) hide show
  1. package/README.md +24 -24
  2. package/dist/CmrComponents/CmrButton/CmrButton.css +0 -0
  3. package/dist/CmrComponents/CmrButton/CmrButton.d.ts +4 -0
  4. package/dist/CmrComponents/CmrButton/CmrButton.js +30 -0
  5. package/dist/CmrComponents/CmrButton/index.d.ts +1 -0
  6. package/dist/CmrComponents/CmrButton/index.js +1 -0
  7. package/dist/CmrComponents/CmrCheckbox/CmrCheckbox.css +29 -0
  8. package/dist/CmrComponents/CmrCheckbox/CmrCheckbox.d.ts +14 -0
  9. package/dist/CmrComponents/CmrCheckbox/CmrCheckbox.js +30 -0
  10. package/dist/CmrComponents/CmrCheckbox/index.d.ts +1 -0
  11. package/dist/CmrComponents/CmrCheckbox/index.js +1 -0
  12. package/dist/CmrComponents/CmrColorPicker/CmrColorPicker.d.ts +8 -0
  13. package/dist/CmrComponents/CmrColorPicker/CmrColorPicker.js +29 -0
  14. package/dist/CmrComponents/CmrColorPicker/CmrColorPicker.scss +27 -0
  15. package/dist/CmrComponents/CmrInput/CmrInput.css +27 -0
  16. package/dist/CmrComponents/CmrInput/CmrInput.d.ts +17 -0
  17. package/dist/CmrComponents/CmrInput/CmrInput.js +29 -0
  18. package/dist/CmrComponents/CmrInput/index.d.ts +1 -0
  19. package/dist/CmrComponents/CmrInput/index.js +1 -0
  20. package/dist/CmrComponents/CmrRadioGroup/CmrRadioGroup.css +25 -0
  21. package/dist/CmrComponents/CmrRadioGroup/CmrRadioGroup.d.ts +15 -0
  22. package/dist/CmrComponents/CmrRadioGroup/CmrRadioGroup.js +37 -0
  23. package/dist/CmrComponents/CmrRadioGroup/index.d.ts +1 -0
  24. package/dist/CmrComponents/CmrRadioGroup/index.js +1 -0
  25. package/dist/CmrComponents/CmrSelect/CmrSelect.css +1 -0
  26. package/dist/CmrComponents/CmrSelect/CmrSelect.d.ts +24 -0
  27. package/dist/CmrComponents/CmrSelect/CmrSelect.js +46 -0
  28. package/dist/CmrComponents/CmrSelect/index.d.ts +1 -0
  29. package/dist/CmrComponents/CmrSelect/index.js +1 -0
  30. package/dist/CmrComponents/checkbox/Checkbox.css +8 -0
  31. package/dist/CmrComponents/checkbox/Checkbox.d.ts +15 -0
  32. package/dist/CmrComponents/checkbox/Checkbox.js +25 -0
  33. package/dist/CmrComponents/collapse/Collapse.css +3 -0
  34. package/dist/CmrComponents/collapse/Collapse.d.ts +18 -0
  35. package/dist/CmrComponents/collapse/Collapse.js +87 -0
  36. package/dist/CmrComponents/dialogue/Confirmation.d.ts +20 -0
  37. package/dist/CmrComponents/dialogue/Confirmation.js +36 -0
  38. package/dist/CmrComponents/dialogue/DeletionDialog.d.ts +4 -0
  39. package/dist/CmrComponents/dialogue/DeletionDialog.js +39 -0
  40. package/dist/CmrComponents/dialogue/EditConfirmation.d.ts +13 -0
  41. package/dist/CmrComponents/dialogue/EditConfirmation.js +45 -0
  42. package/dist/CmrComponents/double-slider/DualSlider.d.ts +21 -0
  43. package/dist/CmrComponents/double-slider/DualSlider.js +152 -0
  44. package/dist/CmrComponents/double-slider/InvertibleDualSlider.d.ts +24 -0
  45. package/dist/CmrComponents/double-slider/InvertibleDualSlider.js +174 -0
  46. package/dist/CmrComponents/gui-slider/ControlledSlider.d.ts +9 -0
  47. package/dist/CmrComponents/gui-slider/ControlledSlider.js +96 -0
  48. package/dist/CmrComponents/gui-slider/Slider.d.ts +20 -0
  49. package/dist/CmrComponents/gui-slider/Slider.js +127 -0
  50. package/dist/CmrComponents/header/Header.d.ts +17 -0
  51. package/dist/CmrComponents/header/Header.js +90 -0
  52. package/dist/CmrComponents/header/Header.scss +32 -0
  53. package/dist/CmrComponents/input-number/InputNumber.css +0 -0
  54. package/dist/CmrComponents/input-number/InputNumber.d.ts +17 -0
  55. package/dist/CmrComponents/input-number/InputNumber.js +30 -0
  56. package/dist/CmrComponents/label/Label.css +13 -0
  57. package/dist/CmrComponents/label/Label.d.ts +9 -0
  58. package/dist/CmrComponents/label/Label.js +18 -0
  59. package/dist/CmrComponents/panel/Panel.css +5 -0
  60. package/dist/CmrComponents/panel/Panel.d.ts +12 -0
  61. package/dist/CmrComponents/panel/Panel.js +42 -0
  62. package/dist/CmrComponents/rename/edit.d.ts +7 -0
  63. package/dist/CmrComponents/rename/edit.js +117 -0
  64. package/dist/CmrComponents/select-upload/SelectUpload.css +26 -0
  65. package/dist/CmrComponents/select-upload/SelectUpload.d.ts +33 -0
  66. package/dist/CmrComponents/select-upload/SelectUpload.js +90 -0
  67. package/dist/CmrComponents/tk-dualrange/TKDualRange.d.ts +17 -0
  68. package/dist/CmrComponents/tk-dualrange/TKDualRange.js +65 -0
  69. package/dist/CmrComponents/tk-dualrange/tk-dual-range.css +140 -0
  70. package/dist/CmrComponents/tooltip/Tooltip.css +0 -0
  71. package/dist/CmrComponents/tooltip/Tooltip.d.ts +18 -0
  72. package/dist/CmrComponents/tooltip/Tooltip.js +30 -0
  73. package/dist/CmrComponents/upload/Upload.css +5 -0
  74. package/dist/CmrComponents/upload/Upload.d.ts +80 -0
  75. package/dist/CmrComponents/upload/Upload.js +185 -0
  76. package/dist/CmrComponents/upload/UploadWindow.d.ts +15 -0
  77. package/dist/CmrComponents/upload/UploadWindow.js +286 -0
  78. package/dist/CmrTable/CmrTable.css +26 -0
  79. package/dist/CmrTable/CmrTable.d.ts +13 -0
  80. package/dist/CmrTable/CmrTable.js +47 -0
  81. package/dist/CmrTabs/CmrTabs.d.ts +7 -0
  82. package/dist/CmrTabs/CmrTabs.js +64 -0
  83. package/dist/CmrTabs/tab.model.d.ts +12 -0
  84. package/dist/CmrTabs/tab.model.js +1 -0
  85. package/dist/core/app/main/Main.d.ts +6 -0
  86. package/dist/core/app/main/Main.js +18 -0
  87. package/dist/core/app/results/Logs.d.ts +1 -0
  88. package/dist/core/app/results/Logs.js +33 -0
  89. package/dist/core/app/results/PreprocessJob.d.ts +1 -0
  90. package/dist/core/app/results/PreprocessJob.js +100 -0
  91. package/dist/core/app/results/Results.d.ts +15 -0
  92. package/dist/core/app/results/Results.js +372 -0
  93. package/dist/core/app/results/Results.scss +92 -0
  94. package/dist/core/app/results/Rois.d.ts +11 -0
  95. package/dist/core/app/results/Rois.js +269 -0
  96. package/dist/core/app/settings/Settings.d.ts +1 -0
  97. package/dist/core/app/settings/Settings.js +109 -0
  98. package/dist/core/app/signin/ForgotPassword.d.ts +3 -0
  99. package/dist/core/app/signin/ForgotPassword.js +142 -0
  100. package/dist/core/app/signin/Register.d.ts +3 -0
  101. package/dist/core/app/signin/Register.js +126 -0
  102. package/dist/core/app/signin/Signin.d.ts +5 -0
  103. package/dist/core/app/signin/Signin.js +84 -0
  104. package/dist/core/app/signin/Signin.scss +86 -0
  105. package/dist/core/app/upload/Upload.d.ts +3 -0
  106. package/dist/core/app/upload/Upload.js +261 -0
  107. package/dist/core/app/upload/Upload.scss +0 -0
  108. package/dist/core/common/components/CmrColorPicker/CmrColorPicker.d.ts +8 -0
  109. package/dist/core/common/components/CmrColorPicker/CmrColorPicker.js +29 -0
  110. package/dist/core/common/components/CmrColorPicker/CmrColorPicker.scss +27 -0
  111. package/dist/core/common/components/NiivueTools/Niivue.css +8 -0
  112. package/dist/core/common/components/NiivueTools/Niivue.d.ts +14 -0
  113. package/dist/core/common/components/NiivueTools/Niivue.js +1270 -0
  114. package/dist/core/common/components/NiivueTools/NiivuePatcher.js +1875 -0
  115. package/dist/core/common/components/NiivueTools/components/ColorPicker.d.ts +5 -0
  116. package/dist/core/common/components/NiivueTools/components/ColorPicker.js +68 -0
  117. package/dist/core/common/components/NiivueTools/components/DrawPlatte.d.ts +10 -0
  118. package/dist/core/common/components/NiivueTools/components/DrawPlatte.js +88 -0
  119. package/dist/core/common/components/NiivueTools/components/DrawToolKit.d.ts +32 -0
  120. package/dist/core/common/components/NiivueTools/components/DrawToolKit.js +164 -0
  121. package/dist/core/common/components/NiivueTools/components/EraserPlatte.d.ts +10 -0
  122. package/dist/core/common/components/NiivueTools/components/EraserPlatte.js +43 -0
  123. package/dist/core/common/components/NiivueTools/components/Layer.d.ts +10 -0
  124. package/dist/core/common/components/NiivueTools/components/Layer.js +117 -0
  125. package/dist/core/common/components/NiivueTools/components/LayersPanel.d.ts +8 -0
  126. package/dist/core/common/components/NiivueTools/components/LayersPanel.js +108 -0
  127. package/dist/core/common/components/NiivueTools/components/LocationTable.d.ts +9 -0
  128. package/dist/core/common/components/NiivueTools/components/LocationTable.js +42 -0
  129. package/dist/core/common/components/NiivueTools/components/MaskPlatte.d.ts +10 -0
  130. package/dist/core/common/components/NiivueTools/components/MaskPlatte.js +123 -0
  131. package/dist/core/common/components/NiivueTools/components/NiivuePanel.d.ts +34 -0
  132. package/dist/core/common/components/NiivueTools/components/NiivuePanel.js +305 -0
  133. package/dist/core/common/components/NiivueTools/components/NumberPicker.d.ts +8 -0
  134. package/dist/core/common/components/NiivueTools/components/NumberPicker.js +40 -0
  135. package/dist/core/common/components/NiivueTools/components/SettingsPanel.d.ts +7 -0
  136. package/dist/core/common/components/NiivueTools/components/SettingsPanel.js +30 -0
  137. package/dist/core/common/components/NiivueTools/components/Switch.d.ts +5 -0
  138. package/dist/core/common/components/NiivueTools/components/Switch.js +26 -0
  139. package/dist/core/common/components/NiivueTools/components/Toolbar.d.ts +40 -0
  140. package/dist/core/common/components/NiivueTools/components/Toolbar.js +184 -0
  141. package/dist/core/common/components/NiivueTools/components/Toolbar.scss +39 -0
  142. package/dist/core/common/components/NiivueTools/components/stats.d.ts +2 -0
  143. package/dist/core/common/components/NiivueTools/components/stats.js +13 -0
  144. package/dist/core/common/components/NiivueTools/index.css +14 -0
  145. package/dist/core/common/components/NiivueTools/util.js +309 -0
  146. package/dist/core/common/components/footer/Footer.d.ts +3 -0
  147. package/dist/core/common/components/footer/Footer.js +20 -0
  148. package/dist/core/common/components/footer/Footer.scss +5 -0
  149. package/dist/core/common/utilities/AuthenticatedRequests.d.ts +16 -0
  150. package/dist/core/common/utilities/AuthenticatedRequests.js +158 -0
  151. package/dist/core/common/utilities/CalendarHelper.d.ts +5 -0
  152. package/dist/core/common/utilities/CalendarHelper.js +27 -0
  153. package/dist/core/common/utilities/DownloadFromText.d.ts +3 -0
  154. package/dist/core/common/utilities/DownloadFromText.js +20 -0
  155. package/dist/core/common/utilities/StoreToRequest.d.ts +1 -0
  156. package/dist/core/common/utilities/StoreToRequest.js +4 -0
  157. package/dist/core/common/utilities/SystemUtilities.d.ts +4 -0
  158. package/dist/core/common/utilities/SystemUtilities.js +79 -0
  159. package/dist/core/common/utilities/file-transformation/anonymize.d.ts +1 -0
  160. package/dist/core/common/utilities/file-transformation/anonymize.js +114 -0
  161. package/dist/core/common/utilities/file-transformation/utilities.d.ts +2 -0
  162. package/dist/core/common/utilities/file-transformation/utilities.js +23 -0
  163. package/dist/core/common/utilities/index.d.ts +25 -0
  164. package/dist/core/common/utilities/index.js +118 -0
  165. package/dist/core/common/utilities/parse-jwt.d.ts +1 -0
  166. package/dist/core/common/utilities/parse-jwt.js +14 -0
  167. package/dist/core/components/PasswordRequirements.d.ts +7 -0
  168. package/dist/core/components/PasswordRequirements.js +30 -0
  169. package/dist/core/config/AppConfig.d.ts +5 -0
  170. package/dist/core/config/AppConfig.js +42 -0
  171. package/dist/core/config/types.d.ts +40 -0
  172. package/dist/core/config/types.js +1 -0
  173. package/dist/core/features/authenticate/authenticateActionCreation.d.ts +46 -0
  174. package/dist/core/features/authenticate/authenticateActionCreation.js +326 -0
  175. package/dist/core/features/authenticate/authenticateSlice.d.ts +45 -0
  176. package/dist/core/features/authenticate/authenticateSlice.js +203 -0
  177. package/dist/core/features/data/dataActionCreation.d.ts +40 -0
  178. package/dist/core/features/data/dataActionCreation.js +340 -0
  179. package/dist/core/features/data/dataSlice.d.ts +37 -0
  180. package/dist/core/features/data/dataSlice.js +87 -0
  181. package/dist/core/features/jobs/jobActionCreation.d.ts +35 -0
  182. package/dist/core/features/jobs/jobActionCreation.js +242 -0
  183. package/dist/core/features/jobs/jobsSlice.d.ts +57 -0
  184. package/dist/core/features/jobs/jobsSlice.js +54 -0
  185. package/dist/core/features/rois/resultActionCreation.d.ts +21 -0
  186. package/dist/core/features/rois/resultActionCreation.js +114 -0
  187. package/dist/core/features/rois/resultSlice.d.ts +24 -0
  188. package/dist/core/features/rois/resultSlice.js +68 -0
  189. package/dist/core/features/rois/roiTypes.d.ts +44 -0
  190. package/dist/core/features/rois/roiTypes.js +1 -0
  191. package/dist/core/features/setup/setupActionCreation.d.ts +7 -0
  192. package/dist/core/features/setup/setupActionCreation.js +100 -0
  193. package/dist/core/index.d.ts +22 -0
  194. package/dist/core/index.js +27 -0
  195. package/dist/core/store/configureStore.d.ts +13 -0
  196. package/dist/core/store/configureStore.js +38 -0
  197. package/dist/core/store/hooks.d.ts +11 -0
  198. package/dist/core/store/hooks.js +5 -0
  199. package/dist/core/utils/passwordValidation.d.ts +25 -0
  200. package/dist/core/utils/passwordValidation.js +19 -0
  201. package/dist/index.d.ts +29 -329
  202. package/dist/index.js +26 -1402
  203. package/dist/style.css +47 -0
  204. package/package.json +309 -41
  205. package/dist/index.css +0 -170
  206. package/dist/index.mjs +0 -1354
@@ -0,0 +1,1270 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
21
+ var __generator = (this && this.__generator) || function (thisArg, body) {
22
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
23
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24
+ function verb(n) { return function (v) { return step([n, v]); }; }
25
+ function step(op) {
26
+ if (f) throw new TypeError("Generator is already executing.");
27
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
28
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
29
+ if (y = 0, t) op = [op[0] & 2, t.value];
30
+ switch (op[0]) {
31
+ case 0: case 1: t = op; break;
32
+ case 4: _.label++; return { value: op[1], done: false };
33
+ case 5: _.label++; y = op[1]; op = [0]; continue;
34
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
35
+ default:
36
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40
+ if (t[2]) _.ops.pop();
41
+ _.trys.pop(); continue;
42
+ }
43
+ op = body.call(thisArg, _);
44
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
+ }
47
+ };
48
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
49
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
50
+ if (ar || !(i in from)) {
51
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
52
+ ar[i] = from[i];
53
+ }
54
+ }
55
+ return to.concat(ar || Array.prototype.slice.call(from));
56
+ };
57
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
58
+ import React, { useState } from "react";
59
+ import { Box, Button } from "@mui/material";
60
+ import { NVImage } from "@niivue/niivue";
61
+ import { SettingsPanel } from "./components/SettingsPanel";
62
+ import { NumberPicker } from "./components/NumberPicker";
63
+ import { ColorPicker } from "./components/ColorPicker";
64
+ import { LayersPanel } from "./components/LayersPanel";
65
+ import { NiivuePanel } from "./components/NiivuePanel";
66
+ import { Niivue } from "./NiivuePatcher";
67
+ import NVSwitch from "./components/Switch";
68
+ import Toolbar from "./components/Toolbar";
69
+ import Layer from "./components/Layer";
70
+ import "./Niivue.css";
71
+ import { CmrEditConfirmation } from "../../../../index";
72
+ import axios from "axios";
73
+ import { getEndpoints } from "../../../config/AppConfig";
74
+ import Confirmation from "../../../../CmrComponents/dialogue/Confirmation";
75
+ import Plotly from "plotly.js-dist-min";
76
+ import { calculateMean, calculateStandardDeviation } from "./components/stats";
77
+ import JSZip from "jszip";
78
+ import { getMax, getMin } from "../../utilities";
79
+ import { getPipelineROI } from "../../../features/rois/resultActionCreation";
80
+ import { useAppDispatch, useAppSelector } from "../../../store/hooks";
81
+ import { AuthenticatedHttpClient } from "../../utilities/AuthenticatedRequests";
82
+ export var nv = new Niivue({
83
+ loadingText: "",
84
+ isColorbar: true,
85
+ isRadiologicalConvention: true,
86
+ fontSizeScaling: 0.04,
87
+ fontMinPx: 8,
88
+ colorbarHeight: 0.02,
89
+ dragMode: "pan",
90
+ // crosshairColor: [0.098,0.453,0.824]
91
+ crosshairColor: [1, 1, 0],
92
+ fontColor: [0.0, 0.94, 0.37, 1],
93
+ isNearestInterpolation: true,
94
+ isFilledPen: true,
95
+ drawPen: 1
96
+ });
97
+ window.nv = nv;
98
+ // The NiiVue component wraps all other components in the UI.
99
+ // It is exported so that it can be used in other projects easily
100
+ export default function NiiVueport(props) {
101
+ var _this = this;
102
+ var selectedVolume = props.selectedVolume;
103
+ var setSelectedVolume = props.setSelectedVolume;
104
+ var setWarning = props.setWarning, setWarningOpen = props.setWarningOpen;
105
+ // const nv = props.nv;
106
+ var _a = React.useState(false), openSettings = _a[0], setOpenSettings = _a[1];
107
+ var _b = React.useState(false), openLayers = _b[0], setOpenLayers = _b[1];
108
+ var _c = React.useState(nv.opts.crosshairColor), crosshairColor = _c[0], setCrosshairColor = _c[1];
109
+ var _d = React.useState(nv.opts.selectionBoxColor), selectionBoxColor = _d[0], setSelectionBoxColor = _d[1];
110
+ var _e = React.useState(nv.opts.backColor), backColor = _e[0], setBackColor = _e[1];
111
+ var _f = React.useState(nv.opts.clipPlaneColor), clipPlaneColor = _f[0], setClipPlaneColor = _f[1];
112
+ var _g = React.useState(nv.volumes), layers = _g[0], setLayers = _g[1];
113
+ var _h = React.useState(false), cornerText = _h[0], setCornerText = _h[1];
114
+ var _j = React.useState(true), radiological = _j[0], setRadiological = _j[1];
115
+ var _k = React.useState(false), crosshair3D = _k[0], setCrosshair3D = _k[1];
116
+ var _l = React.useState(nv.opts.textHeight), textSize = _l[0], setTextSize = _l[1];
117
+ var _m = React.useState(nv.opts.isColorbar), colorBar = _m[0], setColorBar = _m[1];
118
+ var _o = React.useState(nv.opts.isSliceMM), worldSpace = _o[0], setWorldSpace = _o[1];
119
+ var _p = React.useState(nv.currentClipPlaneIndex > 0 ? true : false), clipPlane = _p[0], setClipPlane = _p[1];
120
+ // TODO: add crosshair size state and setter
121
+ var _q = React.useState(1.0), opacity = _q[0], setopacity = _q[1];
122
+ var _r = React.useState(nv.opts.drawingEnabled), drawingEnabled = _r[0], setDrawingEnabled = _r[1];
123
+ var _s = React.useState(nv.opts.drawPen), drawPen = _s[0], setDrawPen = _s[1];
124
+ var _t = React.useState(0.8), drawOpacity = _t[0], setDrawOpacity = _t[1];
125
+ var _u = React.useState(nv.opts.crosshairColor[3]), crosshairOpacity = _u[0], setCrosshairOpacity = _u[1];
126
+ var _v = React.useState(nv.opts.clipPlaneColor[3]), clipPlaneOpacity = _v[0], setClipPlaneOpacity = _v[1];
127
+ // Remembers the last crosshair position in millimeter space across volume switches
128
+ var lastMMRef = React.useRef(null);
129
+ var _w = React.useState(true), locationTableVisible = _w[0], setLocationTableVisible = _w[1];
130
+ var _x = React.useState([]), locationData = _x[0], setLocationData = _x[1];
131
+ var _y = React.useState(2), decimalPrecision = _y[0], setDecimalPrecision = _y[1];
132
+ var _z = React.useState(nv.opts.isOrientCube), orientCube = _z[0], setOrientCube = _z[1];
133
+ var _0 = React.useState(nv.opts.isRuler), ruler = _0[0], setRuler = _0[1];
134
+ var _1 = React.useState(nv.opts.multiplanarPadPixels), multiplanarPadPixels = _1[0], setMultiplanarPadPixels = _1[1];
135
+ var _2 = React.useState(nv.opts.maxDrawUndoBitmaps), maxDrawUndoBitmaps = _2[0], setMaxDrawUndoBitmaps = _2[1];
136
+ var _3 = React.useState(nv.opts.sagittalNoseLeft), sagittalNoseLeft = _3[0], setSagittalNoseLeft = _3[1];
137
+ var _4 = React.useState(nv.opts.rulerWidth), rulerWidth = _4[0], setRulerWidth = _4[1];
138
+ var _5 = React.useState(nv.opts.longTouchTimeout), longTouchTimeout = _5[0], setLongTouchTimeout = _5[1];
139
+ var _6 = React.useState(nv.opts.doubleTouchTimeout), doubleTouchTimeout = _6[0], setDoubleTouchTimeout = _6[1];
140
+ var _7 = React.useState(nv.opts.isDragShowsMeasurementTool), dragToMeasure = _7[0], setDragToMeasure = _7[1];
141
+ var _8 = React.useState(nv.opts.rulerColor), rulerColor = _8[0], setRulerColor = _8[1];
142
+ var _9 = React.useState(nv.opts.rulerColor[3]), rulerOpacity = _9[0], setRulerOpacity = _9[1];
143
+ var _10 = React.useState(false), highDPI = _10[0], setHighDPI = _10[1];
144
+ var histoRef = React.useRef(null);
145
+ var _11 = React.useState([]), rois = _11[0], setROIs = _11[1];
146
+ var _12 = React.useState(true), showCrosshair = _12[0], setShowCrosshair = _12[1];
147
+ var _13 = useState(1), brushSize = _13[0], setBrushSize = _13[1];
148
+ var _14 = useState("absolute"), complexMode = _14[0], setComplexMode = _14[1];
149
+ var _15 = useState(["absolute"]), complexOptions = _15[0], setComplexOptions = _15[1];
150
+ var _16 = useState(true), roiVisible = _16[0], setROIVisible = _16[1];
151
+ var _17 = useState(0.8), drawingOpacity = _17[0], setDrawingOpacity = _17[1];
152
+ var _18 = useState(0), min = _18[0], setMin = _18[1];
153
+ var _19 = useState(1), max = _19[0], setMax = _19[1];
154
+ var _20 = useState(false), textsVisible = _20[0], setTextsVisible = _20[1];
155
+ var _21 = useState({ a: 1, b: 0 }), transformFactors = _21[0], setTransformFactors = _21[1];
156
+ var _22 = useState(false), saving = _22[0], setSaving = _22[1];
157
+ // Gamma settings
158
+ var _23 = React.useState(1.0), gamma = _23[0], setGamma = _23[1];
159
+ var _24 = React.useState(0), gammaKey = _24[0], setGammaKey = _24[1];
160
+ // Niivue → React bridge so other places (Toolbar) can force the UI to reset
161
+ nv.onResetGamma = function () {
162
+ setGamma(1.0);
163
+ setGammaKey(function (k) { return k + 1; }); // re-mounts the slider to reflect the reset
164
+ };
165
+ React.useEffect(function () {
166
+ resampleImage();
167
+ // histogram.current?.addEventListener('resize',()=>props.resampleImage());
168
+ }, [histoRef]);
169
+ React.useEffect(function () {
170
+ if (nv.volumes.length !== 0) {
171
+ setLayers(__spreadArray([], nv.volumes, true));
172
+ setBoundMins(nv.frac2mm([0, 0, 0]));
173
+ setBoundMaxs(nv.frac2mm([1, 1, 1]));
174
+ // setMMs(nv.frac2mm([0.5, 0.5, 0.5])); // Commented to prevent recentering on volume load; we now re-apply saved crosshair if available
175
+ try {
176
+ // Initialize sliders to the engine's current crosshair (in mm), not a hard-coded 0.5
177
+ setMMs(nv.frac2mm(nv.scene.crosshairPos));
178
+ }
179
+ catch (_a) { }
180
+ setTimeout(function (args) { return nv.resizeListener(); }, 700);
181
+ }
182
+ }, []);
183
+ // Load initial volume on mount.
184
+ // Note: nv.loadVolumes() triggers onImageLoaded callback (line 285)
185
+ // which handles all the setup automatically.
186
+ React.useEffect(function () {
187
+ var loadInitialVolume = function () { return __awaiter(_this, void 0, void 0, function () {
188
+ var e_1;
189
+ return __generator(this, function (_a) {
190
+ switch (_a.label) {
191
+ case 0:
192
+ if (!props.niis[selectedVolume]) return [3 /*break*/, 4];
193
+ _a.label = 1;
194
+ case 1:
195
+ _a.trys.push([1, 3, , 4]);
196
+ // loadVolumes calls onImageLoaded which does all setup
197
+ return [4 /*yield*/, nv.loadVolumes([niiToVolume(props.niis[selectedVolume])])];
198
+ case 2:
199
+ // loadVolumes calls onImageLoaded which does all setup
200
+ _a.sent();
201
+ // Force a multiplanar view switch to trigger proper rendering, then switch back
202
+ // TODO: fix this horrible hack
203
+ setTimeout(function () {
204
+ nv.setSliceType(nv.sliceTypeMultiplanar);
205
+ // Then switch to the desired slice type
206
+ setTimeout(function () {
207
+ nvUpdateSliceType(sliceType);
208
+ if (!lastMMRef.current) {
209
+ try {
210
+ setMMs(nv.frac2mm(nv.scene.crosshairPos));
211
+ }
212
+ catch (_a) { }
213
+ }
214
+ }, 50);
215
+ }, 100);
216
+ return [3 /*break*/, 4];
217
+ case 3:
218
+ e_1 = _a.sent();
219
+ console.error("Error loading initial volume:", e_1);
220
+ setWarning("Error loading results, please check internet connectivity");
221
+ setWarningOpen(true);
222
+ setTimeout(function () {
223
+ setWarningOpen(false);
224
+ setWarning("");
225
+ }, 2500);
226
+ return [3 /*break*/, 4];
227
+ case 4: return [2 /*return*/];
228
+ }
229
+ });
230
+ }); };
231
+ loadInitialVolume();
232
+ }, []); // Empty dependency array - only run on mount
233
+ React.useEffect(function () {
234
+ // console.log(props.niis[props.selectedVolume]);
235
+ //Wait for other rendering processes to complete before applying styles
236
+ stylingProxy(props.niis[props.selectedVolume]);
237
+ }, [props.selectedVolume, props.niis]);
238
+ // only run this when the component is mounted on the page
239
+ // or else it will be recursive and continuously add all
240
+ // initial images supplied to the NiiVue component
241
+ //
242
+ // All subsequent imgaes should be added via a
243
+ // button or drag and drop
244
+ // React.useEffect(async ()=>{
245
+ // // props.volumes.map(async (vol)=>{
246
+ // // let image = await NVImage.loadFromUrl({url:vol.url})
247
+ // // nv.addVolume(image)
248
+ // // setLayers([...nv.volumes])
249
+ // // })
250
+ // await nv.loadVolumes(props.volumes)
251
+ // setLayers([...nv.volumes])
252
+ // }, [])
253
+ // values dualslider
254
+ var _25 = useState(0), rangeKey = _25[0], setRangeKey = _25[1];
255
+ nv.onResetContrast = function () {
256
+ setRangeKey(rangeKey + 1);
257
+ };
258
+ var _26 = useState([0, 0, 0]), boundMins = _26[0], setBoundMins = _26[1];
259
+ var _27 = useState([1, 1, 1]), boundMaxs = _27[0], setBoundMaxs = _27[1];
260
+ var _28 = useState([0.5, 0.5, 0.5]), mms = _28[0], setMMs = _28[1];
261
+ nv.onImageLoaded = function () {
262
+ var _a;
263
+ if (nv.volumes.length > 1) {
264
+ nv.loadVolumes([niiToVolume(props.niis[props.selectedVolume])]);
265
+ setWarning("Error loading results, please check internet connectivity");
266
+ setWarningOpen(true);
267
+ setTimeout(function () {
268
+ setWarningOpen(false);
269
+ setWarning("");
270
+ }, 2500);
271
+ return;
272
+ }
273
+ // console.log(nv.volumes);
274
+ setLayers(__spreadArray([], nv.volumes, true));
275
+ setBoundMins(nv.frac2mm([0, 0, 0]));
276
+ setBoundMaxs(nv.frac2mm([1, 1, 1]));
277
+ // setMMs(nv.frac2mm([0.5, 0.5, 0.5])); // Commented to prevent recentering on volume load; we now re-apply saved crosshair if available
278
+ if (verifyComplex(nv.volumes[0]))
279
+ //Check if there are complex components
280
+ nvSetDisplayedVoxels("absolute");
281
+ else
282
+ nvSetDisplayedVoxels("absolute");
283
+ var volume = nv.volumes[0];
284
+ nv.setGamma(1.0);
285
+ (_a = nv.onResetGamma) === null || _a === void 0 ? void 0 : _a.call(nv);
286
+ nv.resetScene();
287
+ nvSetDragMode(dragMode); // keep engine behavior in sync with dropdown
288
+ // Re-apply world/voxel mode and last crosshair after resets
289
+ nv.setSliceMM(worldSpace);
290
+ applySavedCrosshairIfAny();
291
+ // NEW: keep display mode consistent after resets
292
+ nvUpdateSliceType(sliceType);
293
+ if (!lastMMRef.current) {
294
+ try {
295
+ setMMs(nv.frac2mm(nv.scene.crosshairPos));
296
+ }
297
+ catch (_b) { }
298
+ }
299
+ // Force a complete re-render with texture rebinding
300
+ // This ensures textures are properly bound in the current view mode
301
+ setTimeout(function () {
302
+ nv.updateGLVolume();
303
+ nv.drawScene();
304
+ }, 100);
305
+ };
306
+ function checkRange(numbers) {
307
+ // console.log(numbers);
308
+ var range_min = getMin(numbers);
309
+ var range_max = getMax(numbers);
310
+ var range = range_max - range_min;
311
+ if (range == 0) {
312
+ return numbers;
313
+ }
314
+ if (range < 1e-2) {
315
+ // Find a suitable 'a' that is a whole power of 10
316
+ // Here, we want 'a' to scale the range to fit within [1, 10)
317
+ var a_1 = 1;
318
+ var power = 0;
319
+ while (range * a_1 < 1) {
320
+ a_1 *= 10;
321
+ power += 1;
322
+ }
323
+ // Calculate 'b' such that the minimum transformed value is 1 (x = 1)
324
+ var b_1 = Math.floor(a_1 * range_min - ((a_1 * range_min) % 10)) / a_1;
325
+ console.log(b_1);
326
+ // Apply the transformation ax + b
327
+ var transformed = numbers.map(function (y) { return a_1 * y - a_1 * b_1; });
328
+ setTransformFactors({ a: a_1, b: b_1 });
329
+ nv.transformA = a_1;
330
+ nv.transformB = b_1;
331
+ nv.power = power;
332
+ return transformed;
333
+ }
334
+ else {
335
+ // If range is not smaller than 10E-2, return the original array
336
+ setTransformFactors({ a: 1, b: 0 });
337
+ nv.transformA = 1;
338
+ nv.transformB = 0;
339
+ nv.power = undefined;
340
+ return numbers;
341
+ }
342
+ }
343
+ function verifyComplex(volume) {
344
+ volume.real = volume.img;
345
+ setComplexMode("absolute");
346
+ // Ensure volume.imaginary is defined and has the same length as volume.img
347
+ if (!volume.imaginary || volume.imaginary.length !== volume.img.length) {
348
+ setComplexOptions(["absolute", "real"]);
349
+ // Initialize absolute and phase arrays
350
+ volume.absolute = new volume.img.constructor(volume.img.length);
351
+ // Calculate absolute and phase values
352
+ for (var i = 0; i < volume.img.length; i++) {
353
+ var realPart = volume.real[i];
354
+ // Calculate the absolute value (magnitude)
355
+ volume.absolute[i] = Math.sqrt(realPart * realPart);
356
+ }
357
+ return false;
358
+ }
359
+ var allZero = true;
360
+ // Test for imaginary nulls
361
+ for (var i = 0; i < volume.img.length; i++) {
362
+ if (volume.imaginary[i] !== 0) {
363
+ allZero = false;
364
+ break;
365
+ }
366
+ }
367
+ // Initialize absolute and phase arrays
368
+ volume.absolute = new Float32Array(volume.img.length);
369
+ volume.phase = new Float32Array(volume.img.length);
370
+ // Calculate absolute and phase values
371
+ for (var i = 0; i < volume.img.length; i++) {
372
+ var realPart = volume.real[i];
373
+ var imaginaryPart = volume.imaginary[i];
374
+ // Calculate the absolute value (magnitude)
375
+ volume.absolute[i] = Math.sqrt(realPart * realPart + imaginaryPart * imaginaryPart);
376
+ // Calculate the phase (argument)
377
+ volume.phase[i] = Math.atan2(imaginaryPart, realPart);
378
+ }
379
+ setComplexOptions(allZero
380
+ ? ["absolute", "real"]
381
+ : ["absolute", "imaginary", "real", "phase"]);
382
+ return !allZero;
383
+ }
384
+ function nvSetDisplayedVoxels(voxelType) {
385
+ setComplexMode(voxelType);
386
+ var volume = nv.volumes[0];
387
+ switch (voxelType) {
388
+ case "phase":
389
+ volume.img = checkRange(volume.phase);
390
+ break;
391
+ case "absolute":
392
+ volume.img = checkRange(volume.absolute);
393
+ break;
394
+ case "real":
395
+ volume.img = checkRange(volume.real);
396
+ break;
397
+ case "imaginary":
398
+ volume.img = checkRange(volume.imaginary);
399
+ break;
400
+ }
401
+ volume.calMinMax();
402
+ setMin(volume.cal_min);
403
+ setMax(volume.cal_max);
404
+ volume.vox_min = getMin(volume.img);
405
+ volume.vox_max = getMax(volume.img);
406
+ nv.setVolume(volume);
407
+ nv.drawScene();
408
+ resampleImage();
409
+ }
410
+ nv.onLocationChange = function (data) {
411
+ if (data.values[0]) {
412
+ setMMs(__spreadArray([], data.values[0].mm, true)); // ensure new array -> React re-renders
413
+ lastMMRef.current = __spreadArray([], data.values[0].mm, true); // keep a fresh copy in the ref too
414
+ data.values[0].transformA = nv.transformA;
415
+ data.values[0].transformB = nv.transformB;
416
+ data.values[0].power = nv.power;
417
+ }
418
+ setLocationData(data.values);
419
+ // if(drawingEnabled){
420
+ // setDrawingChanged(true);
421
+ // // resampleImage();
422
+ // }
423
+ // console.log(nv.scene.pan2Dxyzmm);
424
+ };
425
+ nv.onMouseUp = function (data) {
426
+ if (drawingEnabled) {
427
+ setDrawingChanged(true);
428
+ resampleImage();
429
+ }
430
+ };
431
+ /**
432
+ * Way to test all value changes
433
+ */
434
+ nv.onIntensityChange = function () {
435
+ var volume = nv.volumes[0];
436
+ setMin(volume.cal_min);
437
+ setMax(volume.cal_max);
438
+ };
439
+ // nv.createEmptyDrawing();
440
+ // construct an array of <Layer> components. Each layer is a NVImage or NVMesh
441
+ var layerList = layers.map(function (layer, index) {
442
+ return index === 0 ? ( //Yuelong: we shall expect only one effective layer in this implementation
443
+ _jsx(Layer, { image: layer, nv: nv, nii: props.niis[props.selectedVolume], onColorMapChange: nvUpdateColorMap, onRemoveLayer: nvRemoveLayer, onOpacityChange: nvUpdateLayerOpacity, colorMapValues: nv.colormapFromKey(layer.colormap), getColorMapValues: function (colorMapName) {
444
+ return nv.colormapFromKey(colorMapName);
445
+ } }, layer.name)) : undefined;
446
+ });
447
+ function addLayer(file) {
448
+ return __awaiter(this, void 0, void 0, function () {
449
+ var nvimage;
450
+ return __generator(this, function (_a) {
451
+ switch (_a.label) {
452
+ case 0: return [4 /*yield*/, NVImage.loadFromFile({
453
+ file: file
454
+ })];
455
+ case 1:
456
+ nvimage = _a.sent();
457
+ nv.addVolume(nvimage);
458
+ setLayers(__spreadArray([], nv.volumes, true));
459
+ return [2 /*return*/];
460
+ }
461
+ });
462
+ });
463
+ }
464
+ function toggleSettings() {
465
+ setOpenSettings(!openSettings);
466
+ }
467
+ function toggleLayers() {
468
+ setOpenLayers(!openLayers);
469
+ }
470
+ function toggleLocationTable() {
471
+ setLocationTableVisible(!locationTableVisible);
472
+ }
473
+ function toggleROIVisible() {
474
+ if (roiVisible) {
475
+ setDrawingOpacity(nv.drawOpacity);
476
+ setROIVisible(false);
477
+ nv.setDrawOpacity(0);
478
+ resampleImage();
479
+ }
480
+ else {
481
+ nv.setDrawOpacity(drawingOpacity);
482
+ setROIVisible(true);
483
+ resampleImage();
484
+ }
485
+ }
486
+ function nvUpdateDrawingOpacity(opacity) {
487
+ setDrawingOpacity(opacity);
488
+ if (roiVisible) {
489
+ nv.setDrawOpacity(opacity);
490
+ }
491
+ }
492
+ function nvUpdateOpacity(a) {
493
+ console.log("Opacity = " + a);
494
+ setopacity(a);
495
+ var n = nv.volumes.length;
496
+ for (var i = 0; i < n; i++) {
497
+ nv.volumes[i].opacity = a;
498
+ }
499
+ nv.updateGLVolume();
500
+ }
501
+ function nvToggleLabelVisible() {
502
+ if (textsVisible) {
503
+ nv.hideText = true;
504
+ nv.drawScene();
505
+ setTextsVisible(false);
506
+ }
507
+ else {
508
+ nv.hideText = false;
509
+ nv.drawScene();
510
+ setTextsVisible(true);
511
+ }
512
+ }
513
+ var _29 = useState("pan"), dragMode = _29[0], setDragMode = _29[1];
514
+ function nvSetDragMode(dragMode) {
515
+ switch (dragMode) {
516
+ case "none":
517
+ nv.opts.dragMode = nv.dragModes.none;
518
+ break;
519
+ case "contrast":
520
+ console.log("setting drag mode to contrast");
521
+ nv.opts.dragMode = nv.dragModes.contrast;
522
+ break;
523
+ case "measurement":
524
+ nv.opts.dragMode = nv.dragModes.measurement;
525
+ break;
526
+ case "pan":
527
+ // nv.opts.dragMode = 3;
528
+ nv.opts.dragMode = nv.dragModes.pan;
529
+ break;
530
+ }
531
+ // nv.drawScene();
532
+ setDragMode(dragMode);
533
+ }
534
+ function nvSaveImage() {
535
+ nv.saveImage({
536
+ filename: "roi.nii",
537
+ isSaveDrawing: true
538
+ });
539
+ }
540
+ function nvUpdateDrawingEnabled() {
541
+ setDrawingEnabled(!drawingEnabled);
542
+ nv.setDrawingEnabled(!drawingEnabled);
543
+ nv.drawScene();
544
+ }
545
+ function nvSetDrawingEnabled(enabled) {
546
+ setDrawingEnabled(enabled);
547
+ nv.setDrawingEnabled(enabled);
548
+ nv.drawScene();
549
+ }
550
+ function nvUpdateDrawPen(a) {
551
+ setDrawPen(a.target.value);
552
+ var penValue = a.target.value;
553
+ nv.setPenValue(penValue & 7, penValue > 0);
554
+ if (penValue === 8) {
555
+ nv.setPenValue(0, true);
556
+ }
557
+ }
558
+ function nvUpdateBrushSize(size) {
559
+ setBrushSize(size);
560
+ nv.opts.penBounds = (size - 1) / 2;
561
+ }
562
+ function nvUpdateDrawOpacity(a) {
563
+ setDrawOpacity(a);
564
+ nv.setDrawOpacity(a);
565
+ }
566
+ function nvUpdateCrosshairColor(rgb01, a) {
567
+ if (a === void 0) { a = 1; }
568
+ setCrosshairColor(__spreadArray(__spreadArray([], rgb01, true), [a], false));
569
+ nv.setCrosshairColor(__spreadArray(__spreadArray([], rgb01, true), [a], false));
570
+ }
571
+ function nvUpdateOrientCube() {
572
+ nv.opts.isOrientCube = !orientCube;
573
+ setOrientCube(!orientCube);
574
+ nv.drawScene();
575
+ }
576
+ function nvUpdateHighDPI() {
577
+ nv.setHighResolutionCapable(!highDPI);
578
+ setHighDPI(!highDPI);
579
+ }
580
+ function nvUpdateMultiplanarPadPixels(v) {
581
+ nv.opts.multiplanarPadPixels = v;
582
+ setMultiplanarPadPixels(v);
583
+ nv.drawScene();
584
+ }
585
+ function nvUpdateRuler() {
586
+ nv.opts.isRuler = !ruler;
587
+ setRuler(!ruler);
588
+ nv.drawScene();
589
+ }
590
+ function nvUpdateSagittalNoseLeft() {
591
+ nv.opts.sagittalNoseLeft = !sagittalNoseLeft;
592
+ setSagittalNoseLeft(!sagittalNoseLeft);
593
+ nv.drawScene();
594
+ }
595
+ function nvUpdateRulerWidth(v) {
596
+ nv.opts.rulerWidth = v;
597
+ setRulerWidth(v);
598
+ nv.drawScene();
599
+ }
600
+ function nvUpdateRulerOpacity(a) {
601
+ nv.opts.rulerColor = [rulerColor[0], rulerColor[1], rulerColor[2], a];
602
+ setRulerOpacity(a);
603
+ nv.drawScene();
604
+ }
605
+ function nvUpdateLongTouchTimeout(v) {
606
+ nv.opts.longTouchTimeout = v;
607
+ setLongTouchTimeout(v);
608
+ }
609
+ function nvUpdateDoubleTouchTimeout(v) {
610
+ nv.opts.doubleTouchTimeout = v;
611
+ setDoubleTouchTimeout(v);
612
+ }
613
+ function nvUpdateDragToMeasure() {
614
+ nv.opts.isDragShowsMeasurementTool = !dragToMeasure;
615
+ setDragToMeasure(!dragToMeasure);
616
+ }
617
+ function nvUpdateMaxDrawUndoBitmaps(v) {
618
+ nv.opts.maxDrawUndoBitmaps = v;
619
+ setMaxDrawUndoBitmaps(v);
620
+ }
621
+ function nvUpdateBackColor(rgb01, a) {
622
+ if (a === void 0) { a = 1; }
623
+ setBackColor(__spreadArray(__spreadArray([], rgb01, true), [a], false));
624
+ nv.opts.backColor = __spreadArray(__spreadArray([], rgb01, true), [a], false);
625
+ nv.drawScene();
626
+ }
627
+ function nvUpdateRulerColor(rgb01, a) {
628
+ if (a === void 0) { a = 1; }
629
+ setRulerColor(__spreadArray(__spreadArray([], rgb01, true), [a], false));
630
+ nv.opts.rulerColor = __spreadArray(__spreadArray([], rgb01, true), [a], false);
631
+ if (!ruler) {
632
+ nv.opts.isRuler = !ruler;
633
+ setRuler(!ruler);
634
+ }
635
+ nv.drawScene();
636
+ }
637
+ function nvUpdateClipPlaneColor(rgb01, a) {
638
+ if (a === void 0) { a = 1; }
639
+ setClipPlaneColor(__spreadArray(__spreadArray([], rgb01, true), [a], false));
640
+ nv.opts.clipPlaneColor = __spreadArray(__spreadArray([], rgb01, true), [a], false);
641
+ setClipPlane(true);
642
+ nv.setClipPlane([0, 270, 0]); //left
643
+ nv.updateGLVolume();
644
+ }
645
+ function nvUpdateClipPlane() {
646
+ if (!clipPlane) {
647
+ setClipPlane(true);
648
+ nv.setClipPlane([0, 270, 0]); //left
649
+ }
650
+ else {
651
+ setClipPlane(false);
652
+ nv.setClipPlane([2, 0, 0]); //none
653
+ }
654
+ }
655
+ function nvUpdateColorBar() {
656
+ setColorBar(!colorBar);
657
+ nv.opts.isColorbar = !colorBar;
658
+ nv.drawScene();
659
+ }
660
+ function nvUpdateTextSize(v) {
661
+ setTextSize(v);
662
+ nv.opts.textHeight = v;
663
+ nv.drawScene();
664
+ }
665
+ function updateDecimalPrecision(v) {
666
+ setDecimalPrecision(v);
667
+ }
668
+ function nvUpdateWorldSpace() {
669
+ nvUpdateCrosshair3D();
670
+ setWorldSpace(!worldSpace);
671
+ nv.setSliceMM(!worldSpace);
672
+ // keep sliders synced to the currently displayed crosshair
673
+ try {
674
+ setMMs(nv.frac2mm(nv.scene.crosshairPos));
675
+ }
676
+ catch (_a) { }
677
+ }
678
+ function nvUpdateCornerText() {
679
+ nv.setCornerOrientationText(!cornerText);
680
+ setCornerText(!cornerText);
681
+ }
682
+ function nvUpdateCrosshair3D() {
683
+ nv.opts.show3Dcrosshair = !crosshair3D;
684
+ nv.updateGLVolume();
685
+ setCrosshair3D(!crosshair3D);
686
+ }
687
+ function nvUpdateCrosshair() {
688
+ nv.opts.crosshairWidth = showCrosshair ? 0 : 1;
689
+ nv.drawScene();
690
+ setShowCrosshair(!showCrosshair);
691
+ }
692
+ function nvUpdateRadiological() {
693
+ nv.setRadiologicalConvention(!radiological);
694
+ setRadiological(!radiological);
695
+ }
696
+ function nvUpdateCrosshairOpacity(a) {
697
+ nv.setCrosshairColor([
698
+ crosshairColor[0],
699
+ crosshairColor[1],
700
+ crosshairColor[2],
701
+ a,
702
+ ]);
703
+ setCrosshairOpacity(a);
704
+ }
705
+ function nvUpdateClipPlaneOpacity(a) {
706
+ nv.opts.clipPlaneColor = [
707
+ clipPlaneColor[0],
708
+ clipPlaneColor[1],
709
+ clipPlaneColor[2],
710
+ a,
711
+ ];
712
+ setClipPlaneOpacity(a);
713
+ nv.updateGLVolume();
714
+ }
715
+ function nvUpdateCrosshairSize(w) {
716
+ nv.opts.crosshairWidth = w;
717
+ nv.drawScene();
718
+ }
719
+ // Re-apply a saved crosshair position (in mm) after any operation that resets Niivue state.
720
+ function applySavedCrosshairIfAny() {
721
+ try {
722
+ if (!lastMMRef.current)
723
+ return;
724
+ // Ensure engine uses the currently selected coordinate system
725
+ nv.setSliceMM(worldSpace);
726
+ var frac = nv.mm2frac(lastMMRef.current);
727
+ if (Array.isArray(frac) && frac.length === 3) {
728
+ nv.scene.crosshairPos = frac;
729
+ nv.drawScene();
730
+ setMMs(nv.frac2mm(frac)); // returns a new array; guarantees a state change
731
+ }
732
+ }
733
+ catch (e) {
734
+ // Intentionally ignore; if conversion fails we simply skip re-applying.
735
+ }
736
+ }
737
+ var _30 = useState({}), labelMapping = _30[0], setLabelMapping = _30[1];
738
+ function resampleImage(mapping) {
739
+ if (mapping === void 0) { mapping = labelMapping; }
740
+ var image = nv.volumes[0];
741
+ var rois = [];
742
+ var layout = {
743
+ barmode: "overlay",
744
+ title: { text: "ROI Histogram" },
745
+ // height: 100,
746
+ margin: {
747
+ l: 50,
748
+ r: 50,
749
+ b: 50,
750
+ t: 60,
751
+ pad: 4
752
+ },
753
+ xaxis: {
754
+ autoscale: true,
755
+ title: { text: "Voxel value" },
756
+ showgrid: true
757
+ },
758
+ yaxis: {
759
+ autoscale: true,
760
+ title: { text: "Bin frequency" },
761
+ showgrid: true
762
+ },
763
+ responsive: true
764
+ }; // Set the height of the plot here};
765
+ // Bitmap depicts the drawn content
766
+ if (nv.drawBitmap === null) {
767
+ Plotly.newPlot("histoplot", [], layout, { responsive: true });
768
+ setROIs([]);
769
+ return;
770
+ } //If ROI (drawing) is not inside the stack
771
+ var min = image.robust_min;
772
+ var max = image.robust_max;
773
+ var samples = {
774
+ 1: [],
775
+ 2: [],
776
+ 3: [],
777
+ 4: [],
778
+ 5: [],
779
+ 6: [],
780
+ 7: []
781
+ };
782
+ for (var i = 0; i < nv.drawBitmap.length; i++) {
783
+ //val&7-1 converts to r,g,b index through bit operations
784
+ if (samples[nv.drawBitmap[i]] === undefined) {
785
+ samples[nv.drawBitmap[i]] = [];
786
+ }
787
+ samples[nv.drawBitmap[i]].push(image.img[i]);
788
+ }
789
+ if (nv.hiddenBitmap !== undefined) {
790
+ for (var i = 0; i < nv.hiddenBitmap.length; i++) {
791
+ //val&7-1 converts to r,g,b index through bit operations
792
+ if (samples[nv.hiddenBitmap[i]] === undefined) {
793
+ samples[nv.hiddenBitmap[i]] = [];
794
+ }
795
+ samples[nv.hiddenBitmap[i]].push(image.img[i]);
796
+ }
797
+ }
798
+ var colors = [
799
+ "#bbb",
800
+ "#f00",
801
+ "#0f0",
802
+ "#00f",
803
+ "yellow",
804
+ "cyan",
805
+ "#e81ce8",
806
+ "#e8dbc7",
807
+ ];
808
+ Object.keys(samples).forEach(function (_key) {
809
+ var key = Number(_key);
810
+ var sample = samples[key];
811
+ if (sample.length > 0 && key > 0) {
812
+ console.log(key);
813
+ rois.push({
814
+ label: key.toString(),
815
+ alias: mapping[key] ? mapping[key] : key.toString(),
816
+ visibility: nv.getLabelVisibility(Number(key)),
817
+ color: colors[key],
818
+ mu: calculateMean(sample),
819
+ std: calculateStandardDeviation(sample),
820
+ opacity: nv.drawOpacity,
821
+ count: sample.length,
822
+ sample: sample
823
+ });
824
+ }
825
+ });
826
+ setROIs(rois);
827
+ // plot a histogram of numbers
828
+ var traces = [];
829
+ for (var _i = 0, rois_1 = rois; _i < rois_1.length; _i++) {
830
+ var roi = rois_1[_i];
831
+ // if(roi.visibility){
832
+ traces.push({
833
+ x: roi.sample,
834
+ type: "histogram",
835
+ name: roi.alias,
836
+ opacity: roi.visibility ? 0.5 : 0.1,
837
+ marker: {
838
+ color: roi.color
839
+ },
840
+ autobinx: false,
841
+ xbins: {
842
+ end: max,
843
+ size: (max - min) / 100,
844
+ start: min
845
+ }
846
+ });
847
+ // }
848
+ }
849
+ Plotly.newPlot("histoplot", traces, layout, { responsive: true });
850
+ }
851
+ function nvUpdateSelectionBoxColor(rgb01) {
852
+ setSelectionBoxColor(__spreadArray(__spreadArray([], rgb01, true), [0.5], false));
853
+ nv.setSelectionBoxColor(__spreadArray(__spreadArray([], rgb01, true), [0.5], false));
854
+ }
855
+ var _31 = React.useState("axial"), sliceType = _31[0], setSliceType = _31[1];
856
+ function nvUpdateSliceType(newSliceType) {
857
+ setSliceType(newSliceType);
858
+ if (newSliceType === "axial") {
859
+ nv.setSliceType(nv.sliceTypeAxial);
860
+ }
861
+ else if (newSliceType === "coronal") {
862
+ nv.setSliceType(nv.sliceTypeCoronal);
863
+ }
864
+ else if (newSliceType === "sagittal") {
865
+ nv.setSliceType(nv.sliceTypeSagittal);
866
+ }
867
+ else if (newSliceType === "multi") {
868
+ nv.setSliceType(nv.sliceTypeMultiplanar);
869
+ }
870
+ else if (newSliceType === "3d") {
871
+ nv.setSliceType(nv.sliceTypeRender);
872
+ }
873
+ nvSetDragMode(dragMode); // some Niivue builds reset interaction on slice change
874
+ // Re-apply world/voxel mode and last crosshair after slice type changes
875
+ nv.setSliceMM(worldSpace);
876
+ applySavedCrosshairIfAny();
877
+ }
878
+ function nvUpdateLayerOpacity(a) {
879
+ nv.updateGLVolume();
880
+ }
881
+ function nvUpdateColorMap(id, clr) {
882
+ nv.setColorMap(id, clr);
883
+ var volume = nv.volumes[0];
884
+ setMin(volume.cal_min);
885
+ setMax(volume.cal_max);
886
+ }
887
+ function nvRemoveLayer(imageToRemove) {
888
+ nv.removeVolume(imageToRemove);
889
+ setLayers(__spreadArray([], nv.volumes, true));
890
+ }
891
+ function stylingProxy(nii) {
892
+ if (nii.dim === 2) {
893
+ nvUpdateSliceType("axial");
894
+ setShowCrosshair(false);
895
+ setTextsVisible(false);
896
+ nv.opts.crosshairWidth = 0;
897
+ nv.hideText = true;
898
+ setTimeout(function () {
899
+ nv.setCenteredZoom(0.7);
900
+ }, 300);
901
+ }
902
+ else {
903
+ // nvUpdateSliceType('multi');
904
+ nvUpdateSliceType(sliceType);
905
+ setShowCrosshair(true);
906
+ setTextsVisible(false);
907
+ nv.opts.crosshairWidth = 1;
908
+ nv.hideText = true;
909
+ }
910
+ }
911
+ var dispatch = useAppDispatch();
912
+ var pipeline = useAppSelector(function (state) { var _a; return (_a = state.result.activeJob) === null || _a === void 0 ? void 0 : _a.pipeline_id; });
913
+ var selectVolume = function (volumeIndex) { return __awaiter(_this, void 0, void 0, function () {
914
+ var openVolume;
915
+ var _this = this;
916
+ return __generator(this, function (_a) {
917
+ openVolume = function () { return __awaiter(_this, void 0, void 0, function () {
918
+ var e_2;
919
+ return __generator(this, function (_a) {
920
+ switch (_a.label) {
921
+ case 0:
922
+ nv.closeDrawing();
923
+ setDrawingChanged(false);
924
+ if (drawingEnabled)
925
+ nvUpdateDrawingEnabled();
926
+ if (props.niis[selectedVolume] !== undefined) {
927
+ nv.removeVolume(niiToVolume(props.niis[selectedVolume]));
928
+ }
929
+ _a.label = 1;
930
+ case 1:
931
+ _a.trys.push([1, 3, , 4]);
932
+ // loadVolumes calls onImageLoaded which does all setup
933
+ return [4 /*yield*/, nv.loadVolumes([niiToVolume(props.niis[volumeIndex])])];
934
+ case 2:
935
+ // loadVolumes calls onImageLoaded which does all setup
936
+ _a.sent();
937
+ // Force a multiplanar view switch to trigger proper rendering, then switch back
938
+ // RJW TODO: fix this horrible hack
939
+ setTimeout(function () {
940
+ nv.setSliceType(nv.sliceTypeMultiplanar);
941
+ nv.resizeListener();
942
+ nv.drawScene();
943
+ // Then switch to the desired slice type
944
+ setTimeout(function () {
945
+ nvUpdateSliceType(sliceType);
946
+ nv.resizeListener();
947
+ nv.drawScene();
948
+ }, 50);
949
+ }, 100);
950
+ return [3 /*break*/, 4];
951
+ case 3:
952
+ e_2 = _a.sent();
953
+ setWarning("Error loading results, please check internet connectivity");
954
+ setWarningOpen(true);
955
+ setTimeout(function () {
956
+ setWarningOpen(false);
957
+ setWarning("");
958
+ }, 2500);
959
+ return [2 /*return*/];
960
+ case 4:
961
+ setSelectedVolume(volumeIndex);
962
+ setSelectedDrawingLayer(null);
963
+ return [2 /*return*/];
964
+ }
965
+ });
966
+ }); };
967
+ // In case that changes has been made
968
+ if (drawingChanged) {
969
+ setWarningConfirmationCallback(function () { return function () {
970
+ saveDrawingLayer(function () { return __awaiter(_this, void 0, void 0, function () {
971
+ return __generator(this, function (_a) {
972
+ switch (_a.label) {
973
+ case 0:
974
+ if (!pipeline) return [3 /*break*/, 2];
975
+ return [4 /*yield*/, dispatch(getPipelineROI({ pipeline: pipeline }))];
976
+ case 1:
977
+ _a.sent();
978
+ _a.label = 2;
979
+ case 2:
980
+ setSaving(false);
981
+ openVolume();
982
+ return [2 /*return*/];
983
+ }
984
+ });
985
+ }); }, function () {
986
+ setSaving(true);
987
+ });
988
+ }; });
989
+ setWarningCancelCallback(function () { return function () {
990
+ openVolume();
991
+ }; });
992
+ setConfirmationOpen(true);
993
+ }
994
+ else
995
+ openVolume();
996
+ return [2 /*return*/];
997
+ });
998
+ }); };
999
+ var _32 = useState(null), selectedROI = _32[0], setSelectedDrawingLayer = _32[1];
1000
+ var _33 = useState(false), saveDialogOpen = _33[0], setSaveDialogOpen = _33[1];
1001
+ var _34 = useState(function (text) { }), saveConfirmCallback = _34[0], setSaveConfirmCallback = _34[1];
1002
+ var _35 = useState(false), confirmationOpen = _35[0], setConfirmationOpen = _35[1];
1003
+ var _36 = useState(function () { }), warningConfirmationCallback = _36[0], setWarningConfirmationCallback = _36[1];
1004
+ var _37 = useState(function () { }), warningCancelCallback = _37[0], setWarningCancelCallback = _37[1];
1005
+ var _38 = useState(false), drawingChanged = _38[0], setDrawingChanged = _38[1];
1006
+ var setLabelAlias = function (label, alias) {
1007
+ labelMapping[label] = alias;
1008
+ setLabelMapping(labelMapping);
1009
+ resampleImage(labelMapping);
1010
+ };
1011
+ var zipAndSendDrawingLayer = function (uploadURL, filename, blob) {
1012
+ return __awaiter(this, void 0, void 0, function () {
1013
+ var zip, descriptor, content, file;
1014
+ return __generator(this, function (_a) {
1015
+ switch (_a.label) {
1016
+ case 0:
1017
+ zip = new JSZip();
1018
+ descriptor = {
1019
+ data: [
1020
+ {
1021
+ filename: "".concat(filename, ".nii"),
1022
+ id: 1,
1023
+ name: filename,
1024
+ type: "image",
1025
+ // "numpyPixelType": "complex64",
1026
+ // "pixelType": "complex"
1027
+ labelMapping: labelMapping
1028
+ },
1029
+ ]
1030
+ };
1031
+ zip.file("info.json", JSON.stringify(descriptor));
1032
+ zip.file("".concat(filename, ".nii"), blob, { base64: true });
1033
+ return [4 /*yield*/, zip.generateAsync({ type: "blob" })];
1034
+ case 1:
1035
+ content = _a.sent();
1036
+ file = new File([content], filename, {
1037
+ type: content.type,
1038
+ lastModified: Date.now()
1039
+ });
1040
+ // Upload to bucket
1041
+ return [4 /*yield*/, axios.put(uploadURL, file, {
1042
+ headers: {
1043
+ "Content-Type": "application/octet-stream"
1044
+ }
1045
+ })];
1046
+ case 2:
1047
+ // Upload to bucket
1048
+ _a.sent();
1049
+ return [2 /*return*/];
1050
+ }
1051
+ });
1052
+ });
1053
+ };
1054
+ var unzipAndRenderDrawingLayer = function (accessURL) { return __awaiter(_this, void 0, void 0, function () {
1055
+ var response, blob, zip, fileInfo, content, info_1, niiFilePath, niiDrawing, base64;
1056
+ return __generator(this, function (_a) {
1057
+ switch (_a.label) {
1058
+ case 0: return [4 /*yield*/, fetch(accessURL)];
1059
+ case 1:
1060
+ response = _a.sent();
1061
+ // Check if the request was successful
1062
+ if (!response.ok) {
1063
+ props.warn("Failed to load the requested ROI Layer");
1064
+ return [2 /*return*/];
1065
+ }
1066
+ return [4 /*yield*/, response.blob()];
1067
+ case 2:
1068
+ blob = _a.sent();
1069
+ zip = new JSZip();
1070
+ return [4 /*yield*/, zip.loadAsync(blob)];
1071
+ case 3:
1072
+ _a.sent();
1073
+ fileInfo = zip.file("info.json");
1074
+ if (!fileInfo) return [3 /*break*/, 8];
1075
+ return [4 /*yield*/, fileInfo.async("string")];
1076
+ case 4:
1077
+ content = _a.sent();
1078
+ info_1 = JSON.parse(content);
1079
+ niiFilePath = info_1.data[0].filename;
1080
+ niiDrawing = zip.file(niiFilePath);
1081
+ if (!niiDrawing) return [3 /*break*/, 6];
1082
+ return [4 /*yield*/, niiDrawing.async("base64")];
1083
+ case 5:
1084
+ base64 = _a.sent();
1085
+ console.log(niiFilePath);
1086
+ nv.loadDrawingFromBase64(niiFilePath, base64).then(function () {
1087
+ setLabelMapping(info_1.data[0].labelMapping);
1088
+ resampleImage(info_1.data[0].labelMapping);
1089
+ });
1090
+ return [3 /*break*/, 7];
1091
+ case 6:
1092
+ console.log("".concat(niiFilePath, " not found in the ZIP file."));
1093
+ props.warn("".concat(niiFilePath, " not found in the ZIP file."));
1094
+ return [2 /*return*/, null];
1095
+ case 7: return [3 /*break*/, 9];
1096
+ case 8:
1097
+ console.log("info.json not found in the ZIP file.");
1098
+ props.warn("info.json not found in the ZIP file.");
1099
+ return [2 /*return*/, null];
1100
+ case 9: return [2 /*return*/];
1101
+ }
1102
+ });
1103
+ }); };
1104
+ // This is a small fix that prevents the selected roi index from jumping to
1105
+ // the newest saved roi after user has performed a roi reselection during
1106
+ // roi saving
1107
+ var _39 = useState(false), selectedDuringSaving = _39[0], setSelectedDuringSaving = _39[1];
1108
+ var selectDrawingLayer = function (roiIndex) { return __awaiter(_this, void 0, void 0, function () {
1109
+ return __generator(this, function (_a) {
1110
+ switch (_a.label) {
1111
+ case 0:
1112
+ // console.log(nv.drawBitmap);
1113
+ console.log(props.rois[roiIndex].link);
1114
+ return [4 /*yield*/, unzipAndRenderDrawingLayer(props.rois[roiIndex].link)];
1115
+ case 1:
1116
+ _a.sent();
1117
+ setSelectedDrawingLayer(roiIndex);
1118
+ setSelectedDuringSaving(true);
1119
+ setDrawingChanged(false);
1120
+ return [2 /*return*/];
1121
+ }
1122
+ });
1123
+ }); };
1124
+ var unpackROI = function (accessURL) { return __awaiter(_this, void 0, void 0, function () {
1125
+ return __generator(this, function (_a) {
1126
+ switch (_a.label) {
1127
+ case 0: return [4 /*yield*/, unzipAndRenderDrawingLayer(accessURL)];
1128
+ case 1:
1129
+ _a.sent();
1130
+ setDrawingChanged(false);
1131
+ setSelectedDrawingLayer(props.rois.length);
1132
+ return [2 /*return*/];
1133
+ }
1134
+ });
1135
+ }); };
1136
+ var refreshROI = function () { return __awaiter(_this, void 0, void 0, function () {
1137
+ var roiIndex, load;
1138
+ return __generator(this, function (_a) {
1139
+ roiIndex = selectedROI;
1140
+ console.log(nv.drawBitmap);
1141
+ if (roiIndex !== null) {
1142
+ load = function (idx) {
1143
+ console.log(props.rois[idx].link);
1144
+ console.trace();
1145
+ nv.loadDrawingFromUrl(props.rois[idx].link).then(function (value) {
1146
+ resampleImage();
1147
+ });
1148
+ setSelectedDrawingLayer(roiIndex);
1149
+ setDrawingChanged(false);
1150
+ };
1151
+ load(roiIndex);
1152
+ }
1153
+ return [2 /*return*/];
1154
+ });
1155
+ }); };
1156
+ var saveDrawingLayer = function (afterSaveCallback, preSaveCallback) {
1157
+ if (preSaveCallback === void 0) { preSaveCallback = function () { }; }
1158
+ var endpoints = getEndpoints();
1159
+ setSaveDialogOpen(true);
1160
+ setSaveConfirmCallback(function () { return function (filename) { return __awaiter(_this, void 0, void 0, function () {
1161
+ var config, response, originalCreateObjectURL, successful;
1162
+ return __generator(this, function (_a) {
1163
+ switch (_a.label) {
1164
+ case 0:
1165
+ preSaveCallback();
1166
+ config = {};
1167
+ return [4 /*yield*/, AuthenticatedHttpClient.post(endpoints.ROI_UPLOAD, {
1168
+ filename: "".concat(filename),
1169
+ pipeline_id: props.pipelineID,
1170
+ type: "image",
1171
+ contentType: "application/octet-stream"
1172
+ }, config)];
1173
+ case 1:
1174
+ response = _a.sent();
1175
+ originalCreateObjectURL = URL.createObjectURL;
1176
+ // Redefine the method
1177
+ URL.createObjectURL = function (blob) {
1178
+ var _this = this;
1179
+ console.log("saving blob");
1180
+ console.log(blob);
1181
+ setSelectedDuringSaving(false);
1182
+ zipAndSendDrawingLayer(response.data.upload_url, filename, blob).then(function () { return __awaiter(_this, void 0, void 0, function () {
1183
+ return __generator(this, function (_a) {
1184
+ switch (_a.label) {
1185
+ case 0:
1186
+ // Update available rois with this callback
1187
+ props.saveROICallback();
1188
+ setDrawingChanged(false);
1189
+ if (!(afterSaveCallback instanceof Function)) return [3 /*break*/, 2];
1190
+ return [4 /*yield*/, afterSaveCallback()];
1191
+ case 1:
1192
+ _a.sent();
1193
+ _a.label = 2;
1194
+ case 2:
1195
+ if (!selectedDuringSaving)
1196
+ //Only switch to the newest roi when user hasn't performed reselection
1197
+ // during the period
1198
+ setSelectedDrawingLayer(props.rois.length);
1199
+ return [2 /*return*/];
1200
+ }
1201
+ });
1202
+ }); });
1203
+ // Call the original method and return its result
1204
+ return "javascript:void(0);";
1205
+ };
1206
+ successful = nv.saveImage({
1207
+ filename: filename,
1208
+ isSaveDrawing: true
1209
+ });
1210
+ // De-patch
1211
+ URL.createObjectURL = originalCreateObjectURL;
1212
+ return [2 /*return*/];
1213
+ }
1214
+ });
1215
+ }); }; });
1216
+ };
1217
+ var drawToolkitProps = {
1218
+ nv: nv,
1219
+ volumes: props.niis.map(niiToVolume),
1220
+ selectedVolume: selectedVolume,
1221
+ setSelectedVolume: selectVolume,
1222
+ updateDrawPen: nvUpdateDrawPen,
1223
+ drawPen: drawPen,
1224
+ drawingEnabled: drawingEnabled,
1225
+ setDrawingEnabled: nvSetDrawingEnabled,
1226
+ showColorBar: colorBar,
1227
+ toggleColorBar: nvUpdateColorBar,
1228
+ changesMade: drawingChanged,
1229
+ // toggleSampleDistribution,
1230
+ drawUndo: function () {
1231
+ //To be moved and organized
1232
+ nv.drawUndo();
1233
+ resampleImage();
1234
+ },
1235
+ brushSize: brushSize,
1236
+ updateBrushSize: nvUpdateBrushSize,
1237
+ resampleImage: resampleImage,
1238
+ roiVisible: roiVisible,
1239
+ toggleROIVisible: toggleROIVisible,
1240
+ drawingOpacity: drawingOpacity,
1241
+ setDrawingOpacity: nvUpdateDrawingOpacity,
1242
+ setDrawingChanged: setDrawingChanged
1243
+ };
1244
+ return (_jsxs(Box, __assign({ sx: {
1245
+ display: "flex",
1246
+ flexDirection: "column",
1247
+ height: "100%",
1248
+ width: "100%",
1249
+ alignItems: "center",
1250
+ justifyContent: "center"
1251
+ } }, { children: [_jsxs(SettingsPanel, __assign({ open: openSettings, width: 300, toggleMenu: toggleSettings }, { children: [_jsx(ColorPicker, { colorRGB01: backColor, onSetColor: nvUpdateBackColor, title: "Background color" }), _jsx(ColorPicker, { colorRGB01: clipPlaneColor, onSetColor: nvUpdateClipPlaneColor, title: "Clip plane color" }), _jsx(NumberPicker, { value: clipPlaneOpacity, onChange: nvUpdateClipPlaneOpacity, title: "Clip plane opacity", min: 0, max: 1, step: 0.1 }), _jsx(ColorPicker, { colorRGB01: crosshairColor, onSetColor: nvUpdateCrosshairColor, title: "Crosshair color" }), _jsx(NumberPicker, { value: crosshairOpacity, onChange: nvUpdateCrosshairOpacity, title: "Crosshair opacity", min: 0, max: 1, step: 0.1 }), _jsx(ColorPicker, { colorRGB01: selectionBoxColor, onSetColor: nvUpdateSelectionBoxColor, title: "Selection box color" }), _jsx(NumberPicker, { value: nv.opts.crosshairWidth, onChange: nvUpdateCrosshairSize, title: "Crosshair size", min: 0, max: 10, step: 1 }), _jsx(NumberPicker, { value: textSize, onChange: nvUpdateTextSize, title: "Text size", min: 0, max: 0.2, step: 0.01 }), _jsx(ColorPicker, { colorRGB01: rulerColor, onSetColor: nvUpdateRulerColor, title: "Ruler color" }), _jsx(NumberPicker, { value: rulerWidth, onChange: nvUpdateRulerWidth, title: "Ruler thickness", min: 0, max: 10, step: 1 }), _jsx(NumberPicker, { value: rulerOpacity, onChange: nvUpdateRulerOpacity, title: "Ruler opacity", min: 0, max: 1, step: 0.1 }), _jsx(NumberPicker, { value: opacity, onChange: nvUpdateOpacity, title: "Opacity", min: 0, max: 1, step: 0.01 }), _jsx(NumberPicker, { value: drawOpacity, onChange: nvUpdateDrawOpacity, title: "Draw Opacity", min: 0, max: 1, step: 0.01 }), _jsx("label", __assign({ htmlFor: "drawPen" }, { children: "Draw color:" })), _jsxs("select", __assign({ name: "drawPen", id: "drawPen", onChange: nvUpdateDrawPen, defaultValue: drawPen }, { children: [_jsx("option", __assign({ value: "0" }, { children: "Erase" })), _jsx("option", __assign({ value: "1" }, { children: "Red" })), _jsx("option", __assign({ value: "2" }, { children: "Green" })), _jsx("option", __assign({ value: "3" }, { children: "Blue" })), _jsx("option", __assign({ value: "8" }, { children: "Filled Erase" })), _jsx("option", __assign({ value: "9" }, { children: "Filled Red" })), _jsx("option", __assign({ value: "10" }, { children: "Filled Green" })), _jsx("option", __assign({ value: "11" }, { children: "Filled Blue" })), _jsx("option", __assign({ value: "12" }, { children: "Erase Selected Cluster" }))] })), _jsx(Button, __assign({ title: "Save image", onClick: nvSaveImage }, { children: "Save image" })), _jsx(NVSwitch, { checked: locationTableVisible, title: "Location table", onChange: toggleLocationTable }), _jsx(NVSwitch, { checked: drawingEnabled, title: "Enable drawing", onChange: nvUpdateDrawingEnabled }), _jsx(NVSwitch, { checked: orientCube, title: "Orientation cube", onChange: nvUpdateOrientCube }), _jsx(NVSwitch, { checked: ruler, title: "Ruler", onChange: nvUpdateRuler }), _jsx(NVSwitch, { checked: clipPlane, title: "Clip plane", onChange: nvUpdateClipPlane }), _jsx(NVSwitch, { checked: cornerText, title: "Corner text", onChange: nvUpdateCornerText }), _jsx(NVSwitch, { checked: radiological, title: "radiological", onChange: nvUpdateRadiological }), _jsx(NVSwitch, { checked: crosshair3D, title: "3D crosshair", onChange: nvUpdateCrosshair3D }), _jsx(NVSwitch, { checked: colorBar, title: "Show color bar", onChange: nvUpdateColorBar }), _jsx(NVSwitch, { checked: worldSpace, title: "World space", onChange: nvUpdateWorldSpace }), _jsx(NVSwitch, { checked: sagittalNoseLeft, title: "Nose left", onChange: nvUpdateSagittalNoseLeft }), _jsx(NVSwitch, { checked: dragToMeasure, title: "Drag to measure", onChange: nvUpdateDragToMeasure }), _jsx(NVSwitch, { checked: highDPI, title: "High DPI", onChange: nvUpdateHighDPI }), _jsx(NumberPicker, { value: decimalPrecision, onChange: updateDecimalPrecision, title: "Decimal precision", min: 0, max: 8, step: 1 }), _jsx(NumberPicker, { value: multiplanarPadPixels, onChange: nvUpdateMultiplanarPadPixels, title: "Multiplanar padding", min: 0, max: 20, step: 2 }), _jsx(NumberPicker, { value: maxDrawUndoBitmaps, onChange: nvUpdateMaxDrawUndoBitmaps, title: "Max Draw Undos", min: 8, max: 28, step: 1 }), _jsx(NumberPicker, { value: longTouchTimeout, onChange: nvUpdateLongTouchTimeout, title: "Long touch timeout msec", min: 1000, max: 5000, step: 100 }), _jsx(NumberPicker, { value: doubleTouchTimeout, onChange: nvUpdateDoubleTouchTimeout, title: "Double touch timeout msec", min: 500, max: 999, step: 25 })] })), _jsx(LayersPanel, __assign({ open: openLayers, width: 320, onToggleMenu: toggleLayers, onAddLayer: addLayer }, { children: layerList })), _jsx(Toolbar, { nv: nv, nvUpdateSliceType: nvUpdateSliceType, sliceType: sliceType, toggleSettings: toggleSettings, toggleLayers: toggleLayers, volumes: props.niis.map(niiToVolume), selectedVolume: selectedVolume, setSelectedVolume: selectVolume, showColorBar: colorBar, toggleColorBar: nvUpdateColorBar, rois: props.rois, selectedROI: selectedROI, refreshROI: refreshROI, setSelectedROI: selectDrawingLayer, toggleShowCrosshair: nvUpdateCrosshair, showCrosshair: showCrosshair, dragMode: dragMode, setDragMode: nvSetDragMode, toggleRadiological: nvUpdateRadiological, radiological: radiological, saveROI: saveDrawingLayer, complexMode: complexMode, setComplexMode: nvSetDisplayedVoxels, complexOptions: complexOptions, labelsVisible: textsVisible, toggleLabelsVisible: nvToggleLabelVisible, saving: saving, setSaving: setSaving }), _jsx(Confirmation, { name: "New Changes Made", message: "Consider saving your drawing before switching.", open: confirmationOpen, setOpen: setConfirmationOpen, cancellable: true, confirmCallback: warningConfirmationCallback, cancelCallback: warningCancelCallback, cancelText: "Don't save" }), _jsx(CmrEditConfirmation, { name: "Save drawings", message: "Please enter the name of the saved drawing", open: saveDialogOpen, setOpen: setSaveDialogOpen, confirmCallback: saveConfirmCallback, cancellable: true, cancelCallback: function () { },
1252
+ // suffix={'.zip'}
1253
+ defaultText: selectedROI
1254
+ ? props.rois[selectedROI] !== undefined
1255
+ ? props.rois[selectedROI].filename
1256
+ : undefined
1257
+ : undefined }), props.niis[selectedVolume] !== undefined && (_jsx(NiivuePanel, { nv: nv,
1258
+ // key={`${selectedVolume}`}
1259
+ transformFactors: transformFactors, decimalPrecision: decimalPrecision, locationData: locationData, locationTableVisible: locationTableVisible, pipelineID: props.pipelineID || "", resampleImage: resampleImage, rois: rois, drawToolkitProps: drawToolkitProps, layerList: layerList, mins: boundMins, maxs: boundMaxs, mms: mms, min: min, max: max, setMin: setMin, setMax: setMax, rangeKey: rangeKey, unzipAndRenderROI: unpackROI, zipAndSendROI: zipAndSendDrawingLayer, setLabelAlias: setLabelAlias, gamma: gamma, gammaKey: gammaKey, setGamma: setGamma }))] })));
1260
+ }
1261
+ function niiToVolume(nii) {
1262
+ return {
1263
+ //URL is for NiiVue blob loading
1264
+ url: nii.link,
1265
+ //name is for NiiVue name replacer (needs proper extension like .nii)
1266
+ name: nii.filename.split("/").pop() || nii.filename,
1267
+ //alias is for user selection in toolbar
1268
+ alias: nii.name
1269
+ };
1270
+ }