cloudmr-ux 4.3.2 → 4.3.4
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/dist/CmrComponents/draw-toolkit/DrawPlatte.d.ts +10 -0
- package/dist/CmrComponents/draw-toolkit/DrawPlatte.js +62 -0
- package/dist/CmrComponents/draw-toolkit/DrawToolkit.d.ts +32 -0
- package/dist/CmrComponents/draw-toolkit/DrawToolkit.js +136 -0
- package/dist/CmrComponents/draw-toolkit/EraserPlatte.d.ts +10 -0
- package/dist/CmrComponents/draw-toolkit/EraserPlatte.js +42 -0
- package/dist/CmrComponents/draw-toolkit/MaskPlatte.d.ts +10 -0
- package/dist/CmrComponents/draw-toolkit/MaskPlatte.js +92 -0
- package/dist/CmrComponents/niivue-roi-histogram/NiivueRoiHistogram.d.ts +11 -0
- package/dist/CmrComponents/niivue-roi-histogram/NiivueRoiHistogram.js +9 -0
- package/dist/CmrComponents/niivue-roi-histogram/resampleNiivueRoiHistogram.d.ts +29 -0
- package/dist/CmrComponents/niivue-roi-histogram/resampleNiivueRoiHistogram.js +134 -0
- package/dist/CmrComponents/niivue-roi-histogram/roiHistogramStats.d.ts +2 -0
- package/dist/CmrComponents/niivue-roi-histogram/roiHistogramStats.js +13 -0
- package/dist/CmrComponents/niivue-roi-histogram/useNiivueRoiHistogram.d.ts +14 -0
- package/dist/CmrComponents/niivue-roi-histogram/useNiivueRoiHistogram.js +31 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface DrawPlatteProps {
|
|
3
|
+
expandDrawOptions: boolean;
|
|
4
|
+
updateDrawPen: (e: any) => void;
|
|
5
|
+
setDrawingEnabled: (enabled: boolean) => void;
|
|
6
|
+
brushSize: number;
|
|
7
|
+
updateBrushSize: (size: number) => void;
|
|
8
|
+
}
|
|
9
|
+
declare const DrawPlatte: React.FC<DrawPlatteProps>;
|
|
10
|
+
export default DrawPlatte;
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { Stack, IconButton, Slider, Typography } from "@mui/material";
|
|
14
|
+
import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord";
|
|
15
|
+
var DrawPlatte = function (_a) {
|
|
16
|
+
var expandDrawOptions = _a.expandDrawOptions, updateDrawPen = _a.updateDrawPen, setDrawingEnabled = _a.setDrawingEnabled, brushSize = _a.brushSize, updateBrushSize = _a.updateBrushSize;
|
|
17
|
+
var filledOptions = [
|
|
18
|
+
_jsx(FiberManualRecordIcon, { sx: { color: "red" } }, "f0"),
|
|
19
|
+
_jsx(FiberManualRecordIcon, { sx: { color: "green" } }, "f1"),
|
|
20
|
+
_jsx(FiberManualRecordIcon, { sx: { color: "blue" } }, "f2"),
|
|
21
|
+
_jsx(FiberManualRecordIcon, { sx: { color: "yellow" } }, "f3"),
|
|
22
|
+
_jsx(FiberManualRecordIcon, { sx: { color: "cyan" } }, "f4"),
|
|
23
|
+
_jsx(FiberManualRecordIcon, { sx: { color: "#e81ce8" } }, "f5"),
|
|
24
|
+
];
|
|
25
|
+
return (_jsxs(Stack, __assign({ style: {
|
|
26
|
+
position: "absolute",
|
|
27
|
+
top: "100%",
|
|
28
|
+
left: 0,
|
|
29
|
+
zIndex: 10,
|
|
30
|
+
border: "".concat(expandDrawOptions ? "1px" : 0, " solid #bbb"),
|
|
31
|
+
maxWidth: expandDrawOptions ? 300 : 0,
|
|
32
|
+
overflow: "hidden",
|
|
33
|
+
borderRadius: "16px",
|
|
34
|
+
borderTopLeftRadius: "6pt",
|
|
35
|
+
borderTopRightRadius: "6pt",
|
|
36
|
+
background: "#333"
|
|
37
|
+
}, direction: "column" }, { children: [_jsxs(Stack, __assign({ sx: { mb: 1 }, alignItems: "center" }, { children: [_jsx(Typography, __assign({ color: "white", noWrap: true, gutterBottom: true, width: "100%", marginLeft: "10pt", fontSize: "11pt", alignItems: "start" }, { children: "Brush Size: ".concat(brushSize) })), _jsx(Slider, { value: brushSize, sx: {
|
|
38
|
+
width: "80%",
|
|
39
|
+
color: "#fff",
|
|
40
|
+
"& .MuiSlider-track": { backgroundColor: "#fff", border: "none" },
|
|
41
|
+
"& .MuiSlider-rail": { backgroundColor: "rgba(255,255,255,0.3)" },
|
|
42
|
+
"& .MuiSlider-thumb": {
|
|
43
|
+
backgroundColor: "#fff",
|
|
44
|
+
border: "2px solid #fff",
|
|
45
|
+
"&:hover, &.Mui-focusVisible, &.Mui-active": {
|
|
46
|
+
boxShadow: "0 0 0 8px rgba(255,255,255,0.16)"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"& .MuiSlider-mark": { backgroundColor: "#fff" },
|
|
50
|
+
"& .MuiSlider-markActive": { backgroundColor: "#fff" },
|
|
51
|
+
"& .MuiSlider-valueLabel": {
|
|
52
|
+
backgroundColor: "#fff",
|
|
53
|
+
color: "#000"
|
|
54
|
+
}
|
|
55
|
+
}, step: 2, min: 1, max: 15, marks: true, onChange: function (_event, value) {
|
|
56
|
+
updateBrushSize(value);
|
|
57
|
+
} })] })), _jsx(Stack, __assign({ direction: "row" }, { children: filledOptions.map(function (value, index) { return (_jsx(IconButton, __assign({ onClick: function () {
|
|
58
|
+
updateDrawPen({ target: { value: index + 1 } });
|
|
59
|
+
setDrawingEnabled(true);
|
|
60
|
+
} }, { children: value }), index)); }) }))] })));
|
|
61
|
+
};
|
|
62
|
+
export default DrawPlatte;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CSSProperties } from "react";
|
|
2
|
+
import type { ROI } from "../../core/features/rois/roiTypes";
|
|
3
|
+
export interface DrawToolkitProps {
|
|
4
|
+
nv: any;
|
|
5
|
+
volumes: {
|
|
6
|
+
url: string;
|
|
7
|
+
name: string;
|
|
8
|
+
}[];
|
|
9
|
+
selectedVolume: number;
|
|
10
|
+
updateDrawPen: (e: any) => void;
|
|
11
|
+
drawPen: number;
|
|
12
|
+
setDrawingEnabled: (enabled: boolean) => void;
|
|
13
|
+
drawingEnabled: boolean;
|
|
14
|
+
rois: ROI[];
|
|
15
|
+
selectedROI: number;
|
|
16
|
+
setSelectedROI: (selected: number) => void;
|
|
17
|
+
saveROI: () => void;
|
|
18
|
+
changesMade: boolean;
|
|
19
|
+
drawUndo: () => void;
|
|
20
|
+
style: CSSProperties;
|
|
21
|
+
brushSize: number;
|
|
22
|
+
updateBrushSize: (size: number) => void;
|
|
23
|
+
resampleImage: () => void;
|
|
24
|
+
roiVisible: boolean;
|
|
25
|
+
toggleROIVisible: () => void;
|
|
26
|
+
drawingOpacity: number;
|
|
27
|
+
setDrawingOpacity: (opacity: number) => void;
|
|
28
|
+
labelsVisible: boolean;
|
|
29
|
+
toggleLabelsVisible: () => void;
|
|
30
|
+
setDrawingChanged: (changed: boolean) => void;
|
|
31
|
+
}
|
|
32
|
+
export declare const DrawToolkit: (props: DrawToolkitProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,136 @@
|
|
|
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
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { Box, FormControl, IconButton, Slider, Stack, Tooltip, Typography, FormLabel, } from "@mui/material";
|
|
14
|
+
import BrushIcon from "@mui/icons-material/Brush";
|
|
15
|
+
import AutoFixNormalOutlinedIcon from "@mui/icons-material/AutoFixNormalOutlined";
|
|
16
|
+
import ReplyIcon from "@mui/icons-material/Reply";
|
|
17
|
+
import CameraAltIcon from "@mui/icons-material/CameraAlt";
|
|
18
|
+
import React, { useState } from "react";
|
|
19
|
+
import SvgIcon from "@mui/material/SvgIcon";
|
|
20
|
+
import FormatColorFillIcon from "@mui/icons-material/FormatColorFill";
|
|
21
|
+
import DrawPlatte from "./DrawPlatte";
|
|
22
|
+
import DeleteIcon from "@mui/icons-material/Delete";
|
|
23
|
+
import EraserPlatte from "./EraserPlatte";
|
|
24
|
+
import VisibilityIcon from "@mui/icons-material/Visibility";
|
|
25
|
+
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
|
26
|
+
import OpacityIcon from "@mui/icons-material/Opacity";
|
|
27
|
+
import MaskPlatte from "./MaskPlatte";
|
|
28
|
+
import ClickAwayListener from "@mui/material/ClickAwayListener";
|
|
29
|
+
export var DrawToolkit = function (props) {
|
|
30
|
+
var _a = useState("n"), expandedOption = _a[0], setExpandedOption = _a[1];
|
|
31
|
+
var _b = React.useState(false), expandOpacityOptions = _b[0], setExpandOpacityOptions = _b[1];
|
|
32
|
+
var penColor = ["red", "green", "blue", "yellow", "cyan", "#e81ce8"][(props.drawPen & 7) - 1];
|
|
33
|
+
var filled = props.drawPen > 7;
|
|
34
|
+
function clickPaintBrush() {
|
|
35
|
+
if (expandedOption === "d") {
|
|
36
|
+
setExpandedOption("n");
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
setExpandedOption("d");
|
|
40
|
+
}
|
|
41
|
+
props.setDrawingEnabled(expandedOption !== "d");
|
|
42
|
+
}
|
|
43
|
+
function clickEraser() {
|
|
44
|
+
if (expandedOption === "e") {
|
|
45
|
+
setExpandedOption("n");
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
props.updateDrawPen({ target: { value: 8 } });
|
|
49
|
+
setExpandedOption("e");
|
|
50
|
+
}
|
|
51
|
+
props.setDrawingEnabled(expandedOption !== "e");
|
|
52
|
+
}
|
|
53
|
+
var _c = useState(undefined), maskColor = _c[0], setMaskColor = _c[1];
|
|
54
|
+
function clickMask() {
|
|
55
|
+
if (expandedOption === "m") {
|
|
56
|
+
setExpandedOption("n");
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
setExpandedOption("m");
|
|
60
|
+
}
|
|
61
|
+
props.setDrawingEnabled(false);
|
|
62
|
+
}
|
|
63
|
+
return (_jsx(ClickAwayListener, __assign({ onClickAway: function () {
|
|
64
|
+
setExpandedOption("n");
|
|
65
|
+
setExpandOpacityOptions(false);
|
|
66
|
+
props.setDrawingEnabled(false);
|
|
67
|
+
} }, { children: _jsxs(Box, __assign({ sx: {
|
|
68
|
+
display: "flex",
|
|
69
|
+
width: "100%",
|
|
70
|
+
flexDirection: "row",
|
|
71
|
+
justifyItems: "center",
|
|
72
|
+
alignItems: "center",
|
|
73
|
+
borderRadius: "4px",
|
|
74
|
+
height: "20pt",
|
|
75
|
+
backgroundColor: "#333"
|
|
76
|
+
}, style: props.style }, { children: [_jsx(FormControl, { children: _jsx(FormLabel, __assign({ component: "legend", className: "ms-2", style: {
|
|
77
|
+
width: "100%",
|
|
78
|
+
textAlign: "center",
|
|
79
|
+
color: "white",
|
|
80
|
+
fontSize: 16,
|
|
81
|
+
fontWeight: 400
|
|
82
|
+
}, sx: {
|
|
83
|
+
marginBottom: 0,
|
|
84
|
+
marginLeft: 2,
|
|
85
|
+
color: "white",
|
|
86
|
+
fontWeight: 500,
|
|
87
|
+
fontSize: 14
|
|
88
|
+
} }, { children: "ROI Tools:" })) }), _jsx(FormControl, { children: _jsxs(Stack, __assign({ direction: "row" }, { children: [_jsx(IconButton, __assign({ "aria-label": "draw", onClick: clickPaintBrush }, { children: _jsx(BrushIcon, { style: {
|
|
89
|
+
color: expandedOption === "d" && penColor !== undefined
|
|
90
|
+
? penColor
|
|
91
|
+
: "white"
|
|
92
|
+
} }) })), _jsx(DrawPlatte, { expandDrawOptions: expandedOption === "d", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, brushSize: props.brushSize, updateBrushSize: props.updateBrushSize })] })) }), _jsx(FormControl, { children: _jsxs(Stack, __assign({ direction: "row" }, { children: [_jsx(IconButton, __assign({ "aria-label": "erase", onClick: clickEraser }, { children: filled || !(expandedOption === "e") ? (_jsx(EraserIcon, { style: { color: "#ddd" } })) : (_jsx(AutoFixNormalOutlinedIcon, { style: { color: "white" } })) })), _jsx(EraserPlatte, { expandEraseOptions: expandedOption === "e", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, brushSize: props.brushSize, updateBrushSize: props.updateBrushSize })] })) }), _jsx(FormControl, { children: _jsx(Stack, __assign({ direction: "row" }, { children: _jsx(IconButton, __assign({ "aria-label": "revert", onClick: function () {
|
|
93
|
+
props.drawUndo();
|
|
94
|
+
} }, { children: _jsx(ReplyIcon, { style: { color: "white" } }) })) })) }), _jsx(FormControl, { children: _jsx(IconButton, __assign({ "aria-label": "capture", onClick: function () {
|
|
95
|
+
props.nv.saveScene("".concat(props.volumes[props.selectedVolume].name, "_drawing.png"));
|
|
96
|
+
} }, { children: _jsx(CameraAltIcon, { style: { color: "white" } }) })) }), _jsx(FormControl, { children: _jsx(IconButton, __assign({ "aria-label": "delete", onClick: function () {
|
|
97
|
+
props.nv.clearDrawing();
|
|
98
|
+
props.resampleImage();
|
|
99
|
+
props.setDrawingChanged(false);
|
|
100
|
+
} }, { children: _jsx(DeleteIcon, { style: { color: "white" } }) })) }), _jsx(Tooltip, __assign({ title: "Region of interests visibility" }, { children: _jsx(FormControl, { children: _jsx(IconButton, __assign({ "aria-label": "visible", onClick: function () {
|
|
101
|
+
props.toggleROIVisible();
|
|
102
|
+
} }, { children: props.roiVisible ? (_jsx(VisibilityIcon, { style: { color: "white" } })) : (_jsx(VisibilityOffIcon, { style: { color: "white" } })) })) }) })), _jsxs(FormControl, __assign({ style: { flexDirection: "row", alignItems: "center", color: "white" } }, { children: [_jsx(Tooltip, __assign({ title: "Region of interests opacity" }, { children: _jsx(IconButton, __assign({ "aria-label": "opaque", onClick: function () {
|
|
103
|
+
setExpandOpacityOptions(!expandOpacityOptions);
|
|
104
|
+
} }, { children: _jsx(OpacityIcon, { style: { color: "white" } }) })) })), "=", " ".concat(props.drawingOpacity), _jsx(OpacityPlatte, { drawingOpacity: props.drawingOpacity, setDrawingOpacity: props.setDrawingOpacity, expanded: expandOpacityOptions })] })), _jsxs(FormControl, { children: [_jsx(Stack, __assign({ direction: "row" }, { children: _jsx(IconButton, __assign({ "aria-label": "fill", onClick: clickMask }, { children: _jsx(FormatColorFillIcon, { style: {
|
|
105
|
+
color: expandedOption === "m" && maskColor !== undefined
|
|
106
|
+
? maskColor
|
|
107
|
+
: "white"
|
|
108
|
+
} }) })) })), _jsx(MaskPlatte, { resampleImage: function () {
|
|
109
|
+
props.resampleImage();
|
|
110
|
+
props.setDrawingChanged(true);
|
|
111
|
+
}, expanded: expandedOption === "m", nv: props.nv, setMaskColor: setMaskColor, unfocus: function () {
|
|
112
|
+
setExpandedOption("n");
|
|
113
|
+
} })] })] })) })));
|
|
114
|
+
};
|
|
115
|
+
function EraserIcon(props) {
|
|
116
|
+
return (_jsxs(SvgIcon, __assign({}, props, { viewBox: "0 0 25 25" }, { children: [_jsx("rect", { x: "6", y: "3", width: "12", height: "22", rx: "2", ry: "2", transform: "rotate(230 12 12)", fill: "currentColor" }), _jsx("rect", { x: "7", y: "4", width: "10", height: "8", rx: "2", ry: "2", transform: "rotate(230 12 12)", fill: "#FFFFFF" })] })));
|
|
117
|
+
}
|
|
118
|
+
var OpacityPlatte = function (_a) {
|
|
119
|
+
var drawingOpacity = _a.drawingOpacity, setDrawingOpacity = _a.setDrawingOpacity, expanded = _a.expanded;
|
|
120
|
+
return (_jsx(Stack, __assign({ style: {
|
|
121
|
+
position: "absolute",
|
|
122
|
+
top: "100%",
|
|
123
|
+
left: 0,
|
|
124
|
+
zIndex: 10,
|
|
125
|
+
border: "".concat(expanded ? "1px" : 0, " solid #bbb"),
|
|
126
|
+
maxWidth: expanded ? 300 : 0,
|
|
127
|
+
overflow: "hidden",
|
|
128
|
+
borderRadius: "16px",
|
|
129
|
+
borderTopLeftRadius: "6pt",
|
|
130
|
+
borderTopRightRadius: "6pt",
|
|
131
|
+
background: "#333",
|
|
132
|
+
width: 150
|
|
133
|
+
}, direction: "column" }, { children: _jsxs(Stack, __assign({ sx: { mb: 1 }, alignItems: "center" }, { children: [_jsx(Typography, __assign({ color: "white", noWrap: true, gutterBottom: true, width: "100%", marginLeft: "10pt", fontSize: "11pt", alignItems: "start" }, { children: "Opacity: ".concat(drawingOpacity) })), _jsx(Slider, { sx: { width: "80%" }, value: drawingOpacity, step: 0.01, min: 0, max: 1, onChange: function (_event, value) {
|
|
134
|
+
setDrawingOpacity(value);
|
|
135
|
+
} })] })) })));
|
|
136
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface EraserPlatteProps {
|
|
3
|
+
expandEraseOptions: boolean;
|
|
4
|
+
updateDrawPen: (e: any) => void;
|
|
5
|
+
setDrawingEnabled: (enabled: boolean) => void;
|
|
6
|
+
brushSize: number;
|
|
7
|
+
updateBrushSize: (size: number) => void;
|
|
8
|
+
}
|
|
9
|
+
declare const EraserPlatte: React.FC<EraserPlatteProps>;
|
|
10
|
+
export default EraserPlatte;
|
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { Stack, IconButton, Slider, Typography } from "@mui/material";
|
|
14
|
+
import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord";
|
|
15
|
+
import FiberManualRecordOutlinedIcon from "@mui/icons-material/FiberManualRecordOutlined";
|
|
16
|
+
var EraserPlatte = function (_a) {
|
|
17
|
+
var expandEraseOptions = _a.expandEraseOptions, updateDrawPen = _a.updateDrawPen, setDrawingEnabled = _a.setDrawingEnabled, brushSize = _a.brushSize, updateBrushSize = _a.updateBrushSize;
|
|
18
|
+
var eraseOptions = [
|
|
19
|
+
_jsx(FiberManualRecordIcon, { style: { color: "white" } }, "e0"),
|
|
20
|
+
_jsx(FiberManualRecordOutlinedIcon, { style: { color: "white" } }, "e1"),
|
|
21
|
+
];
|
|
22
|
+
return (_jsxs(Stack, __assign({ style: {
|
|
23
|
+
position: "absolute",
|
|
24
|
+
top: "100%",
|
|
25
|
+
left: 0,
|
|
26
|
+
zIndex: 10,
|
|
27
|
+
border: "".concat(expandEraseOptions ? "1px" : 0, " solid #bbb"),
|
|
28
|
+
maxWidth: expandEraseOptions ? 300 : 0,
|
|
29
|
+
overflow: "hidden",
|
|
30
|
+
borderRadius: "16px",
|
|
31
|
+
borderTopLeftRadius: "6pt",
|
|
32
|
+
borderTopRightRadius: "6pt",
|
|
33
|
+
background: "#333",
|
|
34
|
+
width: 150
|
|
35
|
+
}, direction: "column" }, { children: [_jsxs(Stack, __assign({ sx: { mb: 1 }, alignItems: "center" }, { children: [_jsx(Typography, __assign({ color: "white", noWrap: true, gutterBottom: true, width: "100%", marginLeft: "10pt", fontSize: "11pt", alignItems: "start" }, { children: "Eraser Size: ".concat(brushSize) })), _jsx(Slider, { sx: { width: "80%" }, value: brushSize, step: 2, min: 1, max: 15, marks: true, onChange: function (_event, value) {
|
|
36
|
+
updateBrushSize(value);
|
|
37
|
+
} })] })), _jsx(Stack, __assign({ direction: "row", style: { justifyContent: "center" } }, { children: eraseOptions.map(function (value, index) { return (_jsx(IconButton, __assign({ onClick: function () {
|
|
38
|
+
updateDrawPen({ target: { value: index === 0 ? 8 : 0 } });
|
|
39
|
+
setDrawingEnabled(true);
|
|
40
|
+
} }, { children: value }), index)); }) }))] })));
|
|
41
|
+
};
|
|
42
|
+
export default EraserPlatte;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface MaskPlatteProps {
|
|
3
|
+
expanded: boolean;
|
|
4
|
+
nv: any;
|
|
5
|
+
setMaskColor: (color: string | undefined) => void;
|
|
6
|
+
resampleImage: () => void;
|
|
7
|
+
unfocus: () => void;
|
|
8
|
+
}
|
|
9
|
+
declare const MaskPlatte: React.FC<MaskPlatteProps>;
|
|
10
|
+
export default MaskPlatte;
|
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { useEffect, useState } from "react";
|
|
14
|
+
import { Stack, IconButton, Typography, Box } from "@mui/material";
|
|
15
|
+
import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord";
|
|
16
|
+
import CheckIcon from "@mui/icons-material/Check";
|
|
17
|
+
import CloseIcon from "@mui/icons-material/Close";
|
|
18
|
+
import { InvertibleDualSlider } from "../double-slider/InvertibleDualSlider";
|
|
19
|
+
import { CmrCheckbox } from "../CmrCheckbox/CmrCheckbox";
|
|
20
|
+
var MaskPlatte = function (_a) {
|
|
21
|
+
var expanded = _a.expanded, nv = _a.nv, setMaskColor = _a.setMaskColor, resampleImage = _a.resampleImage, unfocus = _a.unfocus;
|
|
22
|
+
var _b = useState(0), colorIndex = _b[0], storeColorIndex = _b[1];
|
|
23
|
+
var _c = useState("red"), maskColor = _c[0], storeMaskColor = _c[1];
|
|
24
|
+
var _d = useState(false), checked = _d[0], setChecked = _d[1];
|
|
25
|
+
var _e = useState(undefined), original = _e[0], setOriginal = _e[1];
|
|
26
|
+
var colors = ["red", "green", "blue", "yellow", "cyan", "#e81ce8"];
|
|
27
|
+
var filledOptions = colors.map(function (color, i) { return (_jsx(FiberManualRecordIcon, { sx: { color: color } }, i)); });
|
|
28
|
+
if (expanded) {
|
|
29
|
+
setMaskColor(maskColor);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
setMaskColor(undefined);
|
|
33
|
+
}
|
|
34
|
+
var _f = useState(nv.volumes[0] ? nv.volumes[0].vox_min : 0), min = _f[0], setMin = _f[1];
|
|
35
|
+
var _g = useState(nv.volumes[0] ? nv.volumes[0].vox_max : 1), max = _g[0], setMax = _g[1];
|
|
36
|
+
var cancelMask = function () {
|
|
37
|
+
if (original)
|
|
38
|
+
nv.drawBitmap = new Uint8Array(original);
|
|
39
|
+
else
|
|
40
|
+
return;
|
|
41
|
+
nv.refreshDrawing(true);
|
|
42
|
+
resampleImage();
|
|
43
|
+
setOriginal(undefined);
|
|
44
|
+
};
|
|
45
|
+
useEffect(function () {
|
|
46
|
+
if (!expanded) {
|
|
47
|
+
cancelMask();
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
if (colorIndex !== -1)
|
|
51
|
+
nv.fillRange(min, max, colorIndex + 1, checked, original, setOriginal);
|
|
52
|
+
resampleImage();
|
|
53
|
+
}
|
|
54
|
+
}, [expanded]);
|
|
55
|
+
useEffect(function () {
|
|
56
|
+
if (colorIndex !== -1 && expanded)
|
|
57
|
+
nv.fillRange(min, max, colorIndex + 1, checked, original, setOriginal);
|
|
58
|
+
}, [min, max, checked]);
|
|
59
|
+
return (_jsxs(Stack, __assign({ style: {
|
|
60
|
+
position: "absolute",
|
|
61
|
+
top: "100%",
|
|
62
|
+
left: 0,
|
|
63
|
+
zIndex: 10,
|
|
64
|
+
border: "".concat(expanded ? "1px" : 0, " solid #bbb"),
|
|
65
|
+
maxWidth: expanded ? 450 : 0,
|
|
66
|
+
overflow: "hidden",
|
|
67
|
+
borderRadius: "16px",
|
|
68
|
+
borderTopLeftRadius: "6pt",
|
|
69
|
+
borderTopRightRadius: "6pt",
|
|
70
|
+
background: "#333"
|
|
71
|
+
}, direction: "column" }, { children: [_jsx(Stack, __assign({ alignItems: "center" }, { children: _jsx(Typography, __assign({ color: "white", gutterBottom: true, width: "100%", marginLeft: "10pt", fontSize: "11pt", alignItems: "start" }, { children: "Mask range:" })) })), _jsxs(Stack, __assign({ direction: "row", flexDirection: "row", justifyContent: "center" }, { children: [filledOptions.map(function (value, index) { return (_jsx(IconButton, __assign({ onClick: function () {
|
|
72
|
+
storeColorIndex(index);
|
|
73
|
+
storeMaskColor(colors[index]);
|
|
74
|
+
setMaskColor(colors[index]);
|
|
75
|
+
nv.fillRange(min, max, index + 1, checked, original, setOriginal);
|
|
76
|
+
resampleImage();
|
|
77
|
+
} }, { children: value }), index)); }), _jsx(CmrCheckbox, __assign({ style: { color: "white" }, onChange: function (e) {
|
|
78
|
+
e.stopPropagation();
|
|
79
|
+
setChecked(e.target.checked);
|
|
80
|
+
resampleImage();
|
|
81
|
+
} }, { children: "Inverted" }))] })), _jsx(Stack, __assign({ direction: "row", sx: { mb: 1 } }, { children: _jsx(Box, __assign({ width: 400, style: { paddingLeft: "10px", paddingRight: "10px" } }, { children: _jsx(InvertibleDualSlider, { name: "", min: nv.volumes[0] ? nv.volumes[0].vox_min : 0, max: nv.volumes[0] ? nv.volumes[0].vox_max : 1, reverse: checked, setMin: setMin, setMax: setMax, onFinalize: function () {
|
|
82
|
+
resampleImage();
|
|
83
|
+
} }) })) })), _jsxs(Stack, __assign({ direction: "row", flexDirection: "row", justifyContent: "center" }, { children: [_jsx(IconButton, __assign({ onClick: function () {
|
|
84
|
+
setOriginal(undefined);
|
|
85
|
+
nv.drawAddUndoBitmapWithHiddenVoxels();
|
|
86
|
+
unfocus();
|
|
87
|
+
} }, { children: _jsx(CheckIcon, { style: { color: "green" } }) })), _jsx(IconButton, __assign({ onClick: function () {
|
|
88
|
+
cancelMask();
|
|
89
|
+
unfocus();
|
|
90
|
+
} }, { children: _jsx(CloseIcon, { style: { color: "red" } }) }))] }))] })));
|
|
91
|
+
};
|
|
92
|
+
export default MaskPlatte;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface NiivueRoiHistogramProps {
|
|
3
|
+
/** DOM id used by `resampleNiivueRoiHistogram` / `document.getElementById`. Default: `histoplot`. */
|
|
4
|
+
plotElementId?: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
style?: React.CSSProperties;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Mount point for the Plotly ROI histogram. Default id `histoplot` matches MROptimum WebGUI.
|
|
10
|
+
*/
|
|
11
|
+
export declare function NiivueRoiHistogram(props: NiivueRoiHistogramProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Mount point for the Plotly ROI histogram. Default id `histoplot` matches MROptimum WebGUI.
|
|
4
|
+
*/
|
|
5
|
+
export function NiivueRoiHistogram(props) {
|
|
6
|
+
var _a;
|
|
7
|
+
var id = (_a = props.plotElementId) !== null && _a !== void 0 ? _a : "histoplot";
|
|
8
|
+
return (_jsx("div", { id: id, className: props.className, style: props.style }));
|
|
9
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Layout } from "plotly.js-dist-min";
|
|
2
|
+
/** Maps Niivue label index (e.g. "1".."7") to a display name in the legend / ROI table. */
|
|
3
|
+
export type RoiLabelMapping = Record<string, string>;
|
|
4
|
+
export interface NiivueRoiHistogramRow {
|
|
5
|
+
label: string;
|
|
6
|
+
alias: string;
|
|
7
|
+
visibility: boolean;
|
|
8
|
+
color: string;
|
|
9
|
+
mu: number;
|
|
10
|
+
std: number;
|
|
11
|
+
opacity: number;
|
|
12
|
+
count: number;
|
|
13
|
+
sample: number[];
|
|
14
|
+
}
|
|
15
|
+
/** Plotly layout matching MROptimum WebGUI ROI histogram defaults. */
|
|
16
|
+
export declare function getDefaultRoiHistogramLayout(): Partial<Layout>;
|
|
17
|
+
/**
|
|
18
|
+
* Recomputes per-ROI voxel samples from the Niivue instance, updates the Plotly histogram
|
|
19
|
+
* at `plotRoot`, and returns the row data for tables / export.
|
|
20
|
+
*
|
|
21
|
+
* @returns `null` if `plotRoot` is missing (caller should retain prior ROI state), otherwise
|
|
22
|
+
* the new ROI rows (empty when drawing was cleared).
|
|
23
|
+
*/
|
|
24
|
+
export declare function resampleNiivueRoiHistogram(options: {
|
|
25
|
+
nv: any;
|
|
26
|
+
labelMapping?: RoiLabelMapping;
|
|
27
|
+
plotRoot: HTMLElement | null | undefined;
|
|
28
|
+
layout?: Partial<Layout>;
|
|
29
|
+
}): NiivueRoiHistogramRow[] | null;
|
|
@@ -0,0 +1,134 @@
|
|
|
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
|
+
import Plotly from "plotly.js-dist-min";
|
|
13
|
+
import { calculateMean, calculateStandardDeviation } from "./roiHistogramStats";
|
|
14
|
+
var ROI_HISTOGRAM_COLORS = [
|
|
15
|
+
"#bbb",
|
|
16
|
+
"#f00",
|
|
17
|
+
"#0f0",
|
|
18
|
+
"#00f",
|
|
19
|
+
"yellow",
|
|
20
|
+
"cyan",
|
|
21
|
+
"#e81ce8",
|
|
22
|
+
"#e8dbc7",
|
|
23
|
+
];
|
|
24
|
+
/** Plotly layout matching MROptimum WebGUI ROI histogram defaults. */
|
|
25
|
+
export function getDefaultRoiHistogramLayout() {
|
|
26
|
+
return {
|
|
27
|
+
barmode: "overlay",
|
|
28
|
+
title: { text: "ROI Histogram" },
|
|
29
|
+
margin: {
|
|
30
|
+
l: 50,
|
|
31
|
+
r: 50,
|
|
32
|
+
b: 50,
|
|
33
|
+
t: 60,
|
|
34
|
+
pad: 4
|
|
35
|
+
},
|
|
36
|
+
xaxis: {
|
|
37
|
+
title: { text: "Voxel value" },
|
|
38
|
+
showgrid: true
|
|
39
|
+
},
|
|
40
|
+
yaxis: {
|
|
41
|
+
title: { text: "Bin frequency" },
|
|
42
|
+
showgrid: true
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Recomputes per-ROI voxel samples from the Niivue instance, updates the Plotly histogram
|
|
48
|
+
* at `plotRoot`, and returns the row data for tables / export.
|
|
49
|
+
*
|
|
50
|
+
* @returns `null` if `plotRoot` is missing (caller should retain prior ROI state), otherwise
|
|
51
|
+
* the new ROI rows (empty when drawing was cleared).
|
|
52
|
+
*/
|
|
53
|
+
export function resampleNiivueRoiHistogram(options) {
|
|
54
|
+
var _a, _b, _c, _d;
|
|
55
|
+
var nv = options.nv, _e = options.labelMapping, labelMapping = _e === void 0 ? {} : _e, plotRoot = options.plotRoot, layoutOverrides = options.layout;
|
|
56
|
+
if (typeof document === "undefined" || !plotRoot) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
var image = (_a = nv.volumes) === null || _a === void 0 ? void 0 : _a[0];
|
|
60
|
+
var layout = __assign(__assign({}, getDefaultRoiHistogramLayout()), layoutOverrides);
|
|
61
|
+
if (nv.drawBitmap == null) {
|
|
62
|
+
Plotly.newPlot(plotRoot, [], layout, { responsive: true });
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
if (!image) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
var min = image.robust_min;
|
|
69
|
+
var max = image.robust_max;
|
|
70
|
+
var samples = {
|
|
71
|
+
1: [],
|
|
72
|
+
2: [],
|
|
73
|
+
3: [],
|
|
74
|
+
4: [],
|
|
75
|
+
5: [],
|
|
76
|
+
6: [],
|
|
77
|
+
7: []
|
|
78
|
+
};
|
|
79
|
+
for (var i = 0; i < nv.drawBitmap.length; i++) {
|
|
80
|
+
var k = nv.drawBitmap[i];
|
|
81
|
+
if (samples[k] === undefined) {
|
|
82
|
+
samples[k] = [];
|
|
83
|
+
}
|
|
84
|
+
samples[k].push(image.img[i]);
|
|
85
|
+
}
|
|
86
|
+
if (nv.hiddenBitmap !== undefined) {
|
|
87
|
+
for (var i = 0; i < nv.hiddenBitmap.length; i++) {
|
|
88
|
+
var k = nv.hiddenBitmap[i];
|
|
89
|
+
if (samples[k] === undefined) {
|
|
90
|
+
samples[k] = [];
|
|
91
|
+
}
|
|
92
|
+
samples[k].push(image.img[i]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
var rois = [];
|
|
96
|
+
for (var sk in samples) {
|
|
97
|
+
var key = Number(sk);
|
|
98
|
+
var sample = samples[key];
|
|
99
|
+
if (sample.length > 0 && key > 0) {
|
|
100
|
+
rois.push({
|
|
101
|
+
label: String(key),
|
|
102
|
+
alias: (_c = (_b = labelMapping[sk]) !== null && _b !== void 0 ? _b : labelMapping[String(key)]) !== null && _c !== void 0 ? _c : String(key),
|
|
103
|
+
visibility: nv.getLabelVisibility(Number(key)),
|
|
104
|
+
color: (_d = ROI_HISTOGRAM_COLORS[key]) !== null && _d !== void 0 ? _d : ROI_HISTOGRAM_COLORS[0],
|
|
105
|
+
mu: calculateMean(sample),
|
|
106
|
+
std: calculateStandardDeviation(sample),
|
|
107
|
+
opacity: nv.drawOpacity,
|
|
108
|
+
count: sample.length,
|
|
109
|
+
sample: sample
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
var traces = [];
|
|
114
|
+
for (var _i = 0, rois_1 = rois; _i < rois_1.length; _i++) {
|
|
115
|
+
var roi = rois_1[_i];
|
|
116
|
+
traces.push({
|
|
117
|
+
x: roi.sample,
|
|
118
|
+
type: "histogram",
|
|
119
|
+
name: roi.alias,
|
|
120
|
+
opacity: roi.visibility ? 0.5 : 0.1,
|
|
121
|
+
marker: {
|
|
122
|
+
color: roi.color
|
|
123
|
+
},
|
|
124
|
+
autobinx: false,
|
|
125
|
+
xbins: {
|
|
126
|
+
start: min,
|
|
127
|
+
end: max,
|
|
128
|
+
size: (max - min) / 100
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
Plotly.newPlot(plotRoot, traces, layout, { responsive: true });
|
|
133
|
+
return rois;
|
|
134
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function calculateMean(numbers) {
|
|
2
|
+
var sum = numbers.reduce(function (acc, val) { return acc + val; }, 0);
|
|
3
|
+
return sum / numbers.length;
|
|
4
|
+
}
|
|
5
|
+
export function calculateStandardDeviation(numbers) {
|
|
6
|
+
var mean = calculateMean(numbers);
|
|
7
|
+
var squareDiffs = numbers.map(function (value) {
|
|
8
|
+
var diff = value - mean;
|
|
9
|
+
return diff * diff;
|
|
10
|
+
});
|
|
11
|
+
var avgSquareDiff = calculateMean(squareDiffs);
|
|
12
|
+
return Math.sqrt(avgSquareDiff);
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { Layout } from "plotly.js-dist-min";
|
|
3
|
+
import { type NiivueRoiHistogramRow, type RoiLabelMapping } from "./resampleNiivueRoiHistogram";
|
|
4
|
+
export declare function useNiivueRoiHistogram(nv: any, options?: {
|
|
5
|
+
plotElementId?: string;
|
|
6
|
+
/** Optional Plotly layout overrides passed through to each resample. */
|
|
7
|
+
layout?: Partial<Layout>;
|
|
8
|
+
}): {
|
|
9
|
+
rois: NiivueRoiHistogramRow[];
|
|
10
|
+
setRois: import("react").Dispatch<import("react").SetStateAction<NiivueRoiHistogramRow[]>>;
|
|
11
|
+
labelMapping: RoiLabelMapping;
|
|
12
|
+
setLabelMapping: import("react").Dispatch<import("react").SetStateAction<RoiLabelMapping>>;
|
|
13
|
+
resample: (mapping?: RoiLabelMapping) => void;
|
|
14
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
import { resampleNiivueRoiHistogram, } from "./resampleNiivueRoiHistogram";
|
|
3
|
+
export function useNiivueRoiHistogram(nv, options) {
|
|
4
|
+
var _a;
|
|
5
|
+
var plotElementId = (_a = options === null || options === void 0 ? void 0 : options.plotElementId) !== null && _a !== void 0 ? _a : "histoplot";
|
|
6
|
+
var layout = options === null || options === void 0 ? void 0 : options.layout;
|
|
7
|
+
var _b = useState({}), labelMapping = _b[0], setLabelMapping = _b[1];
|
|
8
|
+
var _c = useState([]), rois = _c[0], setRois = _c[1];
|
|
9
|
+
var resample = useCallback(function (mapping) {
|
|
10
|
+
if (mapping === void 0) { mapping = labelMapping; }
|
|
11
|
+
var el = typeof document !== "undefined"
|
|
12
|
+
? document.getElementById(plotElementId)
|
|
13
|
+
: null;
|
|
14
|
+
var next = resampleNiivueRoiHistogram({
|
|
15
|
+
nv: nv,
|
|
16
|
+
labelMapping: mapping,
|
|
17
|
+
plotRoot: el,
|
|
18
|
+
layout: layout
|
|
19
|
+
});
|
|
20
|
+
if (next !== null) {
|
|
21
|
+
setRois(next);
|
|
22
|
+
}
|
|
23
|
+
}, [nv, labelMapping, plotElementId, layout]);
|
|
24
|
+
return {
|
|
25
|
+
rois: rois,
|
|
26
|
+
setRois: setRois,
|
|
27
|
+
labelMapping: labelMapping,
|
|
28
|
+
setLabelMapping: setLabelMapping,
|
|
29
|
+
resample: resample
|
|
30
|
+
};
|
|
31
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,12 @@ export { NiivueSlicePosition } from "./CmrComponents/niivue-slice-position/Niivu
|
|
|
25
25
|
export type { NiivueSlicePositionProps } from "./CmrComponents/niivue-slice-position/NiivueSlicePosition";
|
|
26
26
|
export { NiivueContrastAdjustments } from "./CmrComponents/niivue-contrast-adjustments/NiivueContrastAdjustments";
|
|
27
27
|
export type { NiivueContrastAdjustmentsProps } from "./CmrComponents/niivue-contrast-adjustments/NiivueContrastAdjustments";
|
|
28
|
+
export { DrawToolkit } from "./CmrComponents/draw-toolkit/DrawToolkit";
|
|
29
|
+
export type { DrawToolkitProps } from "./CmrComponents/draw-toolkit/DrawToolkit";
|
|
30
|
+
export { resampleNiivueRoiHistogram, getDefaultRoiHistogramLayout, } from "./CmrComponents/niivue-roi-histogram/resampleNiivueRoiHistogram";
|
|
31
|
+
export type { NiivueRoiHistogramRow, RoiLabelMapping, } from "./CmrComponents/niivue-roi-histogram/resampleNiivueRoiHistogram";
|
|
32
|
+
export { NiivueRoiHistogram } from "./CmrComponents/niivue-roi-histogram/NiivueRoiHistogram";
|
|
33
|
+
export { useNiivueRoiHistogram } from "./CmrComponents/niivue-roi-histogram/useNiivueRoiHistogram";
|
|
28
34
|
import type { FC } from "react";
|
|
29
35
|
import type { CmrTableProps } from "./CmrTable/CmrTable";
|
|
30
36
|
export declare const CmrTable: FC<CmrTableProps>;
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,10 @@ export { Slider } from "./CmrComponents/gui-slider/Slider";
|
|
|
24
24
|
export { InvertibleDualSlider } from "./CmrComponents/double-slider/InvertibleDualSlider";
|
|
25
25
|
export { NiivueSlicePosition } from "./CmrComponents/niivue-slice-position/NiivueSlicePosition";
|
|
26
26
|
export { NiivueContrastAdjustments } from "./CmrComponents/niivue-contrast-adjustments/NiivueContrastAdjustments";
|
|
27
|
+
export { DrawToolkit } from "./CmrComponents/draw-toolkit/DrawToolkit";
|
|
28
|
+
export { resampleNiivueRoiHistogram, getDefaultRoiHistogramLayout, } from "./CmrComponents/niivue-roi-histogram/resampleNiivueRoiHistogram";
|
|
29
|
+
export { NiivueRoiHistogram } from "./CmrComponents/niivue-roi-histogram/NiivueRoiHistogram";
|
|
30
|
+
export { useNiivueRoiHistogram } from "./CmrComponents/niivue-roi-histogram/useNiivueRoiHistogram";
|
|
27
31
|
import CmrTableComponent from "./CmrTable/CmrTable";
|
|
28
32
|
export var CmrTable = CmrTableComponent;
|
|
29
33
|
export * from "./core";
|