From 79679e34b8176ac22d69bf976d85d27865f63278 Mon Sep 17 00:00:00 2001
From: Chuan-Heng Hsiao <2970164+chhsiao1981@users.noreply.github.com>
Date: Sun, 12 Oct 2025 01:21:39 -0400
Subject: [PATCH] 1. better performance in change colormap. 2.
isNearestInterpolation
---
.../Preview/displays/NiiVueDisplay.tsx | 9 ++-
src/components/Preview/displays/types.ts | 5 ++
src/components/SizedNiivueCanvas/index.tsx | 75 +++++++++++++++----
3 files changed, 71 insertions(+), 18 deletions(-)
diff --git a/src/components/Preview/displays/NiiVueDisplay.tsx b/src/components/Preview/displays/NiiVueDisplay.tsx
index 6ffee9174..5639f33ab 100644
--- a/src/components/Preview/displays/NiiVueDisplay.tsx
+++ b/src/components/Preview/displays/NiiVueDisplay.tsx
@@ -206,7 +206,6 @@ export default (props: Props) => {
onChange={safeSetColorMap}
style={selectStyle}
/>
- {crosshairText}
{
isChecked={isRadiologistView}
onChange={onChangeRadiologistView}
/>
+ {crosshairText}
{
colormapLabel={colormapLabel}
calMax={calMax}
calMin={calMin}
- onLocationChange={(c: CrosshairLocation) =>
- setCrosshairText(c.string)
- }
+ onLocationChange={(c: CrosshairLocation) => {
+ console.info("NiiVueDisplay: onLocationChange: c:", c);
+ setCrosshairText(c.string);
+ }}
sliceType={sliceTypeName}
isRadiologistView={isRadiologistView}
isHide={isHide}
diff --git a/src/components/Preview/displays/types.ts b/src/components/Preview/displays/types.ts
index 212679c37..61cbfb1fc 100644
--- a/src/components/Preview/displays/types.ts
+++ b/src/components/Preview/displays/types.ts
@@ -7,6 +7,11 @@ import type { SLICE_TYPE } from "@niivue/niivue";
*/
export type CrosshairLocation = {
string: string;
+ axCorSag: SLICE_TYPE;
+ frac: Float32Array;
+ mm: Float32Array;
+ vox: Float32Array;
+ xy: [number, number];
};
export enum DisplayType {
diff --git a/src/components/SizedNiivueCanvas/index.tsx b/src/components/SizedNiivueCanvas/index.tsx
index 073d8b882..d95d8ee4d 100644
--- a/src/components/SizedNiivueCanvas/index.tsx
+++ b/src/components/SizedNiivueCanvas/index.tsx
@@ -46,9 +46,9 @@ type Props = {
isScaling?: boolean;
onLocationChange?: (location: CrosshairLocation) => void;
urls?: string[];
- colormap?: string;
- calMin?: number;
- calMax?: number;
+ colormap: string;
+ calMin: number;
+ calMax: number;
colormapLabel?: ColorMap | null;
sliceType?: SliceType;
@@ -78,14 +78,15 @@ export default (props: Props) => {
const glRef = useRef(null);
const [theNiivue, setTheNiivue] = useState(null);
- const [[canvasWidth, canvasHeight], setCanvasDimensions] = useState<
- [number, number]
- >([400, 400]);
+ const [[canvasWidth, canvasHeight], setCanvasDimensions] = useState([
+ 400, 400,
+ ]);
+
+ const [volumeUrl, setVolumeUrl] = useState("");
const isLoggedIn = useAppSelector(({ user }) => user.isLoggedIn);
// useEffect
- // biome-ignore lint/correctness/useExhaustiveDependencies: no need for the onLocationChange
useEffect(() => {
if (isHide) {
return;
@@ -103,16 +104,17 @@ export default (props: Props) => {
crosshairWidth: 1,
isRadiologicalConvention: isRadiologistView,
sliceType: SLICE_TYPE_MAP[sliceType],
+ isNearestInterpolation: true,
});
nv.attachToCanvas(glRef.current);
- if (onLocationChange) {
- nv.onLocationChange = (location) => {
- // console.info("SizedNiivueCanvas: location:", location);
- // onLocationChange(location as CrosshairLocation);
- };
- }
+ nv.onLocationChange = (location) => {
+ console.info("SizedNiivueCanvas: location:", location);
+ if (onLocationChange) {
+ onLocationChange(location as CrosshairLocation);
+ }
+ };
setTheNiivue(nv);
- }, [theNiivue, isHide]);
+ }, [theNiivue, glRef.current, isHide]);
useEffect(() => {
if (!theNiivue) {
@@ -129,6 +131,46 @@ export default (props: Props) => {
theNiivue.setRadiologicalConvention(isRadiologistView);
}, [theNiivue, isRadiologistView]);
+ useEffect(() => {
+ if (!theNiivue) {
+ return;
+ }
+
+ console.info(
+ "SizedNiivueCanvas: updated colormap: volumes:",
+ theNiivue.volumes.length,
+ );
+ if (!theNiivue.volumes.length) {
+ return;
+ }
+
+ theNiivue.volumes[0].setColormap(colormap);
+ if (colormapLabel) {
+ theNiivue.volumes[0].setColormapLabel(colormapLabel);
+ }
+
+ theNiivue.volumes[0].cal_min = calMin;
+ theNiivue.volumes[0].cal_max = calMax;
+
+ console.info(
+ "SizedNiivueCanvas: to refreshLayers: colormap:",
+ colormap,
+ "calMax:",
+ calMax,
+ "volumes[0].cal_max:",
+ theNiivue.volumes[0].cal_max,
+ "calMin:",
+ calMin,
+ "volumes[0].cal_min:",
+ theNiivue.volumes[0].cal_min,
+ "volumes:",
+ theNiivue.volumes[0],
+ );
+
+ theNiivue.refreshLayers(theNiivue.volumes[0], 0);
+ theNiivue.refreshDrawing(true);
+ }, [theNiivue, calMin, calMax, colormap, colormapLabel]);
+
useEffect(() => {
if (isHide) {
return;
@@ -141,6 +183,10 @@ export default (props: Props) => {
return;
}
+ if (urls[0] === volumeUrl) {
+ return;
+ }
+
const volumes = urls.map((url) =>
NVImageFromUrlOptions(
url, // url
@@ -179,6 +225,7 @@ export default (props: Props) => {
};
});
+ setVolumeUrl(urls[0]);
(async () => {
await theNiivue.loadVolumes(authedVolumes);
console.info("after theNiivue.loadVolumes:", theNiivue.volumes.length);