fix(refboard): remove loading overlay that got stuck due to viewport culling
The asset progress overlay (e.g. "Loading assets 6/22") was incompatible with the viewport culling system — culling only loads nearby textures and unloads distant ones, so loaded count could never reach total. Simplified to a brief spinner during scene data parsing only.
This commit is contained in:
@@ -540,24 +540,6 @@ export class SceneManager {
|
|||||||
return Array.from(this.items.values());
|
return Array.from(this.items.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Count how many image/video assets have loaded textures vs total. */
|
|
||||||
getLoadProgress(): { loaded: number; total: number } {
|
|
||||||
let loaded = 0;
|
|
||||||
let total = 0;
|
|
||||||
for (const item of this.items.values()) {
|
|
||||||
if (item.type === 'image') {
|
|
||||||
total++;
|
|
||||||
const spr = item.displayObject;
|
|
||||||
if ((spr instanceof ImageSprite || spr instanceof AnimatedGifSprite) && spr.loaded) loaded++;
|
|
||||||
} else if (item.type === 'video') {
|
|
||||||
total++;
|
|
||||||
const spr = item.displayObject;
|
|
||||||
if (spr instanceof VideoSprite && (spr.hasPoster || spr.isPlaying)) loaded++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { loaded, total };
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get only top-level items (excludes group children). Used for selection/hit testing. */
|
/** Get only top-level items (excludes group children). Used for selection/hit testing. */
|
||||||
getTopLevelItems(): SceneItem[] {
|
getTopLevelItems(): SceneItem[] {
|
||||||
return Array.from(this.items.values()).filter((item) => !isGroupChild(item.id));
|
return Array.from(this.items.values()).filter((item) => !isGroupChild(item.id));
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ export default function Editor({ isPublicView }: EditorProps) {
|
|||||||
const [zoom, setZoom] = useState(1);
|
const [zoom, setZoom] = useState(1);
|
||||||
const [objectCount, setObjectCount] = useState(0);
|
const [objectCount, setObjectCount] = useState(0);
|
||||||
const [sceneLoading, setSceneLoading] = useState(true);
|
const [sceneLoading, setSceneLoading] = useState(true);
|
||||||
const [loadProgress, setLoadProgress] = useState({ loaded: 0, total: 0 });
|
|
||||||
const [saveStatus, setSaveStatus] = useState<SaveStatus>('saved');
|
const [saveStatus, setSaveStatus] = useState<SaveStatus>('saved');
|
||||||
const [onlineUsers, setOnlineUsers] = useState<OnlineUser[]>([]);
|
const [onlineUsers, setOnlineUsers] = useState<OnlineUser[]>([]);
|
||||||
const [canUndo, setCanUndo] = useState(false);
|
const [canUndo, setCanUndo] = useState(false);
|
||||||
@@ -409,20 +408,15 @@ export default function Editor({ isPublicView }: EditorProps) {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [objectCount]);
|
}, [objectCount]);
|
||||||
|
|
||||||
// Track asset load progress during initial load
|
// Track scene loading state (board data parsing, not asset textures — those are culled)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!sceneLoading && loadProgress.total > 0 && loadProgress.loaded >= loadProgress.total) return;
|
if (!sceneLoading) return;
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
const scene = canvasRef.current?.getScene();
|
|
||||||
if (!scene) return;
|
|
||||||
const progress = scene.getLoadProgress();
|
|
||||||
setLoadProgress(progress);
|
|
||||||
// Also update sceneLoading flag
|
|
||||||
const isLoading = canvasRef.current?.isSceneLoading() ?? false;
|
const isLoading = canvasRef.current?.isSceneLoading() ?? false;
|
||||||
setSceneLoading(isLoading);
|
setSceneLoading(isLoading);
|
||||||
}, 300);
|
}, 300);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [sceneLoading, loadProgress]);
|
}, [sceneLoading]);
|
||||||
|
|
||||||
// Inline composer position — tracks viewport + scene changes for anchored placement
|
// Inline composer position — tracks viewport + scene changes for anchored placement
|
||||||
const composerAnchor = draftPin ? { objectId: draftPin.objectId, pinX: draftPin.pinX, pinY: draftPin.pinY } : null;
|
const composerAnchor = draftPin ? { objectId: draftPin.objectId, pinX: draftPin.pinX, pinY: draftPin.pinY } : null;
|
||||||
@@ -1150,8 +1144,8 @@ export default function Editor({ isPublicView }: EditorProps) {
|
|||||||
canvasTransform={canvasTransform}
|
canvasTransform={canvasTransform}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Loading overlay — blocks interaction until scene is ready */}
|
{/* Loading overlay — shown only while scene data is being parsed */}
|
||||||
{(sceneLoading || (objectCount > 0 && loadProgress.total > 0 && loadProgress.loaded < loadProgress.total)) && (
|
{sceneLoading && (
|
||||||
<div style={{
|
<div style={{
|
||||||
position: 'absolute', inset: 0, zIndex: 9999,
|
position: 'absolute', inset: 0, zIndex: 9999,
|
||||||
display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
|
display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
|
||||||
@@ -1165,23 +1159,7 @@ export default function Editor({ isPublicView }: EditorProps) {
|
|||||||
animation: 'spin 0.8s linear infinite',
|
animation: 'spin 0.8s linear infinite',
|
||||||
}} />
|
}} />
|
||||||
<style>{`@keyframes spin { to { transform: rotate(360deg) } }`}</style>
|
<style>{`@keyframes spin { to { transform: rotate(360deg) } }`}</style>
|
||||||
<div style={{ fontSize: '14px', fontWeight: 500 }}>
|
<div style={{ fontSize: '14px', fontWeight: 500 }}>Loading board…</div>
|
||||||
{sceneLoading
|
|
||||||
? `Loading ${loadProgress.total || ''} items…`
|
|
||||||
: `Loading assets ${loadProgress.loaded} / ${loadProgress.total}`}
|
|
||||||
</div>
|
|
||||||
{loadProgress.total > 0 && (
|
|
||||||
<div style={{
|
|
||||||
width: '200px', height: '4px', borderRadius: '2px',
|
|
||||||
background: '#333', overflow: 'hidden',
|
|
||||||
}}>
|
|
||||||
<div style={{
|
|
||||||
width: `${Math.round((loadProgress.loaded / loadProgress.total) * 100)}%`,
|
|
||||||
height: '100%', background: '#4a9eff', borderRadius: '2px',
|
|
||||||
transition: 'width 0.3s ease',
|
|
||||||
}} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{objectCount === 0 && !sceneLoading && (
|
{objectCount === 0 && !sceneLoading && (
|
||||||
|
|||||||
Reference in New Issue
Block a user