feat: 优化跨层级移动和套索抠图命令,支持异步执行,改进画布刷新逻辑,新增背景裁剪选项

This commit is contained in:
bighuixiang
2025-07-11 00:26:38 +08:00
parent d3e22f368b
commit 96e13cb22a
10 changed files with 129 additions and 121 deletions

View File

@@ -181,7 +181,7 @@ export class CrossLevelMoveCommand extends Command {
return ancestor ? checkChildren(ancestor.children) : false;
}
execute() {
async execute() {
console.log("🎯 执行跨层级移动命令:", {
layerId: this.layerId,
from: this.fromContainerType,
@@ -220,10 +220,13 @@ export class CrossLevelMoveCommand extends Command {
this.saveAfterState();
// 刷新画布
if (this.canvas) {
this.canvas.renderAll();
console.log("🎨 画布已刷新");
}
// if (this.canvas) {
// this.canvas.renderAll();
// console.log("🎨 画布已刷新");
// }
await this.layerManager?.updateLayersObjectsInteractivity();
this.canvas?.renderAll();
console.log("✅ 跨层级移动命令执行成功");
return true;
@@ -248,7 +251,7 @@ export class CrossLevelMoveCommand extends Command {
}
}
undo() {
async undo() {
if (!this.beforeState) {
throw new Error("没有保存的前置状态,无法撤销");
}
@@ -262,14 +265,10 @@ export class CrossLevelMoveCommand extends Command {
// 恢复fabric对象状态
this.restoreFabricObjectStates(this.beforeState.fabricObjects);
await this.layerManager?.updateLayersObjectsInteractivity();
this.canvas?.renderAll();
// 刷新画布
if (this.canvas) {
// 使用 requestAnimationFrame 确保DOM更新完成后再渲染
requestAnimationFrame(() => {
this.canvas.renderAll();
});
}
this.canvas?.renderAll();
console.log("✅ 跨层级移动命令撤销成功");
return true;
} catch (error) {
@@ -331,7 +330,7 @@ export class CrossLevelMoveCommand extends Command {
/**
* 重做命令
*/
redo() {
async redo() {
if (!this.afterState) {
throw new Error("没有保存的后置状态,无法重做");
}
@@ -345,13 +344,9 @@ export class CrossLevelMoveCommand extends Command {
// 恢复fabric对象状态
this.restoreFabricObjectStates(this.afterState.fabricObjects);
await this.layerManager?.updateLayersObjectsInteractivity();
// 刷新画布
if (this.canvas) {
// 使用 requestAnimationFrame 确保DOM更新完成后再渲染
requestAnimationFrame(() => {
this.canvas.renderAll();
});
}
this.canvas?.renderAll();
console.log("✅ 跨层级移动命令重做成功");
return true;

View File

@@ -2,6 +2,7 @@ import {
createLayer,
findInChildLayers,
LayerType,
OperationType,
} from "../utils/layerHelper.js";
import { createRasterizedImage } from "../utils/selectionToImage.js";
import { CompositeCommand, Command } from "./Command.js";
@@ -11,6 +12,7 @@ import {
} from "./LayerCommands.js";
import { fabric } from "fabric-with-all";
import { generateId } from "../utils/helper.js";
import { ToolCommand } from "./ToolCommands.js";
/**
* 套索抠图命令
@@ -256,16 +258,16 @@ export class LassoCutoutCommand extends CompositeCommand {
// this.fabricImage.toObject("id", "layerId", "layerName", "parentId"),
// ];
// 2. 删除原图层命令
const removeOriginalLayerCmd = new RemoveLayerCommand({
canvas: this.canvas,
layers: this.layerManager.layers,
layerId: this.originalLayer.id,
activeLayerId: this.layerManager.activeLayerId,
});
// const removeOriginalLayerCmd = new RemoveLayerCommand({
// canvas: this.canvas,
// layers: this.layerManager.layers,
// layerId: this.originalLayer.id,
// activeLayerId: this.layerManager.activeLayerId,l
// });
// 执行删除原图层命令
await removeOriginalLayerCmd.execute();
this.executedCommands.push(removeOriginalLayerCmd);
// // 执行删除原图层命令
// await removeOriginalLayerCmd.execute();
// this.executedCommands.push(removeOriginalLayerCmd);
this.groupLayer.clippingMask = clippingMask.toObject(["id", "layerId"]); // 设置组图层的fabricObject为遮罩图像
@@ -275,6 +277,21 @@ export class LassoCutoutCommand extends CompositeCommand {
this.layerManager.activeLayerId.value = selectLayer.id; // 设置新组图层为活动图层
// 切换工具到选择模式
// 3. 切换工具到选择模式命令
if (this.toolManager) {
const toolCmd = new ToolCommand({
toolManager: this.toolManager,
tool: OperationType.SELECT,
previousTool: this.toolManager.getCurrentTool(),
});
// 执行工具切换命令
await toolCmd.execute();
this.commands.push(toolCmd);
this.executedCommands.push(toolCmd);
}
this.canvas.discardActiveObject();
// this.canvas.setActiveObject(this.fabricImage);
await this.layerManager.updateLayersObjectsInteractivity(true);

View File

@@ -2033,8 +2033,12 @@ export class LayerObjectsToGroupCommand extends Command {
const allObjects = [...originalObjects, ...newObjects];
const clipPath = allObjects?.[0]?.clipPath || null;
// 从画布中移除所有要组合的对象
allObjects.forEach((obj) => {
obj.clipPath = null;
obj.dirty = true; // 标记为脏对象
// obj.setCoords();
obj.opacity = 1;
removeCanvasObjectByObject(this.canvas, obj);
});
@@ -2052,6 +2056,10 @@ export class LayerObjectsToGroupCommand extends Command {
// 添加组对象到画布
this.canvas.add(groupObject);
groupObject.clipPath = clipPath; // 恢复剪切路径
groupObject.dirty = true; // 标记为脏对象
groupObject.setCoords();
// 更新图层的对象列表
// this.activeLayer.fabricObjects = [groupObject];
this.activeLayer.fabricObjects = [