Example-Automerge-App/src/canvasManager.js

143 lines
5.0 KiB
JavaScript

// 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");
}