Refactor Canvas class as facade and clean up CanvasLayers

Refactored the Canvas class to act as a facade, providing a simplified high-level interface and delegating detailed operations to internal modules. Added Polish documentation, grouped and clarified main operations, and moved legacy/delegation methods to the end for backward compatibility. Removed unused or redundant methods from CanvasLayers.js, such as removeLayer, moveLayer, addMattedLayer, isRotationHandle, getResizeHandle, handleBlendModeSelection, and getFlattenedCanvasAsDataURL, to streamline the codebase.
This commit is contained in:
Dariusz L
2025-06-29 04:41:48 +02:00
parent 7a7c8f2295
commit 9dcf38b36d
2 changed files with 290 additions and 491 deletions

View File

@@ -162,32 +162,6 @@ export class CanvasLayers {
return this.addLayerWithImage(image);
}
async removeLayer(index) {
if (index >= 0 && index < this.canvasLayers.layers.length) {
const layer = this.canvasLayers.layers[index];
if (layer.imageId) {
const isImageUsedElsewhere = this.canvasLayers.layers.some((l, i) => i !== index && l.imageId === layer.imageId);
if (!isImageUsedElsewhere) {
await removeImage(layer.imageId);
this.canvasLayers.imageCache.delete(layer.imageId);
}
}
this.canvasLayers.layers.splice(index, 1);
this.canvasLayers.selectedLayer = this.canvasLayers.layers[this.canvasLayers.layers.length - 1] || null;
this.canvasLayers.render();
this.canvasLayers.saveState();
}
}
moveLayer(fromIndex, toIndex) {
if (fromIndex >= 0 && fromIndex < this.canvasLayers.layers.length &&
toIndex >= 0 && toIndex < this.canvasLayers.layers.length) {
const layer = this.canvasLayers.layers.splice(fromIndex, 1)[0];
this.canvasLayers.layers.splice(toIndex, 0, layer);
this.canvasLayers.render();
}
}
moveLayerUp() {
if (this.canvasLayers.selectedLayers.length === 0) return;
const selectedIndicesSet = new Set(this.canvasLayers.selectedLayers.map(layer => this.canvasLayers.layers.indexOf(layer)));
@@ -361,33 +335,6 @@ export class CanvasLayers {
}
}
addMattedLayer(image, mask) {
const layer = {
image: image,
mask: mask,
x: 0,
y: 0,
width: image.width,
height: image.height,
rotation: 0,
zIndex: this.canvasLayers.layers.length
};
this.canvasLayers.layers.push(layer);
this.canvasLayers.selectedLayer = layer;
this.canvasLayers.render();
}
isRotationHandle(x, y) {
if (!this.canvasLayers.selectedLayer) return false;
const handleX = this.canvasLayers.selectedLayer.x + this.canvasLayers.selectedLayer.width / 2;
const handleY = this.canvasLayers.selectedLayer.y - 20;
const handleRadius = 5;
return Math.sqrt(Math.pow(x - handleX, 2) + Math.pow(y - handleY, 2)) <= handleRadius;
}
getHandles(layer) {
if (!layer) return {};
@@ -442,34 +389,6 @@ export class CanvasLayers {
return null;
}
getResizeHandle(x, y) {
if (!this.canvasLayers.selectedLayer) return null;
const handleRadius = 5;
const handles = {
'nw': {x: this.canvasLayers.selectedLayer.x, y: this.canvasLayers.selectedLayer.y},
'ne': {
x: this.canvasLayers.selectedLayer.x + this.canvasLayers.selectedLayer.width,
y: this.canvasLayers.selectedLayer.y
},
'se': {
x: this.canvasLayers.selectedLayer.x + this.canvasLayers.selectedLayer.width,
y: this.canvasLayers.selectedLayer.y + this.canvasLayers.selectedLayer.height
},
'sw': {
x: this.canvasLayers.selectedLayer.x,
y: this.canvasLayers.selectedLayer.y + this.canvasLayers.selectedLayer.height
}
};
for (const [position, point] of Object.entries(handles)) {
if (Math.sqrt(Math.pow(x - point.x, 2) + Math.pow(y - point.y, 2)) <= handleRadius) {
return position;
}
}
return null;
}
showBlendModeMenu(x, y) {
this.closeBlendModeMenu();
@@ -591,17 +510,6 @@ export class CanvasLayers {
}
}
handleBlendModeSelection(mode) {
if (this.selectedBlendMode === mode && !this.isAdjustingOpacity) {
this.applyBlendMode(mode, this.blendOpacity);
this.closeBlendModeMenu();
} else {
this.selectedBlendMode = mode;
this.isAdjustingOpacity = true;
this.showOpacitySlider(mode);
}
}
showOpacitySlider(mode) {
const slider = document.createElement('input');
slider.type = 'range';
@@ -734,36 +642,4 @@ export class CanvasLayers {
}, 'image/png');
});
}
async getFlattenedCanvasAsDataURL() {
if (this.canvasLayers.layers.length === 0) return null;
const tempCanvas = document.createElement('canvas');
tempCanvas.width = this.canvasLayers.width;
tempCanvas.height = this.canvasLayers.height;
const tempCtx = tempCanvas.getContext('2d');
const sortedLayers = [...this.canvasLayers.layers].sort((a, b) => a.zIndex - b.zIndex);
sortedLayers.forEach(layer => {
if (!layer.image) return;
tempCtx.save();
tempCtx.globalCompositeOperation = layer.blendMode || 'normal';
tempCtx.globalAlpha = layer.opacity !== undefined ? layer.opacity : 1;
const centerX = layer.x + layer.width / 2;
const centerY = layer.y + layer.height / 2;
tempCtx.translate(centerX, centerY);
tempCtx.rotate(layer.rotation * Math.PI / 180);
tempCtx.drawImage(
layer.image,
-layer.width / 2,
-layer.height / 2,
layer.width,
layer.height
);
tempCtx.restore();
});
return tempCanvas.toDataURL('image/png');
}
}