From a773acfa8c56a00540696d7a0138d8595f28d55d Mon Sep 17 00:00:00 2001 From: Tom Kane Date: Fri, 14 Aug 2026 16:23:39 +0000 Subject: [PATCH 01/19] replace camera view with actual video feed from dcam3 --- .../components/tomography/CameraViewer.tsx | 55 ------------------- .../components/tomography/TomographyPlots.tsx | 6 +- 2 files changed, 4 insertions(+), 57 deletions(-) delete mode 100644 apps/visr/src/components/tomography/CameraViewer.tsx diff --git a/apps/visr/src/components/tomography/CameraViewer.tsx b/apps/visr/src/components/tomography/CameraViewer.tsx deleted file mode 100644 index fcc80a53..00000000 --- a/apps/visr/src/components/tomography/CameraViewer.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Box, Typography } from "@mui/material"; - -export default function CameraViewer() { - // static image showing camera view/projection feed - return ( - - - - Camera View - - - - - - - - ); -} diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index d0d33376..fe2e4355 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -1,5 +1,4 @@ import { Box } from "@mui/material"; -import CameraViewer from "./CameraViewer"; import VolumeViewer from "./VolumeViewer"; import SliceViewer from "./SliceViewer"; import { Plane } from "./PlaneEnum"; @@ -35,7 +34,10 @@ function TomographyPlots({ if (!volumeData) return ; const views = [ - , + Detector, Date: Mon, 17 Aug 2026 10:21:35 +0000 Subject: [PATCH 02/19] add titles in TomographyPlots to make viewers more generic --- .../src/components/tomography/SliceViewer.tsx | 36 ++++--------------- .../components/tomography/TomographyPlots.tsx | 23 ++++++++++-- .../components/tomography/VolumeViewer.tsx | 16 --------- 3 files changed, 28 insertions(+), 47 deletions(-) diff --git a/apps/visr/src/components/tomography/SliceViewer.tsx b/apps/visr/src/components/tomography/SliceViewer.tsx index 132ad5fa..a30e0c71 100644 --- a/apps/visr/src/components/tomography/SliceViewer.tsx +++ b/apps/visr/src/components/tomography/SliceViewer.tsx @@ -48,35 +48,13 @@ export default function SliceViewer({ borderColor: "divider", }} > - - - Slice View - - -
- -
+
); } diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index fe2e4355..4753083e 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -1,4 +1,4 @@ -import { Box } from "@mui/material"; +import { Box, Typography } from "@mui/material"; import VolumeViewer from "./VolumeViewer"; import SliceViewer from "./SliceViewer"; import { Plane } from "./PlaneEnum"; @@ -50,14 +50,33 @@ function TomographyPlots({ plane={plane} />, ]; + const titles = ["Camera View", "Reconstruction", "Slice View"]; const plots = views.map((view, i) => ( + + + {titles[i]} + + {view} )); diff --git a/apps/visr/src/components/tomography/VolumeViewer.tsx b/apps/visr/src/components/tomography/VolumeViewer.tsx index 13ae0341..921b0d76 100644 --- a/apps/visr/src/components/tomography/VolumeViewer.tsx +++ b/apps/visr/src/components/tomography/VolumeViewer.tsx @@ -25,22 +25,6 @@ export default function VolumeViewer({ borderColor: "divider", }} > - - - Reconstruction - - - {visible && volumeData && volumeShape ? ( Date: Mon, 17 Aug 2026 10:24:24 +0000 Subject: [PATCH 03/19] remove typography import to fix linting --- apps/visr/src/components/tomography/SliceViewer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/visr/src/components/tomography/SliceViewer.tsx b/apps/visr/src/components/tomography/SliceViewer.tsx index a30e0c71..12f2bdce 100644 --- a/apps/visr/src/components/tomography/SliceViewer.tsx +++ b/apps/visr/src/components/tomography/SliceViewer.tsx @@ -1,4 +1,4 @@ -import { Box, Typography } from "@mui/material"; +import { Box } from "@mui/material"; import { Plane } from "./PlaneEnum"; import { HeatmapPlot } from "@diamondlightsource/davidia"; import ndarray from "ndarray"; From 956a779328537873fd7435002bb0bf3c0e9e978d Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Mon, 17 Aug 2026 11:01:50 +0000 Subject: [PATCH 04/19] remove extra parent objects in sliceViewer and VolumeViewer --- .../src/components/tomography/SliceViewer.tsx | 24 ++++--------- .../components/tomography/VolumeViewer.tsx | 35 ++++++------------- 2 files changed, 18 insertions(+), 41 deletions(-) diff --git a/apps/visr/src/components/tomography/SliceViewer.tsx b/apps/visr/src/components/tomography/SliceViewer.tsx index 12f2bdce..c3b8def6 100644 --- a/apps/visr/src/components/tomography/SliceViewer.tsx +++ b/apps/visr/src/components/tomography/SliceViewer.tsx @@ -39,22 +39,12 @@ export default function SliceViewer({ } return ( - - - + ); } diff --git a/apps/visr/src/components/tomography/VolumeViewer.tsx b/apps/visr/src/components/tomography/VolumeViewer.tsx index 921b0d76..dbfb05c6 100644 --- a/apps/visr/src/components/tomography/VolumeViewer.tsx +++ b/apps/visr/src/components/tomography/VolumeViewer.tsx @@ -14,35 +14,22 @@ export default function VolumeViewer({ volumeShape, visible, }: Props) { - return ( + return visible && volumeData && volumeShape ? ( + + ) : ( - {visible && volumeData && volumeShape ? ( - - ) : ( - - ... - - )} + ... ); } From 90c1debf1d187a8807417e52251716a2bf21abb2 Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Mon, 17 Aug 2026 12:46:36 +0000 Subject: [PATCH 05/19] remove VolumeViewer and show VolumeRenderer directly in TomographyPlots --- .../components/tomography/TomographyPlots.tsx | 7 ++-- .../components/tomography/VolumeViewer.tsx | 35 ------------------- 2 files changed, 3 insertions(+), 39 deletions(-) delete mode 100644 apps/visr/src/components/tomography/VolumeViewer.tsx diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index 4753083e..4ce3026c 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -1,8 +1,8 @@ import { Box, Typography } from "@mui/material"; -import VolumeViewer from "./VolumeViewer"; import SliceViewer from "./SliceViewer"; import { Plane } from "./PlaneEnum"; import { ReactGridLayout, useContainerWidth } from "react-grid-layout"; +import VolumeRenderer from "./VolumeRenderer"; interface Props { volumeData: Uint8Array; @@ -16,7 +16,6 @@ interface Props { function TomographyPlots({ volumeData, volumeShape, - volumeVisible, plane, slice, drawerOpen, @@ -38,10 +37,10 @@ function TomographyPlots({ src="https://visr-pvws.diamond.ac.uk/mjpg/BL01B-DI-CAM-01:PVA:OUTPUT" alt="Detector" />, - , - ) : ( - - ... - - ); -} From db08eabfadc70fd730e1aa4de898f7eaf53887a0 Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Tue, 18 Aug 2026 10:51:32 +0000 Subject: [PATCH 06/19] make plots fill their parent box and fix tomography resizing issues --- .../spectroscopy/SpectroscopyPlots.tsx | 14 +++++-- .../src/components/tomography/SliceViewer.tsx | 34 +++++++++++++---- .../components/tomography/TomographyPlots.tsx | 38 ++++++++++++------- apps/visr/src/utils/createArrayFromView.ts | 1 + 4 files changed, 63 insertions(+), 24 deletions(-) diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx index 2a2429ce..c59920c7 100644 --- a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx +++ b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx @@ -116,13 +116,16 @@ function SpectroscopyPlots({ }> + } + sx={{ display: "flex" }} + > {mounted && ( + + + + + ); } diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index 4ce3026c..7605eb59 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -49,41 +49,51 @@ function TomographyPlots({ plane={plane} />, ]; + const titles = ["Camera View", "Reconstruction", "Slice View"]; + const plots = views.map((view, i) => ( + + {titles[i]} + - - {titles[i]} - + {view} - {view} )); - console.log(plots[0]); + return ( - } color="blue"> + }> {mounted && ( {}} > {plots} diff --git a/apps/visr/src/utils/createArrayFromView.ts b/apps/visr/src/utils/createArrayFromView.ts index 3266f182..0fc5c9b2 100644 --- a/apps/visr/src/utils/createArrayFromView.ts +++ b/apps/visr/src/utils/createArrayFromView.ts @@ -1,6 +1,7 @@ import ndarray, { type NdArray } from "ndarray"; import { assign } from "ndarray-ops"; +//copied (and simplified) from h5web: https://github.com/silx-kit/h5web/blob/a8cceed504b8ab57d426319db56b8b8dab309e3f/packages/shared/src/vis-utils.ts#L103 export default function createArrayFromView( view: NdArray, ): NdArray { From 8a28eedda441a0e72729bfb2d0d2aa482a2a836b Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Tue, 18 Aug 2026 14:25:22 +0100 Subject: [PATCH 07/19] fix spectroscopy resizing --- .../src/components/spectroscopy/SpectroscopyPlots.tsx | 9 +++++---- apps/visr/src/components/tomography/SliceViewer.tsx | 2 +- apps/visr/src/components/tomography/TomographyPlots.tsx | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx index c59920c7..011873da 100644 --- a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx +++ b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx @@ -116,16 +116,16 @@ function SpectroscopyPlots({ {mounted && ( }> {mounted && ( Date: Tue, 18 Aug 2026 13:30:29 +0000 Subject: [PATCH 08/19] allow plotAspectRatio to be any aspect accepted by Davidia --- apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx | 6 +++--- apps/visr/src/components/spectroscopy/SpectroscopyView.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx index 011873da..0841b358 100644 --- a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx +++ b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx @@ -84,7 +84,7 @@ export type SpectroscopyData = Partial>; interface SpectroscopyPlotsProps { expanded: boolean; - plotAspectRatio: number; + plotAspectRatio: number | "auto" | "equal"; } function SpectroscopyPlots({ @@ -125,7 +125,7 @@ function SpectroscopyPlots({ > {mounted && ( Date: Wed, 19 Aug 2026 08:21:09 +0000 Subject: [PATCH 09/19] only remount slice view on window size - tomo page --- apps/visr/src/components/tomography/SliceViewer.tsx | 3 +++ apps/visr/src/components/tomography/TomographyPlots.tsx | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/visr/src/components/tomography/SliceViewer.tsx b/apps/visr/src/components/tomography/SliceViewer.tsx index f48344af..d88f5a22 100644 --- a/apps/visr/src/components/tomography/SliceViewer.tsx +++ b/apps/visr/src/components/tomography/SliceViewer.tsx @@ -9,12 +9,14 @@ interface Props { volumeShape: [number, number, number]; plane: Plane; slice: number; + resizeKey?: string; } export default function SliceViewer({ volumeData, volumeShape, plane, slice, + resizeKey, }: Props) { if (volumeData == undefined || volumeShape == undefined) { return ; @@ -58,6 +60,7 @@ export default function SliceViewer({ }} > ; const views = [ @@ -47,6 +49,7 @@ function TomographyPlots({ volumeShape={volumeShape} slice={slice} plane={plane} + resizeKey={resizeKey} />, ]; @@ -93,7 +96,7 @@ function TomographyPlots({ }> {mounted && ( Date: Thu, 20 Aug 2026 15:26:04 +0000 Subject: [PATCH 10/19] remove one parent Box from SliceViewer --- .../src/components/tomography/SliceViewer.tsx | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/visr/src/components/tomography/SliceViewer.tsx b/apps/visr/src/components/tomography/SliceViewer.tsx index d88f5a22..5ef2d006 100644 --- a/apps/visr/src/components/tomography/SliceViewer.tsx +++ b/apps/visr/src/components/tomography/SliceViewer.tsx @@ -41,33 +41,33 @@ export default function SliceViewer({ } return ( + // - - - + + // ); } From 8843f1cc8d4c8396ec487df0e8c24f97d59a157d Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Thu, 20 Aug 2026 15:26:31 +0000 Subject: [PATCH 11/19] change spectroscopy plot aspect ratio to equal --- apps/visr/src/components/spectroscopy/SpectroscopyView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx index 4aab0627..2ed2a6cb 100644 --- a/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx +++ b/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx @@ -41,7 +41,7 @@ function SpectroscopyView() { const DRAWER_COLLAPSED_HEIGHT = 100; const NAVBAR_HEIGHT = 32; - const PLOT_ASPECT_RATIO = "auto"; + const PLOT_ASPECT_RATIO = "equal"; return ( Date: Fri, 21 Aug 2026 12:31:58 +0000 Subject: [PATCH 12/19] only remount slice view on controls drawer open/close --- apps/visr/src/components/tomography/SliceViewer.tsx | 13 ++----------- .../src/components/tomography/TomographyPlots.tsx | 2 +- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/apps/visr/src/components/tomography/SliceViewer.tsx b/apps/visr/src/components/tomography/SliceViewer.tsx index 5ef2d006..c2fddaa1 100644 --- a/apps/visr/src/components/tomography/SliceViewer.tsx +++ b/apps/visr/src/components/tomography/SliceViewer.tsx @@ -9,7 +9,7 @@ interface Props { volumeShape: [number, number, number]; plane: Plane; slice: number; - resizeKey?: string; + resizeKey?: string; //if this depends on a value, the plot will remount every time that value changes. If no need for it to remound, leave as undefined } export default function SliceViewer({ volumeData, @@ -41,14 +41,6 @@ export default function SliceViewer({ } return ( - // - // ); } diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index d7c789ba..48e530a5 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -30,7 +30,7 @@ function TomographyPlots({ { i: "2", x: drawerOpen ? 2 : 2, y: 0, w: w, h: h, static: true }, ]; - const resizeKey = `${width}`; //`${drawerOpen}-${width}`; + const resizeKey = `${drawerOpen}`; // `${width}`; //`${drawerOpen}-${width}`; if (!volumeData) return ; From a98e1964a06c30ea68e044cf5002d3767abeba67 Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Fri, 21 Aug 2026 12:40:12 +0000 Subject: [PATCH 13/19] spectroscopy plots to display: grid so no need to remount --- .../spectroscopy/SpectroscopyPlots.tsx | 20 +++++++++++++------ .../spectroscopy/SpectroscopyView.tsx | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx index 0841b358..491e0bda 100644 --- a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx +++ b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx @@ -116,12 +116,20 @@ function SpectroscopyPlots({ } - sx={{ display: "flex" }} + sx={{ display: "grid" }} > {mounted && ( Date: Wed, 19 Aug 2026 15:42:10 +0000 Subject: [PATCH 14/19] wip - sorting dynamic grid height --- .../components/tomography/TomographyPlots.tsx | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index d0d33376..01b6303c 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -4,6 +4,7 @@ import VolumeViewer from "./VolumeViewer"; import SliceViewer from "./SliceViewer"; import { Plane } from "./PlaneEnum"; import { ReactGridLayout, useContainerWidth } from "react-grid-layout"; +import { useLayoutEffect, useState } from "react"; interface Props { volumeData: Uint8Array; @@ -25,6 +26,33 @@ function TomographyPlots({ const { width, containerRef, mounted } = useContainerWidth(); const h = 10; const w = 1; + const verticalMargin = 20; + const minimumRowHeight = 10; + const minimumGridHeight = minimumRowHeight * h + verticalMargin * (h - 1); + const [containerHeight, setContainerHeight] = useState(0); + + useLayoutEffect(() => { + const container = containerRef.current; + if (!container) return; + + const resizeObserver = new ResizeObserver(([entry]) => { + setContainerHeight(entry.contentRect.height); + }); + resizeObserver.observe(container); + + return () => resizeObserver.disconnect(); + }, [containerRef]); + + const rowHeight = + containerHeight > 0 + ? Math.max( + (containerHeight - verticalMargin * (h - 1)) / h, + minimumRowHeight, + ) + : drawerOpen + ? minimumRowHeight + : 50; + const gridHeight = rowHeight * h + verticalMargin * (h - 1); const layout = [ { i: "0", x: 0, y: 0, w: w, h: h, static: true }, @@ -52,24 +80,34 @@ function TomographyPlots({ {view} )); - console.log(plots[0]); + return ( - } color="blue"> + } + sx={{ + flex: "1 1 0", + height: gridHeight, + minHeight: minimumGridHeight, + overflow: "visible", + }} + > {mounted && ( {plots} From b40789614571a596d1ca0e66ee8a5c0a96e7f016 Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Thu, 20 Aug 2026 13:55:01 +0000 Subject: [PATCH 15/19] fix overlap issue by removing margin --- .../src/components/tomography/TomographyPlots.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index 01b6303c..ddf0398b 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -26,9 +26,8 @@ function TomographyPlots({ const { width, containerRef, mounted } = useContainerWidth(); const h = 10; const w = 1; - const verticalMargin = 20; - const minimumRowHeight = 10; - const minimumGridHeight = minimumRowHeight * h + verticalMargin * (h - 1); + const minimumRowHeight = 20; + const minimumGridHeight = minimumRowHeight * h; const [containerHeight, setContainerHeight] = useState(0); useLayoutEffect(() => { @@ -45,14 +44,11 @@ function TomographyPlots({ const rowHeight = containerHeight > 0 - ? Math.max( - (containerHeight - verticalMargin * (h - 1)) / h, - minimumRowHeight, - ) + ? Math.max(containerHeight / h, minimumRowHeight) : drawerOpen ? minimumRowHeight : 50; - const gridHeight = rowHeight * h + verticalMargin * (h - 1); + const gridHeight = rowHeight * h; const layout = [ { i: "0", x: 0, y: 0, w: w, h: h, static: true }, @@ -107,7 +103,7 @@ function TomographyPlots({ gridConfig={{ cols: drawerOpen ? 3 : 3, rowHeight: rowHeight, - margin: [verticalMargin, verticalMargin], + margin: [0, 0], }} > {plots} From bea8c32409353ec989503e0600222108b8360bff Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Thu, 20 Aug 2026 15:48:06 +0000 Subject: [PATCH 16/19] get slice viewer to fill height of box --- apps/visr/src/components/tomography/SliceViewer.tsx | 11 +++++++---- .../src/components/tomography/TomographyPlots.tsx | 7 +++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/visr/src/components/tomography/SliceViewer.tsx b/apps/visr/src/components/tomography/SliceViewer.tsx index 132ad5fa..f4823fb2 100644 --- a/apps/visr/src/components/tomography/SliceViewer.tsx +++ b/apps/visr/src/components/tomography/SliceViewer.tsx @@ -63,20 +63,23 @@ export default function SliceViewer({ Slice View -
-
+
); } diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index ddf0398b..b0d59f8f 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -76,8 +76,9 @@ function TomographyPlots({ @@ -90,6 +91,8 @@ function TomographyPlots({ ref={containerRef! as React.RefObject} sx={{ flex: "1 1 0", + width: "100%", + minWidth: 0, height: gridHeight, minHeight: minimumGridHeight, overflow: "visible", From 0c1b40efcba33b27d840cb256a6754d1deb92122 Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Mon, 24 Aug 2026 14:10:56 +0000 Subject: [PATCH 17/19] add margin to typography --- apps/visr/src/components/tomography/TomographyPlots.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index 6966fc32..82f276d0 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -91,7 +91,7 @@ function TomographyPlots({ overflow: "hidden", borderRight: 1, borderColor: "divider", - minWidth: 260, + // minWidth: 260, maxHeight: gridHeight, }} > @@ -100,6 +100,7 @@ function TomographyPlots({ color="primary" borderBottom={1} borderColor={"divider"} + marginLeft={2} > {titles[i]} From 2127f4ac236a1807f092e2574b3665751179a77d Mon Sep 17 00:00:00 2001 From: Tom Kane Date: Thu, 27 Aug 2026 14:11:08 +0000 Subject: [PATCH 18/19] fix plot sizing issues with Davidia components, fix drawer issues, and tidy up --- apps/visr/src/components/ControlsDrawer.tsx | 3 +- .../spectroscopy/SpectroscopyPlots.tsx | 184 +++++++++++++----- .../spectroscopy/SpectroscopyView.tsx | 26 ++- .../src/components/tomography/SliceViewer.tsx | 27 +-- .../components/tomography/TomographyPlots.tsx | 77 ++++++-- .../components/tomography/TomographyView.tsx | 34 +++- 6 files changed, 250 insertions(+), 101 deletions(-) diff --git a/apps/visr/src/components/ControlsDrawer.tsx b/apps/visr/src/components/ControlsDrawer.tsx index 40ff29c1..85003b27 100644 --- a/apps/visr/src/components/ControlsDrawer.tsx +++ b/apps/visr/src/components/ControlsDrawer.tsx @@ -31,6 +31,7 @@ function ControlsDrawer({ boxSizing: "border-box", bgcolor: "transparent", overflowY: "auto", + flexShrink: 0, }, }} > @@ -40,7 +41,7 @@ function ControlsDrawer({ alignItems: "center", justifyContent: "space-between", px: 2, - height: 64, + height: 80, flexShrink: 0, }} > diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx index 491e0bda..5c32835e 100644 --- a/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx +++ b/apps/visr/src/components/spectroscopy/SpectroscopyPlots.tsx @@ -1,9 +1,13 @@ +import { Box, Typography } from "@mui/material"; import { ImagePlot, type NDT } from "@diamondlightsource/davidia"; import ndarray from "ndarray"; +import { ReactGridLayout, useContainerWidth } from "react-grid-layout"; +import { useLayoutEffect, useState, type ComponentProps } from "react"; import { useSpectroscopyData, type RGBColour } from "./useSpectroscopyData"; -import ReactGridLayout, { useContainerWidth } from "react-grid-layout"; -import { useMemo, type ComponentProps } from "react"; -import { Box } from "@mui/material"; + +// --------------------------------------------------------------------------- +// Helpers: data conversion +// --------------------------------------------------------------------------- function toNDT(matrix: (number | null)[][], colour: RGBColour): NDT { if (!matrix?.length || !matrix[0]?.length) { @@ -50,9 +54,14 @@ function toNDT(matrix: (number | null)[][], colour: RGBColour): NDT { return ndarray(rgb, [height, width, 3]) as NDT; } + /** Placeholder empty gray dataset */ const EMPTY_NDT = toNDT([[0]], "gray"); +// --------------------------------------------------------------------------- +// Helpers: data fetching +// --------------------------------------------------------------------------- + /** Return type of `/api/data/map` */ interface MapResponse { values: (number | null)[][]; @@ -71,17 +80,25 @@ async function fetchMap( return toNDT(mapResponse.values, colour); } +// --------------------------------------------------------------------------- +// Channel definitions +// --------------------------------------------------------------------------- + const CHANNELS = [ { key: "red", label: "Red channel" }, { key: "green", label: "Green channel" }, { key: "blue", label: "Blue channel" }, - //{ key: "gray", label: "Gray channel" }, // using gray channel to stop typing errors + //{ key: "gray", label: "Gray channel" }, ] as const; type ChannelKey = (typeof CHANNELS)[number]["key"]; type PlotValues = ComponentProps["values"]; export type SpectroscopyData = Partial>; +// --------------------------------------------------------------------------- +// Component +// --------------------------------------------------------------------------- + interface SpectroscopyPlotsProps { expanded: boolean; plotAspectRatio: number | "auto" | "equal"; @@ -93,72 +110,139 @@ function SpectroscopyPlots({ }: SpectroscopyPlotsProps) { const { data: channels } = useSpectroscopyData(fetchMap); const { width, containerRef, mounted } = useContainerWidth(); - const h = 10; - const w = 1; + // ------------------------------------------------------------------------- + // Grid sizing + // ------------------------------------------------------------------------- + + const totalRows = 10; + const rowsPerPlot = expanded ? totalRows / 2 : totalRows; + const w = 1; + const minimumRowHeight = 20; + const minimumGridHeight = minimumRowHeight * totalRows; + const [containerHeight, setContainerHeight] = useState(0); + + useLayoutEffect(() => { + const container = containerRef.current; + if (!container) return; + + const resizeObserver = new ResizeObserver(([entry]) => { + setContainerHeight(entry.contentRect.height); + }); + resizeObserver.observe(container); + + return () => resizeObserver.disconnect(); + }, [containerRef]); + + const rowHeight = + containerHeight > 0 + ? Math.max(containerHeight / totalRows, minimumRowHeight) + : expanded + ? minimumRowHeight + : 50; + const gridHeight = rowHeight * totalRows; + + // ------------------------------------------------------------------------- + // Layout: 3x1 collapsed, 2x2 expanded + // ------------------------------------------------------------------------- const layout = [ - { i: "0", x: 0, y: 0, w: w, h: h, static: true }, - { i: "1", x: 1, y: 0, w: w, h: h, static: true }, + { i: "0", x: 0, y: 0, w: w, h: rowsPerPlot, static: true }, + { i: "1", x: 1, y: 0, w: w, h: rowsPerPlot, static: true }, { i: "2", - x: !expanded ? 2 : 0, - y: !expanded ? 0 : h, + x: expanded ? 0 : 2, + y: expanded ? rowsPerPlot : 0, w: w, - h: h, + h: rowsPerPlot, static: true, }, - // { i: "3", x: !expanded ? 3 : 1, !expanded ? 0 : h, w: w, h: h, static: true }, ]; - const plots = useMemo( - () => - CHANNELS.map(({ key }, i) => ( - - - - )), - [channels, plotAspectRatio], - ); + // ------------------------------------------------------------------------- + // Views + // ------------------------------------------------------------------------- + const views = CHANNELS.map(({ key }) => ( + + )); + + const titles = CHANNELS.map(({ label }) => label); + + // ------------------------------------------------------------------------- + // Plot cells + // ------------------------------------------------------------------------- + const plots = views.map((view, i) => ( + + + {titles[i]} + + with no height, + // which breaks the size chain. This gives it one. + "& > div": { height: "100%" }, + }} + > + {view} + + + )); + // ------------------------------------------------------------------------- + // Render + // ------------------------------------------------------------------------- return ( } - sx={{ display: "grid" }} + sx={{ + flex: "1 1 0", + width: "100%", + minWidth: 0, + height: gridHeight, + minHeight: minimumGridHeight, + overflow: "visible", + }} > {mounted && ( {}} > {plots} diff --git a/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx b/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx index aa752dc9..137f41fa 100644 --- a/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx +++ b/apps/visr/src/components/spectroscopy/SpectroscopyView.tsx @@ -16,10 +16,20 @@ export type SpectroscopyFormData = { exposure_time: number; }; +// --------------------------------------------------------------------------- +// Layout constants +// --------------------------------------------------------------------------- + +const DRAWER_COLLAPSED_HEIGHT = 80; +const NAVBAR_HEIGHT = 48; +const PLOT_ASPECT_RATIO = "equal"; + function SpectroscopyView() { const [drawerOpen, setDrawerOpen] = useState(true); - // set off workflow when scan ends + // ------------------------------------------------------------------------- + // Set off workflow when scan ends + // ------------------------------------------------------------------------- const scanEvent = useScanEvents(); const { instrumentSession } = useInstrumentSession(); @@ -37,16 +47,18 @@ function SpectroscopyView() { "input-file-path": scanEvent.filepath, }); } - }); - - const DRAWER_COLLAPSED_HEIGHT = 100; - const NAVBAR_HEIGHT = 32; - const PLOT_ASPECT_RATIO = "equal"; + }, [scanEvent, instrumentSession, submitWorkflow]); + // ------------------------------------------------------------------------- + // Render + // ------------------------------------------------------------------------- + // Flex column, not grid: the plots take the remaining space via flex:1 1 0 + // and the drawer keeps its own height. A grid would split the spare height + // evenly between the two rows instead. return ( - - + ); } diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index 82f276d0..32fcacfc 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -1,9 +1,13 @@ import { Box, Typography } from "@mui/material"; -import SliceViewer from "./SliceViewer"; -import { Plane } from "./PlaneEnum"; import { ReactGridLayout, useContainerWidth } from "react-grid-layout"; import { useLayoutEffect, useState } from "react"; +import SliceViewer from "./SliceViewer"; import VolumeRenderer from "./VolumeRenderer"; +import { Plane } from "./PlaneEnum"; + +// --------------------------------------------------------------------------- +// Types +// --------------------------------------------------------------------------- interface Props { volumeData: Uint8Array; @@ -14,6 +18,31 @@ interface Props { plane: Plane; // revolve?: boolean } + +// --------------------------------------------------------------------------- +// Camera view +// --------------------------------------------------------------------------- + +function CamPva() { + const [imgSrc, setImgSrc] = useState( + "https://visr-pvws.diamond.ac.uk/mjpg/BL01B-DI-CAM-01:PVA:OUTPUT", + ); + + return ( + setImgSrc("../../../test-data/seal.png")} + alt="Camera view" + /> + ); +} + +// --------------------------------------------------------------------------- +// Component +// --------------------------------------------------------------------------- + function TomographyPlots({ volumeData, volumeShape, @@ -22,9 +51,13 @@ function TomographyPlots({ drawerOpen, }: Props) { const { width, containerRef, mounted } = useContainerWidth(); + + // ------------------------------------------------------------------------- + // Grid sizing + // ------------------------------------------------------------------------- const h = 10; const w = 1; - const minimumRowHeight = 20; + const minimumRowHeight = 40; const minimumGridHeight = minimumRowHeight * h; const [containerHeight, setContainerHeight] = useState(0); @@ -48,21 +81,22 @@ function TomographyPlots({ : 50; const gridHeight = rowHeight * h; + // ------------------------------------------------------------------------- + // Layout: 3x1 + // ------------------------------------------------------------------------- const layout = [ { i: "0", x: 0, y: 0, w: w, h: h, static: true }, { i: "1", x: 1, y: 0, w: w, h: h, static: true }, - { i: "2", x: drawerOpen ? 2 : 2, y: 0, w: w, h: h, static: true }, + { i: "2", x: 2, y: 0, w: w, h: h, static: true }, ]; - const resizeKey = `${drawerOpen}`; // `${width}`; //`${drawerOpen}-${width}`; - if (!volumeData) return ; + // ------------------------------------------------------------------------- + // Views + // ------------------------------------------------------------------------- const views = [ - Detector, + , , ]; const titles = ["Camera View", "Reconstruction", "Slice View"]; + // ------------------------------------------------------------------------- + // Plot cells + // ------------------------------------------------------------------------- const plots = views.map((view, i) => ( {titles[i]} @@ -108,9 +143,11 @@ function TomographyPlots({ sx={{ flex: 1, minHeight: 0, - width: "100%", - height: "100%", overflow: "hidden", + // davidia wraps every plot in a hardcoded + //
with no height, + // which breaks the size chain. This gives it one. + "& > div": { height: "100%" }, }} > {view} @@ -118,6 +155,9 @@ function TomographyPlots({ )); + // ------------------------------------------------------------------------- + // Render + // ------------------------------------------------------------------------- return ( } @@ -132,12 +172,11 @@ function TomographyPlots({ > {mounted && ( (null); const [volumeVisible, setVolumeVisible] = useState(true); @@ -18,9 +33,10 @@ function TomographyView() { const [slice, setSlice] = useState(0); const [plane, setPlane] = useState(Plane.Z); const [drawerOpen, setDrawerOpen] = useState(true); - const DRAWER_COLLAPSED_HEIGHT = 80; - const NAVBAR_HEIGHT = 32; + // ------------------------------------------------------------------------- + // Load test volume + // ------------------------------------------------------------------------- useEffect(() => { async function loadTestVolume() { const [metaRes, rawRes] = await Promise.all([ @@ -40,7 +56,9 @@ function TomographyView() { loadTestVolume(); }, []); - //use local storage to persist values across multiple open tabs + // ------------------------------------------------------------------------- + // Persist values across multiple open tabs + // ------------------------------------------------------------------------- useEffect(() => { localStorage.setItem("plane", plane.toString()); localStorage.setItem("volumeVisible", volumeVisible.toString()); @@ -71,6 +89,9 @@ function TomographyView() { }; }, []); + // ------------------------------------------------------------------------- + // Handlers + // ------------------------------------------------------------------------- const handleSlider = (event: Event, newValue: number | number[]) => { const slice = typeof newValue == "number" ? newValue : newValue[0]; setSlice(slice); @@ -85,6 +106,9 @@ function TomographyView() { if (!volume) return ; + // ------------------------------------------------------------------------- + // Render + // ------------------------------------------------------------------------- return ( , ]} /> From 123c875f1fcaf3b0e1bd96ee0c088f64427f97f9 Mon Sep 17 00:00:00 2001 From: Abigail Yates Date: Thu, 27 Aug 2026 15:01:37 +0000 Subject: [PATCH 19/19] change min row height to 30 to fit my monitors --- apps/visr/src/components/tomography/TomographyPlots.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/visr/src/components/tomography/TomographyPlots.tsx b/apps/visr/src/components/tomography/TomographyPlots.tsx index 32fcacfc..d309cc2d 100644 --- a/apps/visr/src/components/tomography/TomographyPlots.tsx +++ b/apps/visr/src/components/tomography/TomographyPlots.tsx @@ -57,7 +57,7 @@ function TomographyPlots({ // ------------------------------------------------------------------------- const h = 10; const w = 1; - const minimumRowHeight = 40; + const minimumRowHeight = 30; const minimumGridHeight = minimumRowHeight * h; const [containerHeight, setContainerHeight] = useState(0);