Throttle canvas rendering for large rooms; cap displayed size and use DPR scaling
This commit is contained in:
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>furniture-app</title>
|
||||
<script type="module" crossorigin src="/assets/index-z6fd8Sn7.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BIL7D6zM.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-9k24Ci9h.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -308,11 +308,23 @@ export function ControlPanel({
|
||||
<div className="grid-2">
|
||||
<label className="field">
|
||||
<span>Width</span>
|
||||
<NumberField value={state.room.width} min={100} width="100%" onChange={(v) => setRoom({ width: v })} />
|
||||
<NumberField
|
||||
value={state.room.width}
|
||||
min={100}
|
||||
max={5000}
|
||||
width="100%"
|
||||
onChange={(v) => setRoom({ width: v })}
|
||||
/>
|
||||
</label>
|
||||
<label className="field">
|
||||
<span>Height</span>
|
||||
<NumberField value={state.room.height} min={100} width="100%" onChange={(v) => setRoom({ height: v })} />
|
||||
<NumberField
|
||||
value={state.room.height}
|
||||
min={100}
|
||||
max={5000}
|
||||
width="100%"
|
||||
onChange={(v) => setRoom({ height: v })}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -33,6 +33,38 @@ export function RoomCanvas({ state, onStateChange, mode, selectedId, onSelect, s
|
||||
return () => clearInterval(t);
|
||||
}, [showPaths]);
|
||||
|
||||
const [viewport, setViewport] = useState({ width: 1200, height: 800 });
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const resize = () => {
|
||||
if (containerRef.current) {
|
||||
setViewport({
|
||||
width: Math.floor(containerRef.current.clientWidth),
|
||||
height: Math.floor(containerRef.current.clientHeight),
|
||||
});
|
||||
}
|
||||
};
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
return () => window.removeEventListener('resize', resize);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const dpr = Math.max(1, window.devicePixelRatio || 1);
|
||||
const baseW = Math.min(state.room.width, viewport.width || state.room.width);
|
||||
const baseH = Math.min(state.room.height, viewport.height || state.room.height);
|
||||
canvas.style.width = `${baseW}px`;
|
||||
canvas.style.height = `${baseH}px`;
|
||||
canvas.width = baseW * dpr;
|
||||
canvas.height = baseH * dpr;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (ctx) ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
draw();
|
||||
}, [state.room.width, state.room.height, zoom, viewport]);
|
||||
|
||||
useEffect(() => {
|
||||
draw();
|
||||
}, [state, selectedId, mode, zoom, showPaths, phase]);
|
||||
@@ -42,9 +74,14 @@ export function RoomCanvas({ state, onStateChange, mode, selectedId, onSelect, s
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
const dpr = Math.max(1, window.devicePixelRatio || 1);
|
||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
ctx.clearRect(0, 0, canvas.width / dpr, canvas.height / dpr);
|
||||
ctx.save();
|
||||
ctx.scale(zoom, zoom);
|
||||
const scaleX = (canvas.width / dpr) / state.room.width;
|
||||
const scaleY = (canvas.height / dpr) / state.room.height;
|
||||
const s = Math.min(scaleX, scaleY);
|
||||
ctx.scale(s, s);
|
||||
|
||||
ctx.fillStyle = '#12151b';
|
||||
ctx.fillRect(0, 0, state.room.width, state.room.height);
|
||||
@@ -308,17 +345,19 @@ export function RoomCanvas({ state, onStateChange, mode, selectedId, onSelect, s
|
||||
};
|
||||
|
||||
return (
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
width={Math.max(state.room.width, 400)}
|
||||
height={Math.max(state.room.height, 300)}
|
||||
style={{ maxWidth: '100%', height: 'auto' }}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseUp={handleMouseUp}
|
||||
onDragOver={handleDragOver}
|
||||
onDrop={handleDrop}
|
||||
/>
|
||||
<div ref={containerRef} style={{ width: '100%', height: '100%' }}>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
width={Math.min(state.room.width, 2000)}
|
||||
height={Math.min(state.room.height, 2000)}
|
||||
style={{ maxWidth: '100%', maxHeight: '100%', width: '100%', height: '100%', objectFit: 'contain' }}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseUp={handleMouseUp}
|
||||
onDragOver={handleDragOver}
|
||||
onDrop={handleDrop}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user