Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## 2024-08-02 - Canvas Optimization

**Learning:** Re-assigning canvas dimensions (`canvas.width = canvas.width`) forces the browser to re-allocate the underlying graphics buffer and clear the canvas, which is an expensive operation that can cause layout thrashing. This is a common performance bottleneck in canvas-heavy React components like `PreviewCanvas.tsx` when re-rendering based on user interaction (like mouse moves or drawing annotations).
**Action:** When updating canvas dimensions within a `useCallback` or `useEffect` render pipeline, conditionally set them only if they have actually changed (`if (canvas.width !== targetW) canvas.width = targetW`). Since avoiding dimension re-assignment stops the implicit clear, explicitly call `clearRect` when the dimensions remain the same to prevent visual ghosting/artifacts.
28 changes: 20 additions & 8 deletions src/components/PreviewCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,14 @@ export const PreviewCanvas: React.FC<PreviewCanvasProps> = ({
}
}

if (direction === 'vertical') {
baseCanvas.width = totalW;
baseCanvas.height = totalH;
} else {
baseCanvas.width = totalH;
baseCanvas.height = baseW;
const targetW = direction === 'vertical' ? totalW : totalH;
const targetH = direction === 'vertical' ? totalH : baseW;
Comment on lines +327 to +328

if (baseCanvas.width !== targetW) {
baseCanvas.width = targetW;
}
if (baseCanvas.height !== targetH) {
baseCanvas.height = targetH;
}

// Clean canvas
Expand Down Expand Up @@ -512,10 +514,20 @@ export const PreviewCanvas: React.FC<PreviewCanvasProps> = ({
if (shouldShowMockup) {
drawMockup(canvasRef.current, baseStitchedCanvas, mockup);
} else {
canvasRef.current.width = baseStitchedCanvas.width;
canvasRef.current.height = baseStitchedCanvas.height;
let resized = false;
if (canvasRef.current.width !== baseStitchedCanvas.width) {
canvasRef.current.width = baseStitchedCanvas.width;
resized = true;
}
if (canvasRef.current.height !== baseStitchedCanvas.height) {
canvasRef.current.height = baseStitchedCanvas.height;
resized = true;
}
const ctx = canvasRef.current.getContext('2d');
if (ctx) {
if (!resized) {
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
}
ctx.drawImage(baseStitchedCanvas, 0, 0);
}
}
Expand Down