diff --git a/src/components/LoadingOverlay.js b/src/components/LoadingOverlay.js index f6a30be..8cc4b9e 100644 --- a/src/components/LoadingOverlay.js +++ b/src/components/LoadingOverlay.js @@ -1,9 +1,9 @@ import React from "react"; -import { Box, Progress } from "theme-ui"; +import { Box } from "theme-ui"; import Spinner from "./Spinner"; -function LoadingOverlay({ progress }) { +function LoadingOverlay() { return ( - {progress && ( - - )} ); } diff --git a/src/components/map/Map.js b/src/components/map/Map.js index 198f826..56ae6a1 100644 --- a/src/components/map/Map.js +++ b/src/components/map/Map.js @@ -8,13 +8,12 @@ import MapFog from "./MapFog"; import MapDice from "./MapDice"; import MapGrid from "./MapGrid"; import MapMeasure from "./MapMeasure"; +import MapLoadingOverlay from "./MapLoadingOverlay"; import TokenDataContext from "../../contexts/TokenDataContext"; -import MapLoadingContext from "../../contexts/MapLoadingContext"; import TokenMenu from "../token/TokenMenu"; import TokenDragOverlay from "../token/TokenDragOverlay"; -import LoadingOverlay from "../LoadingOverlay"; import { drawActionsToShapes } from "../../helpers/drawing"; @@ -36,7 +35,6 @@ function Map({ disabledTokens, }) { const { tokensById } = useContext(TokenDataContext); - const { isLoading, loadingProgress } = useContext(MapLoadingContext); const gridX = map && map.gridX; const gridY = map && map.gridY; @@ -299,7 +297,7 @@ function Map({ {tokenMenu} {tokenDragOverlay} - {isLoading && } + } selectedToolId={selectedToolId} diff --git a/src/components/map/MapLoadingOverlay.js b/src/components/map/MapLoadingOverlay.js new file mode 100644 index 0000000..93d5fed --- /dev/null +++ b/src/components/map/MapLoadingOverlay.js @@ -0,0 +1,61 @@ +import React, { useContext, useEffect, useRef } from "react"; +import { Box, Progress } from "theme-ui"; + +import Spinner from "../Spinner"; +import MapLoadingContext from "../../contexts/MapLoadingContext"; + +function MapLoadingOverlay() { + const { isLoading, loadingProgressRef } = useContext(MapLoadingContext); + + const requestRef = useRef(); + const progressBarRef = useRef(); + + // Use an animation frame to update the progress bar + // This bypasses react allowing the animation to be smooth + useEffect(() => { + function animate() { + if (!isLoading) { + return; + } + requestRef.current = requestAnimationFrame(animate); + progressBarRef.current.value = loadingProgressRef.current; + } + + requestRef.current = requestAnimationFrame(animate); + + return () => { + cancelAnimationFrame(requestRef.current); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isLoading]); + + return ( + isLoading && ( + + + + + ) + ); +} + +export default MapLoadingOverlay; diff --git a/src/contexts/MapLoadingContext.js b/src/contexts/MapLoadingContext.js index 12f0f4a..e413a09 100644 --- a/src/contexts/MapLoadingContext.js +++ b/src/contexts/MapLoadingContext.js @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useRef } from "react"; import { omit, isEmpty } from "../helpers/shared"; const MapLoadingContext = React.createContext(); @@ -14,36 +14,36 @@ export function MapLoadingProvider({ children }) { setLoadingAssetCount((prevLoadingAssets) => prevLoadingAssets - 1); } - const [assetProgress, setAssetProgress] = useState({}); + const assetProgressRef = useRef({}); + const loadingProgressRef = useRef(null); function assetProgressUpdate({ id, count, total }) { if (count === total) { - setAssetProgress(omit(assetProgress, [id])); + assetProgressRef.current = omit(assetProgressRef.current, [id]); } else { - setAssetProgress((prevAssetProgress) => ({ - ...prevAssetProgress, + assetProgressRef.current = { + ...assetProgressRef.current, [id]: { count, total }, - })); + }; + } + if (!isEmpty(assetProgressRef.current)) { + let total = 0; + let count = 0; + for (let progress of Object.values(assetProgressRef.current)) { + total += progress.total; + count += progress.count; + } + loadingProgressRef.current = count / total; } } const isLoading = loadingAssetCount > 0; - let loadingProgress = null; - if (!isEmpty(assetProgress)) { - let total = 0; - let count = 0; - for (let progress of Object.values(assetProgress)) { - total += progress.total; - count += progress.count; - } - loadingProgress = count / total; - } const value = { assetLoadStart, assetLoadFinish, isLoading, assetProgressUpdate, - loadingProgress, + loadingProgressRef, }; return (