// js/canvasManager.js let backgroundCanvas; let lastShapesArray = []; const SVG_NS = "http://www.w3.org/2000/svg"; /** * Renders all shapes into an SVG container * @param {SVGElement} container * @param {Array} shapesArray * @param {Array} patches */ export function drawAllShapesOnCanvas(container, shapesArray, patches = []) { if (!container || !(container instanceof SVGElement)) { return; } // Ensure patches is an array const patchArray = patches?.patches || patches || []; if (!Array.isArray(patchArray)) { console.warn("Expected patches to be an array, got:", typeof patchArray, patchArray); // Fall back to full redraw patches = []; } // If no patches, do a full redraw if (!patchArray || patchArray.length === 0) { // Clear container while (container.firstChild) { container.removeChild(container.firstChild); } // Draw all shapes shapesArray.forEach(shape => { let element; if (shape.type === "circle") { element = document.createElementNS(SVG_NS, "circle"); element.id = shape.id; updateCircleAttributes(element, shape); } else if (shape.type === "triangle") { element = document.createElementNS(SVG_NS, "polygon"); element.id = shape.id; updateTriangleAttributes(element, shape); } if (element) { container.appendChild(element); } }); return; } // Process patches patchArray.forEach(patch => { // Check if this patch affects the shapes array if (patch.path[0] === 'shapes') { if (patch.action === 'put') { const shapeIndex = patch.path[1]; const shape = shapesArray[shapeIndex]; if (!shape) return; let element = document.getElementById(shape.id); if (!element) { // Create new element if (shape.type === "circle") { element = document.createElementNS(SVG_NS, "circle"); element.id = shape.id; updateCircleAttributes(element, shape); } else if (shape.type === "triangle") { element = document.createElementNS(SVG_NS, "polygon"); element.id = shape.id; updateTriangleAttributes(element, shape); } if (element) { container.appendChild(element); } } else { // Update existing element if (shape.type === "circle") { updateCircleAttributes(element, shape); } else if (shape.type === "triangle") { updateTriangleAttributes(element, shape); } } } else if (patch.action === 'del') { // Shape removed const element = document.getElementById(patch.path[1]); if (element) { container.removeChild(element); } } } }); } function updateSpecificAttribute(element, shape, path) { if (shape.type === "circle") { switch (path[path.length - 1]) { case 'x': element.setAttributeNS(null, "cx", shape.x); break; case 'y': element.setAttributeNS(null, "cy", shape.y); break; case 'radius': element.setAttributeNS(null, "r", shape.radius); break; case 'color': element.setAttributeNS(null, "fill", shape.color || "black"); break; } } else if (shape.type === "triangle") { if (path.includes('coordinates')) { const points = shape.coordinates .map(p => `${p.x},${p.y}`) .join(" "); element.setAttributeNS(null, "points", points); } else if (path.includes('color')) { element.setAttributeNS(null, "fill", shape.color || "black"); } } } function updateCircleAttributes(element, shape) { element.setAttributeNS(null, "cx", shape.x); element.setAttributeNS(null, "cy", shape.y); element.setAttributeNS(null, "r", shape.radius); element.setAttributeNS(null, "fill", shape.color || "black"); element.setAttributeNS(null, "stroke", "black"); element.setAttributeNS(null, "stroke-width", "1"); } function updateTriangleAttributes(element, shape) { const points = shape.coordinates .map(p => `${p.x},${p.y}`) .join(" "); element.setAttributeNS(null, "points", points); element.setAttributeNS(null, "fill", shape.color || "black"); element.setAttributeNS(null, "stroke", "black"); element.setAttributeNS(null, "stroke-width", "1"); }