Skip to content

Commit 9c18497

Browse files
committed
Fix issue where templates get cut
1 parent d1f35c5 commit 9c18497

1 file changed

Lines changed: 58 additions & 32 deletions

File tree

frontend/src/components/Canvas.js

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,57 +1521,64 @@ function Canvas({
15211521
// This avoids async rendering issues with image stamps
15221522
const stampsToRender = [];
15231523

1524-
// Render template objects as semi-transparent background
1524+
// Create and render template layer separately so it stays below all drawings
1525+
let templateCanvas = null;
15251526
if (currentTemplateObjects && currentTemplateObjects.length > 0) {
1526-
offscreenContext.save();
1527-
offscreenContext.globalAlpha = 0.5;
1527+
templateCanvas = document.createElement('canvas');
1528+
templateCanvas.width = canvasWidth;
1529+
templateCanvas.height = canvasHeight;
1530+
const templateContext = templateCanvas.getContext('2d');
1531+
templateContext.imageSmoothingEnabled = false;
1532+
1533+
templateContext.save();
1534+
templateContext.globalAlpha = 0.5;
15281535

15291536
let renderedCount = 0;
15301537
for (const obj of currentTemplateObjects) {
15311538
try {
15321539
if (obj.type === 'line') {
1533-
offscreenContext.beginPath();
1534-
offscreenContext.moveTo(obj.x1, obj.y1);
1535-
offscreenContext.lineTo(obj.x2, obj.y2);
1536-
offscreenContext.strokeStyle = obj.color || '#333';
1537-
offscreenContext.lineWidth = obj.lineWidth || 2;
1538-
offscreenContext.stroke();
1540+
templateContext.beginPath();
1541+
templateContext.moveTo(obj.x1, obj.y1);
1542+
templateContext.lineTo(obj.x2, obj.y2);
1543+
templateContext.strokeStyle = obj.color || '#333';
1544+
templateContext.lineWidth = obj.lineWidth || 2;
1545+
templateContext.stroke();
15391546
renderedCount++;
15401547
} else if (obj.type === 'rectangle') {
1541-
offscreenContext.strokeStyle = obj.stroke || '#333';
1542-
offscreenContext.lineWidth = obj.lineWidth || 2;
1548+
templateContext.strokeStyle = obj.stroke || '#333';
1549+
templateContext.lineWidth = obj.lineWidth || 2;
15431550
if (obj.fill && obj.fill !== 'transparent') {
1544-
offscreenContext.fillStyle = obj.fill;
1545-
offscreenContext.fillRect(obj.x, obj.y, obj.width, obj.height);
1551+
templateContext.fillStyle = obj.fill;
1552+
templateContext.fillRect(obj.x, obj.y, obj.width, obj.height);
15461553
}
1547-
offscreenContext.strokeRect(obj.x, obj.y, obj.width, obj.height);
1554+
templateContext.strokeRect(obj.x, obj.y, obj.width, obj.height);
15481555
renderedCount++;
15491556
} else if (obj.type === 'circle') {
1550-
offscreenContext.beginPath();
1551-
offscreenContext.arc(obj.cx, obj.cy, obj.radius, 0, Math.PI * 2);
1552-
offscreenContext.strokeStyle = obj.stroke || '#333';
1553-
offscreenContext.lineWidth = obj.lineWidth || 2;
1557+
templateContext.beginPath();
1558+
templateContext.arc(obj.cx, obj.cy, obj.radius, 0, Math.PI * 2);
1559+
templateContext.strokeStyle = obj.stroke || '#333';
1560+
templateContext.lineWidth = obj.lineWidth || 2;
15541561
if (obj.fill && obj.fill !== 'transparent') {
1555-
offscreenContext.fillStyle = obj.fill;
1556-
offscreenContext.fill();
1562+
templateContext.fillStyle = obj.fill;
1563+
templateContext.fill();
15571564
}
1558-
offscreenContext.stroke();
1565+
templateContext.stroke();
15591566
renderedCount++;
15601567
} else if (obj.type === 'ellipse') {
1561-
offscreenContext.beginPath();
1562-
offscreenContext.ellipse(obj.cx, obj.cy, obj.rx, obj.ry, 0, 0, Math.PI * 2);
1563-
offscreenContext.strokeStyle = obj.stroke || '#333';
1564-
offscreenContext.lineWidth = obj.lineWidth || 2;
1568+
templateContext.beginPath();
1569+
templateContext.ellipse(obj.cx, obj.cy, obj.rx, obj.ry, 0, 0, Math.PI * 2);
1570+
templateContext.strokeStyle = obj.stroke || '#333';
1571+
templateContext.lineWidth = obj.lineWidth || 2;
15651572
if (obj.fill && obj.fill !== 'transparent') {
1566-
offscreenContext.fillStyle = obj.fill;
1567-
offscreenContext.fill();
1573+
templateContext.fillStyle = obj.fill;
1574+
templateContext.fill();
15681575
}
1569-
offscreenContext.stroke();
1576+
templateContext.stroke();
15701577
renderedCount++;
15711578
} else if (obj.type === 'text') {
1572-
offscreenContext.fillStyle = obj.color || '#333';
1573-
offscreenContext.font = `${obj.bold ? 'bold ' : ''}${obj.fontSize || 16}px Arial`;
1574-
offscreenContext.fillText(obj.text || '', obj.x, obj.y);
1579+
templateContext.fillStyle = obj.color || '#333';
1580+
templateContext.font = `${obj.bold ? 'bold ' : ''}${obj.fontSize || 16}px Arial`;
1581+
templateContext.fillText(obj.text || '', obj.x, obj.y);
15751582
renderedCount++;
15761583
} else {
15771584
console.warn('Unknown template object type:', obj.type);
@@ -1580,11 +1587,15 @@ function Canvas({
15801587
console.warn('Failed to render template object:', obj, e);
15811588
}
15821589
}
1583-
offscreenContext.restore();
1590+
templateContext.restore();
15841591
} else {
15851592
console.log('No template objects to render');
15861593
}
15871594

1595+
if (templateCanvas) {
1596+
offscreenContext.drawImage(templateCanvas, 0, 0);
1597+
}
1598+
15881599
const cutOriginalIds = new Set();
15891600
try {
15901601
combined.forEach((d) => {
@@ -1686,6 +1697,21 @@ function Canvas({
16861697
} finally {
16871698
offscreenContext.restore();
16881699
}
1700+
1701+
// Restore template layer in the cut region so templates remain visible
1702+
if (templateCanvas) {
1703+
offscreenContext.drawImage(
1704+
templateCanvas,
1705+
Math.floor(r.x) - 2,
1706+
Math.floor(r.y) - 2,
1707+
Math.ceil(r.width) + 4,
1708+
Math.ceil(r.height) + 4,
1709+
Math.floor(r.x) - 2,
1710+
Math.floor(r.y) - 2,
1711+
Math.ceil(r.width) + 4,
1712+
Math.ceil(r.height) + 4
1713+
);
1714+
}
16891715
}
16901716

16911717
continue;

0 commit comments

Comments
 (0)