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);