diff --git a/frontend/package-lock.json b/frontend/package-lock.json index fd8249b3..e34a6e3b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "imaginghub", - "version": "0.14.1", + "version": "0.14.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "imaginghub", - "version": "0.14.1", + "version": "0.14.2", "dependencies": { "@apollo/client": "^4.2.9", "@diamondlightsource/davidia": "^1.1.0", diff --git a/frontend/package.json b/frontend/package.json index 64938f1e..bb080a5b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "imaginghub", "private": true, - "version": "0.14.1", + "version": "0.14.2", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/unified/src/components/WorkflowsDataFetcher/Plot/DataLoadingProgress.tsx b/frontend/unified/src/components/WorkflowsDataFetcher/Plot/DataLoadingProgress.tsx index e646cf0a..2ddbf53f 100644 --- a/frontend/unified/src/components/WorkflowsDataFetcher/Plot/DataLoadingProgress.tsx +++ b/frontend/unified/src/components/WorkflowsDataFetcher/Plot/DataLoadingProgress.tsx @@ -2,8 +2,8 @@ import { Box, CircularProgress, Typography } from "@mui/material"; type DataLoadingProgressProps = { mimeType: string; - loadingImageIndex: number | null; - totalImages: number | null; + loadingImageIndex: number; + totalImages: number; }; const BoxHorizontallyCenteredContent = ({ @@ -30,48 +30,40 @@ export const DataLoadingProgress: React.FC = ({ loadingImageIndex, totalImages, }) => { - const displayDataLoadingProgress = () => { - if (mimeType === "image/jpeg") { - return ( - } - /> - ); - } - + if (mimeType === "image/jpeg") { return ( - - {loadingImageIndex !== null && totalImages !== null ? ( - <> - - - {`${loadingImageIndex + 1} / ${totalImages}`} - - - ) : ( - - )} - + } + /> ); - }; + } - return displayDataLoadingProgress(); + return ( + + <> + + + {`${loadingImageIndex + 1} / ${totalImages}`} + + + ) + + ); }; diff --git a/frontend/unified/src/components/WorkflowsDataFetcher/Plot/DataPlotter.tsx b/frontend/unified/src/components/WorkflowsDataFetcher/Plot/DataPlotter.tsx index 6e80ae65..17afbc04 100644 --- a/frontend/unified/src/components/WorkflowsDataFetcher/Plot/DataPlotter.tsx +++ b/frontend/unified/src/components/WorkflowsDataFetcher/Plot/DataPlotter.tsx @@ -7,6 +7,7 @@ type DataPlotterProps = { artifact: Artifact; data: NDT[]; totalImages: number; + loadingIndex: number | null; }; const EXPAND_PLOT_HEIGHT_STYLING = { display: "grid", height: "75vh" }; @@ -15,6 +16,7 @@ export const DataPlotter: React.FC = ({ artifact, data, totalImages, + loadingIndex, }: DataPlotterProps) => { const [displayedImageIndex, setDisplayedImageIndex] = useState(0); @@ -53,7 +55,20 @@ export const DataPlotter: React.FC = ({ min={0} max={totalImages - 1} defaultValue={0} - onChange={(_, value: number) => setDisplayedImageIndex(value)} + onChange={(_, value: number) => { + if (loadingIndex !== null) { + if (loadingIndex < totalImages - 1 && value < loadingIndex) { + setDisplayedImageIndex(value); + } else { + // TODO: trying to display an image that hasn't yet been fetched, display some + // kind of feedback that this can't be done + } + } else { + // `loadingIndex` is null when the process of data-fetching is not occurring, + // in which case it's fine to select any image + setDisplayedImageIndex(value); + } + }} /> ); diff --git a/frontend/unified/src/components/WorkflowsDataFetcher/Plot/Plot.tsx b/frontend/unified/src/components/WorkflowsDataFetcher/Plot/Plot.tsx index fad8989c..0fe63f9a 100644 --- a/frontend/unified/src/components/WorkflowsDataFetcher/Plot/Plot.tsx +++ b/frontend/unified/src/components/WorkflowsDataFetcher/Plot/Plot.tsx @@ -5,12 +5,30 @@ import { NDT } from "@diamondlightsource/davidia"; import ndarray from "ndarray"; import { decode } from "fast-png"; import { proxyService } from "../../../../../tomography/src/api/services"; -import loadData from "../../../../../tomography/src/components/crop/SampleLoad"; import { DataPlotter } from "./DataPlotter"; import { DataLoadingProgress } from "./DataLoadingProgress"; import { Visit } from "@diamondlightsource/sci-react-ui"; import { ArtifactSelectorFragmentFragment } from "./__generated__/ArtifactSelector.generated"; +const imageIterator = ( + height: number, + width: number, + totalImages: number, + tifUrl: string, + setLoadingImageIndex: React.Dispatch> +): AsyncGenerator => { + const generator = (async function* () { + for (let i = 0; i < totalImages; i++) { + setLoadingImageIndex(i); + const pngData = await proxyService.getTiffPage(tifUrl, i, 1); + const decodedPng = decode(pngData.buffer); + yield ndarray(decodedPng.data, [height, width]) as NDT; + } + })(); + + return generator; +}; + type PlotProps = { workflowName: string | null; visit: Visit; @@ -57,10 +75,25 @@ export const Plot: React.FC = ({ return; } - loadData(url, 1, setLoadingImageIndex, setTotalImages).then((data) => { - setLoadingImageIndex(null); - setArtifactData(data); - }); + const { + page_count: pageCount, + width, + height, + } = await proxyService.getTiffMetadata(url); + setTotalImages(pageCount); + const iter = imageIterator( + height, + width, + pageCount, + url, + setLoadingImageIndex + ); + + setArtifactData([]); + for await (const image of iter) { + setArtifactData((prev) => [...prev, image]); + } + setLoadingImageIndex(null); }; if (artifact !== null) { @@ -88,22 +121,29 @@ export const Plot: React.FC = ({ const displayDataPlotterOrLoadingProgress = () => { if (isPlottingEnabled && workflowName !== null && artifact !== null) { - if (artifactData !== null && totalImages !== null) { + if ( + artifactData !== null && + artifactData.length >= 1 && + totalImages !== null + ) { return ( - + <> + + {loadingImageIndex && ( + + )} + ); } - return ( - - ); } };