mirror of
https://github.com/Azornes/Comfyui-LayerForge.git
synced 2026-03-25 06:22:14 -03:00
Add layer visibility toggle and icon support
Introduces a 'visible' property to layers and updates all relevant logic to support toggling layer visibility. Adds visibility toggle icons to the layers panel using a new IconLoader utility, with SVG and fallback canvas icons. Updates rendering, selection, and batch preview logic to respect layer visibility. Also improves blend mode menu UI and ensures new/pasted layers are always added on top with correct z-index.
This commit is contained in:
@@ -38,6 +38,10 @@ export class CanvasLayers {
|
||||
finalX = area.x + (area.width - finalWidth) / 2;
|
||||
finalY = area.y + (area.height - finalHeight) / 2;
|
||||
}
|
||||
// Find the highest zIndex among existing layers
|
||||
const maxZIndex = this.canvas.layers.length > 0
|
||||
? Math.max(...this.canvas.layers.map(l => l.zIndex))
|
||||
: -1;
|
||||
const layer = {
|
||||
id: generateUUID(),
|
||||
image: image,
|
||||
@@ -50,9 +54,10 @@ export class CanvasLayers {
|
||||
originalWidth: image.width,
|
||||
originalHeight: image.height,
|
||||
rotation: 0,
|
||||
zIndex: this.canvas.layers.length,
|
||||
zIndex: maxZIndex + 1, // Always add new layer on top
|
||||
blendMode: 'normal',
|
||||
opacity: 1,
|
||||
visible: true,
|
||||
...layerProps
|
||||
};
|
||||
if (layer.mask) {
|
||||
@@ -189,12 +194,16 @@ export class CanvasLayers {
|
||||
const { x: mouseX, y: mouseY } = this.canvas.lastMousePosition;
|
||||
const offsetX = mouseX - centerX;
|
||||
const offsetY = mouseY - centerY;
|
||||
this.internalClipboard.forEach((clipboardLayer) => {
|
||||
// Find the highest zIndex among existing layers
|
||||
const maxZIndex = this.canvas.layers.length > 0
|
||||
? Math.max(...this.canvas.layers.map(l => l.zIndex))
|
||||
: -1;
|
||||
this.internalClipboard.forEach((clipboardLayer, index) => {
|
||||
const newLayer = {
|
||||
...clipboardLayer,
|
||||
x: clipboardLayer.x + offsetX,
|
||||
y: clipboardLayer.y + offsetY,
|
||||
zIndex: this.canvas.layers.length
|
||||
zIndex: maxZIndex + 1 + index // Ensure pasted layers maintain their relative order
|
||||
};
|
||||
this.canvas.layers.push(newLayer);
|
||||
newLayers.push(newLayer);
|
||||
@@ -314,6 +323,9 @@ export class CanvasLayers {
|
||||
getLayerAtPosition(worldX, worldY) {
|
||||
for (let i = this.canvas.layers.length - 1; i >= 0; i--) {
|
||||
const layer = this.canvas.layers[i];
|
||||
// Skip invisible layers
|
||||
if (!layer.visible)
|
||||
continue;
|
||||
const centerX = layer.x + layer.width / 2;
|
||||
const centerY = layer.y + layer.height / 2;
|
||||
const dx = worldX - centerX;
|
||||
@@ -354,7 +366,11 @@ export class CanvasLayers {
|
||||
}
|
||||
_drawLayers(ctx, layers, options = {}) {
|
||||
const sortedLayers = [...layers].sort((a, b) => a.zIndex - b.zIndex);
|
||||
sortedLayers.forEach(layer => this._drawLayer(ctx, layer, options));
|
||||
sortedLayers.forEach(layer => {
|
||||
if (layer.visible) {
|
||||
this._drawLayer(ctx, layer, options);
|
||||
}
|
||||
});
|
||||
}
|
||||
drawLayersToContext(ctx, layers, options = {}) {
|
||||
this._drawLayers(ctx, layers, options);
|
||||
@@ -491,8 +507,46 @@ export class CanvasLayers {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid #4a4a4a;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
`;
|
||||
titleBar.textContent = 'Blend Mode';
|
||||
const titleText = document.createElement('span');
|
||||
titleText.textContent = 'Blend Mode';
|
||||
titleText.style.cssText = `
|
||||
flex: 1;
|
||||
cursor: move;
|
||||
`;
|
||||
const closeButton = document.createElement('button');
|
||||
closeButton.textContent = '×';
|
||||
closeButton.style.cssText = `
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 3px;
|
||||
transition: background-color 0.2s;
|
||||
`;
|
||||
closeButton.onmouseover = () => {
|
||||
closeButton.style.backgroundColor = '#4a4a4a';
|
||||
};
|
||||
closeButton.onmouseout = () => {
|
||||
closeButton.style.backgroundColor = 'transparent';
|
||||
};
|
||||
closeButton.onclick = (e) => {
|
||||
e.stopPropagation();
|
||||
this.closeBlendModeMenu();
|
||||
};
|
||||
titleBar.appendChild(titleText);
|
||||
titleBar.appendChild(closeButton);
|
||||
const content = document.createElement('div');
|
||||
content.style.cssText = `padding: 5px;`;
|
||||
menu.appendChild(titleBar);
|
||||
@@ -823,7 +877,8 @@ export class CanvasLayers {
|
||||
rotation: 0,
|
||||
zIndex: minZIndex,
|
||||
blendMode: 'normal',
|
||||
opacity: 1
|
||||
opacity: 1,
|
||||
visible: true
|
||||
};
|
||||
this.canvas.layers = this.canvas.layers.filter((layer) => !this.canvas.canvasSelection.selectedLayers.includes(layer));
|
||||
this.canvas.layers.push(fusedLayer);
|
||||
|
||||
Reference in New Issue
Block a user