From 1622d81da1f3a14f7abcfa7be5e000300a45f42e Mon Sep 17 00:00:00 2001 From: TeunHuijben Date: Fri, 13 Sep 2024 15:13:28 -0700 Subject: [PATCH 1/4] loading dialog stays untill all tracks are rendered --- src/components/App.tsx | 192 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 172 insertions(+), 20 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index e5961c21..80dc1a5a 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -149,41 +149,193 @@ export default function App() { }; }, [canvas.curTime, dispatchCanvas, trackManager]); + + + + // This fetches track IDs based on the selected point IDs. + // useEffect(() => { + // console.debug("effect-selectedPointIds: ", trackManager, canvas.selectedPointIds); + // if (!trackManager) return; + // if (canvas.selectedPointIds.size == 0) return; + + // // this fetches the entire lineage for each track + // const updateTracks = async () => { + // console.debug("updateTracks: ", canvas.selectedPointIds); + + // // Store promises for fetching all tracks and lineages + // const allTrackPromises: Promise[] = []; + + // canvas.selectedPointIds.forEach(async (pointId) => { + // if (canvas.fetchedPointIds.has(pointId)) return; // Skip already fetched + + // setNumLoadingTracks((n) => n + 1); + // canvas.fetchedPointIds.add(pointId); + + // const trackPromise = trackManager.fetchTrackIDsForPoint(pointId).then(async (trackIds) => { + + // // TODO: points actually only belong to one track, so can get rid of the outer loop + // for (const trackId of trackIds) { + // if (canvas.fetchedRootTrackIds.has(trackId)) continue; + + // canvas.fetchedRootTrackIds.add(trackId); + + // const lineagePromise = trackManager.fetchLineageForTrack(trackId).then(async ([lineage, trackData]) => { + // // Process each related track ID in the lineage + // for (const [index, relatedTrackId] of lineage.entries()) { + // if (canvas.tracks.has(relatedTrackId)) return; + + // const pointsPromise = trackManager.fetchPointsForTrack(relatedTrackId).then(([pos, ids]) => { + // // adding the track *in* the dispatcher creates issues with duplicate fetching + // // but we refresh so the selected/loaded count is updated + // canvas.addTrack(relatedTrackId, pos, ids, trackData[index]); + // dispatchCanvas({ type: ActionType.REFRESH }); + + // canvas.renderer.render(canvas.scene, canvas.camera); + // }); + + // await pointsPromise; + // } + // }); + + // await lineagePromise; + // } + // }); + + // // Add the track fetching promise to the promises array + // allTrackPromises.push(trackPromise); + + // // Decrement the loading count once fetching is complete + // trackPromise.finally(() => { + // setNumLoadingTracks((n) => n - 1); + // }); + // }); + + // // Wait for all tracks and lineages to be fetched and added to the canvas + // await Promise.all(allTrackPromises); + + // // Final render and check loop to confirm everything is rendered + // const ensureFinalRender = () => { + // const maxRenderFrames = 5; + // let renderAttempts = 0; + + // const checkRender = () => { + // // Trigger manual render + // canvas.renderer.render(canvas.scene, canvas.camera); + + // renderAttempts += 1; + + // if (renderAttempts >= maxRenderFrames) { + // console.log("All tracks have been rendered on the canvas"); + // } else { + // // Continue rendering and checking in the next frame + // requestAnimationFrame(checkRender); + // } + // }; + + // // Start the render-check loop + // requestAnimationFrame(checkRender); + // }; + + // ensureFinalRender(); + // }; + + // updateTracks(); + // // TODO: add missing dependencies + // }, [trackManager, dispatchCanvas, canvas.selectedPointIds]); + useEffect(() => { console.debug("effect-selectedPointIds: ", trackManager, canvas.selectedPointIds); if (!trackManager) return; - if (canvas.selectedPointIds.size == 0) return; + if (canvas.selectedPointIds.size === 0) return; - // this fetches the entire lineage for each track const updateTracks = async () => { console.debug("updateTracks: ", canvas.selectedPointIds); - canvas.selectedPointIds.forEach(async (pointId) => { - if (canvas.fetchedPointIds.has(pointId)) return; + + // Store promises for fetching all tracks and lineages + const allTrackPromises: Promise[] = []; + + canvas.selectedPointIds.forEach((pointId) => { + if (canvas.fetchedPointIds.has(pointId)) return; // Skip already fetched + setNumLoadingTracks((n) => n + 1); canvas.fetchedPointIds.add(pointId); - const trackIds = await trackManager.fetchTrackIDsForPoint(pointId); - // TODO: points actually only belong to one track, so can get rid of the outer loop - trackIds.forEach(async (trackId) => { - if (canvas.fetchedRootTrackIds.has(trackId)) return; - canvas.fetchedRootTrackIds.add(trackId); - const [lineage, trackData] = await trackManager.fetchLineageForTrack(trackId); - lineage.forEach(async (relatedTrackId: number, index) => { - if (canvas.tracks.has(relatedTrackId)) return; - const [pos, ids] = await trackManager.fetchPointsForTrack(relatedTrackId); - // adding the track *in* the dispatcher creates issues with duplicate fetching - // but we refresh so the selected/loaded count is updated - canvas.addTrack(relatedTrackId, pos, ids, trackData[index]); - dispatchCanvas({ type: ActionType.REFRESH }); - }); + + const trackPromise = trackManager.fetchTrackIDsForPoint(pointId).then(async (trackIds) => { + // Use for...of for async operations while maintaining parallelism + const lineagePromises: Promise[] = []; + + for (const trackId of trackIds) { + if (canvas.fetchedRootTrackIds.has(trackId)) continue; + + canvas.fetchedRootTrackIds.add(trackId); + + const lineagePromise = trackManager.fetchLineageForTrack(trackId).then(async ([lineage, trackData]) => { + const relatedTrackPromises: Promise[] = []; + + for (const [index, relatedTrackId] of lineage.entries()) { + if (canvas.tracks.has(relatedTrackId)) continue; + + const pointsPromise = trackManager.fetchPointsForTrack(relatedTrackId).then(([pos, ids]) => { + canvas.addTrack(relatedTrackId, pos, ids, trackData[index]); + dispatchCanvas({ type: ActionType.REFRESH }); + }); + + relatedTrackPromises.push(pointsPromise); + } + + // Wait for all related tracks to be fetched and rendered in parallel + await Promise.all(relatedTrackPromises); + }); + + lineagePromises.push(lineagePromise); + } + + // Wait for all lineages to be fetched and processed in parallel + await Promise.all(lineagePromises); + }); + + // Add the track fetching promise to the promises array + allTrackPromises.push(trackPromise); + + // Decrement the loading count once fetching is complete + trackPromise.finally(() => { + setNumLoadingTracks((n) => n - 1); }); - setNumLoadingTracks((n) => n - 1); }); + + // Wait for all tracks and lineages to be fetched in parallel + await Promise.all(allTrackPromises); + + // Final render and check loop to confirm everything is rendered + const ensureFinalRender = () => { + const maxRenderFrames = 5; + let renderAttempts = 0; + + const checkRender = () => { + renderAttempts += 1; + + if (renderAttempts >= maxRenderFrames) { + console.log("All tracks have been rendered on the canvas"); + } else { + // Continue rendering and checking in the next frame + requestAnimationFrame(checkRender); + } + }; + + // Start the render-check loop + requestAnimationFrame(checkRender); + }; + + ensureFinalRender(); }; + updateTracks(); - // TODO: add missing dependencies + }, [trackManager, dispatchCanvas, canvas.selectedPointIds]); + + // playback time points // TODO: this is basic and may drop frames useEffect(() => { From c42a6588ea558d2a2b5a528a32dffdb94d596d02 Mon Sep 17 00:00:00 2001 From: TeunHuijben Date: Fri, 13 Sep 2024 15:22:20 -0700 Subject: [PATCH 2/4] removed unneccessary parts --- src/components/App.tsx | 117 +---------------------------------------- 1 file changed, 1 insertion(+), 116 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 80dc1a5a..38ba75ba 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -150,100 +150,6 @@ export default function App() { }, [canvas.curTime, dispatchCanvas, trackManager]); - - - - // This fetches track IDs based on the selected point IDs. - // useEffect(() => { - // console.debug("effect-selectedPointIds: ", trackManager, canvas.selectedPointIds); - // if (!trackManager) return; - // if (canvas.selectedPointIds.size == 0) return; - - // // this fetches the entire lineage for each track - // const updateTracks = async () => { - // console.debug("updateTracks: ", canvas.selectedPointIds); - - // // Store promises for fetching all tracks and lineages - // const allTrackPromises: Promise[] = []; - - // canvas.selectedPointIds.forEach(async (pointId) => { - // if (canvas.fetchedPointIds.has(pointId)) return; // Skip already fetched - - // setNumLoadingTracks((n) => n + 1); - // canvas.fetchedPointIds.add(pointId); - - // const trackPromise = trackManager.fetchTrackIDsForPoint(pointId).then(async (trackIds) => { - - // // TODO: points actually only belong to one track, so can get rid of the outer loop - // for (const trackId of trackIds) { - // if (canvas.fetchedRootTrackIds.has(trackId)) continue; - - // canvas.fetchedRootTrackIds.add(trackId); - - // const lineagePromise = trackManager.fetchLineageForTrack(trackId).then(async ([lineage, trackData]) => { - // // Process each related track ID in the lineage - // for (const [index, relatedTrackId] of lineage.entries()) { - // if (canvas.tracks.has(relatedTrackId)) return; - - // const pointsPromise = trackManager.fetchPointsForTrack(relatedTrackId).then(([pos, ids]) => { - // // adding the track *in* the dispatcher creates issues with duplicate fetching - // // but we refresh so the selected/loaded count is updated - // canvas.addTrack(relatedTrackId, pos, ids, trackData[index]); - // dispatchCanvas({ type: ActionType.REFRESH }); - - // canvas.renderer.render(canvas.scene, canvas.camera); - // }); - - // await pointsPromise; - // } - // }); - - // await lineagePromise; - // } - // }); - - // // Add the track fetching promise to the promises array - // allTrackPromises.push(trackPromise); - - // // Decrement the loading count once fetching is complete - // trackPromise.finally(() => { - // setNumLoadingTracks((n) => n - 1); - // }); - // }); - - // // Wait for all tracks and lineages to be fetched and added to the canvas - // await Promise.all(allTrackPromises); - - // // Final render and check loop to confirm everything is rendered - // const ensureFinalRender = () => { - // const maxRenderFrames = 5; - // let renderAttempts = 0; - - // const checkRender = () => { - // // Trigger manual render - // canvas.renderer.render(canvas.scene, canvas.camera); - - // renderAttempts += 1; - - // if (renderAttempts >= maxRenderFrames) { - // console.log("All tracks have been rendered on the canvas"); - // } else { - // // Continue rendering and checking in the next frame - // requestAnimationFrame(checkRender); - // } - // }; - - // // Start the render-check loop - // requestAnimationFrame(checkRender); - // }; - - // ensureFinalRender(); - // }; - - // updateTracks(); - // // TODO: add missing dependencies - // }, [trackManager, dispatchCanvas, canvas.selectedPointIds]); - useEffect(() => { console.debug("effect-selectedPointIds: ", trackManager, canvas.selectedPointIds); if (!trackManager) return; @@ -306,28 +212,7 @@ export default function App() { // Wait for all tracks and lineages to be fetched in parallel await Promise.all(allTrackPromises); - - // Final render and check loop to confirm everything is rendered - const ensureFinalRender = () => { - const maxRenderFrames = 5; - let renderAttempts = 0; - - const checkRender = () => { - renderAttempts += 1; - - if (renderAttempts >= maxRenderFrames) { - console.log("All tracks have been rendered on the canvas"); - } else { - // Continue rendering and checking in the next frame - requestAnimationFrame(checkRender); - } - }; - - // Start the render-check loop - requestAnimationFrame(checkRender); - }; - - ensureFinalRender(); + console.log("All tracks have been rendered on the canvas"); }; updateTracks(); From f3af62a6f03df5d6e72fdf15d4dc6589847072a9 Mon Sep 17 00:00:00 2001 From: TeunHuijben Date: Fri, 13 Sep 2024 15:24:17 -0700 Subject: [PATCH 3/4] lint fixes --- src/components/App.tsx | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 38ba75ba..d1972b40 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -149,7 +149,6 @@ export default function App() { }; }, [canvas.curTime, dispatchCanvas, trackManager]); - useEffect(() => { console.debug("effect-selectedPointIds: ", trackManager, canvas.selectedPointIds); if (!trackManager) return; @@ -162,7 +161,7 @@ export default function App() { const allTrackPromises: Promise[] = []; canvas.selectedPointIds.forEach((pointId) => { - if (canvas.fetchedPointIds.has(pointId)) return; // Skip already fetched + if (canvas.fetchedPointIds.has(pointId)) return; // Skip already fetched setNumLoadingTracks((n) => n + 1); canvas.fetchedPointIds.add(pointId); @@ -176,23 +175,27 @@ export default function App() { canvas.fetchedRootTrackIds.add(trackId); - const lineagePromise = trackManager.fetchLineageForTrack(trackId).then(async ([lineage, trackData]) => { - const relatedTrackPromises: Promise[] = []; + const lineagePromise = trackManager + .fetchLineageForTrack(trackId) + .then(async ([lineage, trackData]) => { + const relatedTrackPromises: Promise[] = []; - for (const [index, relatedTrackId] of lineage.entries()) { - if (canvas.tracks.has(relatedTrackId)) continue; + for (const [index, relatedTrackId] of lineage.entries()) { + if (canvas.tracks.has(relatedTrackId)) continue; - const pointsPromise = trackManager.fetchPointsForTrack(relatedTrackId).then(([pos, ids]) => { - canvas.addTrack(relatedTrackId, pos, ids, trackData[index]); - dispatchCanvas({ type: ActionType.REFRESH }); - }); + const pointsPromise = trackManager + .fetchPointsForTrack(relatedTrackId) + .then(([pos, ids]) => { + canvas.addTrack(relatedTrackId, pos, ids, trackData[index]); + dispatchCanvas({ type: ActionType.REFRESH }); + }); - relatedTrackPromises.push(pointsPromise); - } + relatedTrackPromises.push(pointsPromise); + } - // Wait for all related tracks to be fetched and rendered in parallel - await Promise.all(relatedTrackPromises); - }); + // Wait for all related tracks to be fetched and rendered in parallel + await Promise.all(relatedTrackPromises); + }); lineagePromises.push(lineagePromise); } @@ -216,11 +219,8 @@ export default function App() { }; updateTracks(); - }, [trackManager, dispatchCanvas, canvas.selectedPointIds]); - - // playback time points // TODO: this is basic and may drop frames useEffect(() => { From a7f7ae8b38db28e1548e4e9ed19631d4976b92f7 Mon Sep 17 00:00:00 2001 From: TeunHuijben Date: Fri, 4 Oct 2024 17:34:02 -0700 Subject: [PATCH 4/4] replaced Promise.all by Promise.allSettled --- src/components/App.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 1de0c310..4ada7452 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -194,14 +194,14 @@ export default function App() { } // Wait for all related tracks to be fetched and rendered in parallel - await Promise.all(relatedTrackPromises); + await Promise.allSettled(relatedTrackPromises); }); lineagePromises.push(lineagePromise); } // Wait for all lineages to be fetched and processed in parallel - await Promise.all(lineagePromises); + await Promise.allSettled(lineagePromises); }); // Add the track fetching promise to the promises array @@ -214,7 +214,7 @@ export default function App() { }); // Wait for all tracks and lineages to be fetched in parallel - await Promise.all(allTrackPromises); + await Promise.allSettled(allTrackPromises); console.log("All tracks have been rendered on the canvas"); };