Moved map asset loading progress to use refs to stop re-renders
Moved map loading overlay to use animation frames for a smooth progress bar
This commit is contained in:
parent
bf022e2686
commit
a81031e84e
@ -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 (
|
||||
<Box
|
||||
sx={{
|
||||
@ -20,9 +20,6 @@ function LoadingOverlay({ progress }) {
|
||||
bg="muted"
|
||||
>
|
||||
<Spinner />
|
||||
{progress && (
|
||||
<Progress max={1} value={progress} m={2} sx={{ width: "24px" }} />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
@ -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}
|
||||
<MapDice />
|
||||
{isLoading && <LoadingOverlay progress={loadingProgress} />}
|
||||
<MapLoadingOverlay />
|
||||
</>
|
||||
}
|
||||
selectedToolId={selectedToolId}
|
||||
|
61
src/components/map/MapLoadingOverlay.js
Normal file
61
src/components/map/MapLoadingOverlay.js
Normal file
@ -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 && (
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
top: 0,
|
||||
left: 0,
|
||||
flexDirection: "column",
|
||||
}}
|
||||
bg="muted"
|
||||
>
|
||||
<Spinner />
|
||||
<Progress
|
||||
ref={progressBarRef}
|
||||
max={1}
|
||||
value={0}
|
||||
m={2}
|
||||
sx={{ width: "32px" }}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default MapLoadingOverlay;
|
@ -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 (
|
||||
|
Loading…
Reference in New Issue
Block a user