Skip to content

Commit

Permalink
Display LoadingIndicator when fetching points data (#29)
Browse files Browse the repository at this point in the history
rebased on main
  • Loading branch information
aganders3 authored Feb 22, 2024
1 parent 8c5f8aa commit 6f82274
Showing 1 changed file with 56 additions and 45 deletions.
101 changes: 56 additions & 45 deletions src/scene.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from "react";
import { Button, InputSlider, InputText, InputToggle } from "@czi-sds/components";
import { Button, InputSlider, InputText, InputToggle, LoadingIndicator } from "@czi-sds/components";
import { PointCanvas } from "./PointCanvas";
import { TrackManager, loadTrackManager } from "./TrackManager";

Expand All @@ -26,6 +26,7 @@ export default function Scene(props: SceneProps) {
const [curTime, setCurTime] = useState(0);
const [autoRotate, setAutoRotate] = useState(false);
const [playing, setPlaying] = useState(false);
const [loading, setLoading] = useState(false);

// Use references here for two things:
// * manage objects that should never change, even when the component re-renders
Expand Down Expand Up @@ -113,6 +114,8 @@ export default function Scene(props: SceneProps) {
// update the points when the array or timepoint changes
useEffect(() => {
setSelectedPoints({});
// show a loading indicator if the fetch takes longer than 10ms (avoid flicker)
const loadingTimer = setTimeout(() => setLoading(true), 10);
let ignore = false;
// TODO: this is a very basic attempt to prevent stale data
// in addition, we should debounce the input and verify the data is current
Expand All @@ -127,12 +130,17 @@ export default function Scene(props: SceneProps) {
console.debug("IGNORE SET points at time %d", curTime);
return;
}
clearTimeout(loadingTimer);
setLoading(false);
canvas.current?.setPointsPositions(data);
});
} else {
clearTimeout(loadingTimer);
setLoading(false);
console.debug("IGNORE FETCH points at time %d", curTime);
}
return () => {
clearTimeout(loadingTimer);
ignore = true;
};
}, [trackManager, curTime]);
Expand All @@ -150,55 +158,58 @@ export default function Scene(props: SceneProps) {
marks.push({ value: numTimes - 1, label: numTimes - 1 });

return (
<div ref={divRef}>
<div className="inputcontainer">
<InputText
id="url-input"
label="Zarr URL"
placeholder={DEFAULT_ZARR_URL.toString()}
value={dataUrl.toString()}
onChange={(e) => setDataUrl(new URL(e.target.value))}
fullWidth={true}
intent={trackManager ? "default" : "error"}
/>
<InputSlider
id="time-frame-slider"
aria-labelledby="input-slider-time-frame"
disabled={trackManager === undefined}
min={0}
max={numTimes - 1}
valueLabelDisplay="on"
onChange={(_, value) => setCurTime(value as number)}
marks={marks}
value={curTime}
/>
<div className="buttoncontainer">
<InputToggle
onLabel="Spin"
offLabel="Spin"
disabled={trackManager === undefined}
onChange={(e) => {
setAutoRotate((e.target as HTMLInputElement).checked);
}}
<div>
<div ref={divRef}>
<div className="inputcontainer">
<InputText
id="url-input"
label="Zarr URL"
placeholder={DEFAULT_ZARR_URL.toString()}
value={dataUrl.toString()}
onChange={(e) => setDataUrl(new URL(e.target.value))}
fullWidth={true}
intent={trackManager ? "default" : "error"}
/>
<InputToggle
onLabel="Play"
offLabel="Play"
<InputSlider
id="time-frame-slider"
aria-labelledby="input-slider-time-frame"
disabled={trackManager === undefined}
onChange={(e) => {
setPlaying((e.target as HTMLInputElement).checked);
}}
min={0}
max={numTimes - 1}
valueLabelDisplay="on"
onChange={(_, value) => setCurTime(value as number)}
marks={marks}
value={curTime}
/>
<Button
disabled={trackManager === undefined}
sdsType="primary"
sdsStyle="rounded"
onClick={() => canvas.current?.removeAllTracks()}
>
Clear Tracks
</Button>
<div className="buttoncontainer">
<InputToggle
onLabel="Spin"
offLabel="Spin"
disabled={trackManager === undefined}
onChange={(e) => {
setAutoRotate((e.target as HTMLInputElement).checked);
}}
/>
<InputToggle
onLabel="Play"
offLabel="Play"
disabled={trackManager === undefined}
onChange={(e) => {
setPlaying((e.target as HTMLInputElement).checked);
}}
/>
<Button
disabled={trackManager === undefined}
sdsType="primary"
sdsStyle="rounded"
onClick={() => canvas.current?.removeAllTracks()}
>
Clear Tracks
</Button>
</div>
</div>
</div>
{loading && <LoadingIndicator sdsStyle="minimal" />}
</div>
);
}

0 comments on commit 6f82274

Please sign in to comment.