feat: 裁剪组裁剪跟随选择组移动
This commit is contained in:
@@ -22,9 +22,7 @@ export class CreateBackgroundLayerCommand extends Command {
|
||||
|
||||
execute() {
|
||||
// 检查是否已经存在背景图层
|
||||
const existingBgLayer = this.layers.value.find(
|
||||
(layer) => layer.isBackground
|
||||
);
|
||||
const existingBgLayer = this.layers.value.find((layer) => layer.isBackground);
|
||||
if (existingBgLayer) {
|
||||
console.warn("已存在背景层,不重复创建");
|
||||
return existingBgLayer.id;
|
||||
@@ -34,11 +32,7 @@ export class CreateBackgroundLayerCommand extends Command {
|
||||
const bgObject = this._createBackgroundObject();
|
||||
|
||||
// 将背景对象添加到图层中
|
||||
this.backgroundLayer.fabricObject = bgObject.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"type",
|
||||
]);
|
||||
this.backgroundLayer.fabricObject = bgObject.toObject(["id", "layerId", "type"]);
|
||||
|
||||
// 添加图层到最底部
|
||||
this.layers.value.push(this.backgroundLayer);
|
||||
@@ -54,9 +48,7 @@ export class CreateBackgroundLayerCommand extends Command {
|
||||
|
||||
undo() {
|
||||
// 从图层列表中删除背景图层
|
||||
const bgLayerIndex = this.layers.value.findIndex(
|
||||
(layer) => layer.isBackground
|
||||
);
|
||||
const bgLayerIndex = this.layers.value.findIndex((layer) => layer.isBackground);
|
||||
if (bgLayerIndex !== -1) {
|
||||
this.layers.value.splice(bgLayerIndex, 1);
|
||||
}
|
||||
@@ -82,8 +74,7 @@ export class CreateBackgroundLayerCommand extends Command {
|
||||
|
||||
// 确保背景色为白色,如果没有设置或者是透明的话
|
||||
const backgroundColor =
|
||||
this.backgroundLayer.backgroundColor &&
|
||||
this.backgroundLayer.backgroundColor !== "transparent"
|
||||
this.backgroundLayer.backgroundColor && this.backgroundLayer.backgroundColor !== "transparent"
|
||||
? this.backgroundLayer.backgroundColor
|
||||
: "#ffffff";
|
||||
|
||||
@@ -139,10 +130,7 @@ export class UpdateBackgroundCommand extends Command {
|
||||
// 查找背景图层
|
||||
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
|
||||
this.oldBackgroundColor = this.oldColor;
|
||||
this.backgroundObject = findObjectById(
|
||||
this.canvas,
|
||||
this.bgLayer.fabricObject.id
|
||||
).object;
|
||||
this.backgroundObject = findObjectById(this.canvas, this.bgLayer.fabricObject.id).object;
|
||||
}
|
||||
|
||||
execute() {
|
||||
@@ -163,9 +151,7 @@ export class UpdateBackgroundCommand extends Command {
|
||||
this.backgroundColorValue.value = this.backgroundColor; // 设置背景颜色
|
||||
|
||||
// 生成缩略图
|
||||
this.canvasManager?.thumbnailManager?.generateLayerThumbnail?.(
|
||||
this.bgLayer.id
|
||||
);
|
||||
this.canvasManager?.thumbnailManager?.generateLayerThumbnail?.(this.bgLayer.id);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -186,9 +172,7 @@ export class UpdateBackgroundCommand extends Command {
|
||||
this.backgroundColorValue.value = this.oldBackgroundColor; // 恢复背景颜色
|
||||
|
||||
// 生成缩略图
|
||||
this.canvasManager?.thumbnailManager?.generateLayerThumbnail?.(
|
||||
this.bgLayer.id
|
||||
);
|
||||
this.canvasManager?.thumbnailManager?.generateLayerThumbnail?.(this.bgLayer.id);
|
||||
// 如果有旧颜色,恢复到旧颜色
|
||||
return true;
|
||||
}
|
||||
@@ -223,10 +207,7 @@ export class BackgroundSizeCommand extends Command {
|
||||
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
|
||||
|
||||
// 记录原尺寸
|
||||
this.backgroundObject = findObjectById(
|
||||
this.canvas,
|
||||
this.bgLayer.fabricObject.id
|
||||
).object;
|
||||
this.backgroundObject = findObjectById(this.canvas, this.bgLayer.fabricObject.id).object;
|
||||
|
||||
this.oldWidth = this.backgroundObject.width;
|
||||
this.oldHeight = this.backgroundObject.height;
|
||||
@@ -255,8 +236,7 @@ export class BackgroundSizeCommand extends Command {
|
||||
// 调整背景对象大小
|
||||
if (this.bgLayer && this.backgroundObject) {
|
||||
// 保持原有的背景颜色,如果没有设置则使用白色
|
||||
const currentFill =
|
||||
this.backgroundObject.fill || this.bgLayer.backgroundColor || "#ffffff";
|
||||
const currentFill = this.backgroundObject.fill || this.bgLayer.backgroundColor || "#ffffff";
|
||||
|
||||
this.backgroundObject.set({
|
||||
width: this.newWidth,
|
||||
@@ -343,10 +323,7 @@ export class BackgroundSizeWithScaleCommand extends Command {
|
||||
// 查找背景图层
|
||||
this.bgLayer = this.layers.value.find((layer) => layer.isBackground);
|
||||
|
||||
this.backgroundObject = findObjectById(
|
||||
this.canvas,
|
||||
this.bgLayer.fabricObject.id
|
||||
).object;
|
||||
this.backgroundObject = findObjectById(this.canvas, this.bgLayer.fabricObject.id).object;
|
||||
|
||||
// 计算缩放比例
|
||||
const scaleXRatio = this.newWidth / this.oldWidth;
|
||||
@@ -409,24 +386,21 @@ export class BackgroundSizeWithScaleCommand extends Command {
|
||||
// 统一缩放:使用平均值,保持相对比例的同时允许适度的形变
|
||||
this.uniformScale = Math.sqrt(scaleXRatio * scaleYRatio);
|
||||
this.offsetX = (this.newWidth - this.oldWidth * this.uniformScale) / 2;
|
||||
this.offsetY =
|
||||
(this.newHeight - this.oldHeight * this.uniformScale) / 2;
|
||||
this.offsetY = (this.newHeight - this.oldHeight * this.uniformScale) / 2;
|
||||
break;
|
||||
|
||||
case "fit":
|
||||
// 适应模式:使用较小值,确保所有内容都在画布内,可能有留白
|
||||
this.uniformScale = Math.min(scaleXRatio, scaleYRatio);
|
||||
this.offsetX = (this.newWidth - this.oldWidth * this.uniformScale) / 2;
|
||||
this.offsetY =
|
||||
(this.newHeight - this.oldHeight * this.uniformScale) / 2;
|
||||
this.offsetY = (this.newHeight - this.oldHeight * this.uniformScale) / 2;
|
||||
break;
|
||||
|
||||
case "fill":
|
||||
// 填充模式:使用较大值,填满画布,可能有部分内容被裁切
|
||||
this.uniformScale = Math.max(scaleXRatio, scaleYRatio);
|
||||
this.offsetX = (this.newWidth - this.oldWidth * this.uniformScale) / 2;
|
||||
this.offsetY =
|
||||
(this.newHeight - this.oldHeight * this.uniformScale) / 2;
|
||||
this.offsetY = (this.newHeight - this.oldHeight * this.uniformScale) / 2;
|
||||
break;
|
||||
|
||||
case "stretch":
|
||||
@@ -441,8 +415,7 @@ export class BackgroundSizeWithScaleCommand extends Command {
|
||||
// 默认使用uniform模式
|
||||
this.uniformScale = Math.sqrt(scaleXRatio * scaleYRatio);
|
||||
this.offsetX = (this.newWidth - this.oldWidth * this.uniformScale) / 2;
|
||||
this.offsetY =
|
||||
(this.newHeight - this.oldHeight * this.uniformScale) / 2;
|
||||
this.offsetY = (this.newHeight - this.oldHeight * this.uniformScale) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,8 +435,7 @@ export class BackgroundSizeWithScaleCommand extends Command {
|
||||
// 调整背景对象大小和位置
|
||||
if (this.bgLayer && this.backgroundObject) {
|
||||
// 保持原有的背景颜色,如果没有设置则使用白色
|
||||
const currentFill =
|
||||
this.backgroundObject.fill || this.bgLayer.backgroundColor || "#ffffff";
|
||||
const currentFill = this.backgroundObject.fill || this.bgLayer.backgroundColor || "#ffffff";
|
||||
|
||||
this.backgroundObject.set({
|
||||
width: this.newWidth,
|
||||
@@ -480,12 +452,10 @@ export class BackgroundSizeWithScaleCommand extends Command {
|
||||
|
||||
// 计算基于原始画布的缩放比例
|
||||
const baseScaleX =
|
||||
this.newWidth /
|
||||
this.objectStates[0]?.obj._originalState?.baseCanvasWidth ||
|
||||
this.newWidth / this.objectStates[0]?.obj._originalState?.baseCanvasWidth ||
|
||||
this.newWidth / this.oldWidth;
|
||||
const baseScaleY =
|
||||
this.newHeight /
|
||||
this.objectStates[0]?.obj._originalState?.baseCanvasHeight ||
|
||||
this.newHeight / this.objectStates[0]?.obj._originalState?.baseCanvasHeight ||
|
||||
this.newHeight / this.oldHeight;
|
||||
|
||||
// 根据策略缩放所有非背景对象
|
||||
@@ -505,13 +475,11 @@ export class BackgroundSizeWithScaleCommand extends Command {
|
||||
const baseUniformScale = Math.sqrt(baseScaleX * baseScaleY);
|
||||
const baseOffsetX =
|
||||
(this.newWidth -
|
||||
(obj._originalState?.baseCanvasWidth || this.oldWidth) *
|
||||
baseUniformScale) /
|
||||
(obj._originalState?.baseCanvasWidth || this.oldWidth) * baseUniformScale) /
|
||||
2;
|
||||
const baseOffsetY =
|
||||
(this.newHeight -
|
||||
(obj._originalState?.baseCanvasHeight || this.oldHeight) *
|
||||
baseUniformScale) /
|
||||
(obj._originalState?.baseCanvasHeight || this.oldHeight) * baseUniformScale) /
|
||||
2;
|
||||
|
||||
obj.set({
|
||||
@@ -537,10 +505,7 @@ export class BackgroundSizeWithScaleCommand extends Command {
|
||||
this.canvas.setHeight(this.oldHeight);
|
||||
|
||||
// 如果使用 CanvasManager,通知它画布大小恢复
|
||||
if (
|
||||
this.canvasManager &&
|
||||
typeof this.canvasManager.updateCanvasSize === "function"
|
||||
) {
|
||||
if (this.canvasManager && typeof this.canvasManager.updateCanvasSize === "function") {
|
||||
this.canvasManager.updateCanvasSize(this.oldWidth, this.oldHeight);
|
||||
}
|
||||
|
||||
@@ -568,12 +533,9 @@ export class BackgroundSizeWithScaleCommand extends Command {
|
||||
const baseScaleX = this.oldWidth / originalState.baseCanvasWidth;
|
||||
const baseScaleY = this.oldHeight / originalState.baseCanvasHeight;
|
||||
const baseUniformScale = Math.sqrt(baseScaleX * baseScaleY);
|
||||
const baseOffsetX =
|
||||
(this.oldWidth - originalState.baseCanvasWidth * baseUniformScale) /
|
||||
2;
|
||||
const baseOffsetX = (this.oldWidth - originalState.baseCanvasWidth * baseUniformScale) / 2;
|
||||
const baseOffsetY =
|
||||
(this.oldHeight - originalState.baseCanvasHeight * baseUniformScale) /
|
||||
2;
|
||||
(this.oldHeight - originalState.baseCanvasHeight * baseUniformScale) / 2;
|
||||
|
||||
obj.set({
|
||||
left: originalState.left * baseUniformScale + baseOffsetX,
|
||||
|
||||
@@ -26,9 +26,7 @@ export class BrushSizeCommand extends BaseBrushCommand {
|
||||
super({
|
||||
...options,
|
||||
name: `设置笔刷大小: ${options.size}`,
|
||||
description: `将笔刷大小从 ${options.previousSize || "?"} 设为 ${
|
||||
options.size
|
||||
}`,
|
||||
description: `将笔刷大小从 ${options.previousSize || "?"} 设为 ${options.size}`,
|
||||
});
|
||||
|
||||
this.size = options.size;
|
||||
@@ -66,9 +64,7 @@ export class BrushColorCommand extends BaseBrushCommand {
|
||||
super({
|
||||
...options,
|
||||
name: `设置笔刷颜色: ${options.color}`,
|
||||
description: `将笔刷颜色从 ${options.previousColor || "?"} 设为 ${
|
||||
options.color
|
||||
}`,
|
||||
description: `将笔刷颜色从 ${options.previousColor || "?"} 设为 ${options.color}`,
|
||||
});
|
||||
|
||||
this.color = options.color;
|
||||
@@ -106,14 +102,11 @@ export class BrushOpacityCommand extends BaseBrushCommand {
|
||||
super({
|
||||
...options,
|
||||
name: `设置笔刷透明度: ${options.opacity}`,
|
||||
description: `将笔刷透明度从 ${options.previousOpacity || "?"} 设为 ${
|
||||
options.opacity
|
||||
}`,
|
||||
description: `将笔刷透明度从 ${options.previousOpacity || "?"} 设为 ${options.opacity}`,
|
||||
});
|
||||
|
||||
this.opacity = options.opacity;
|
||||
this.previousOpacity =
|
||||
options.previousOpacity || this.brushStore.state.opacity;
|
||||
this.previousOpacity = options.previousOpacity || this.brushStore.state.opacity;
|
||||
}
|
||||
|
||||
execute() {
|
||||
@@ -147,9 +140,7 @@ export class BrushTypeCommand extends BaseBrushCommand {
|
||||
super({
|
||||
...options,
|
||||
name: `设置笔刷类型: ${options.brushType}`,
|
||||
description: `将笔刷类型从 ${options.previousType || "?"} 设为 ${
|
||||
options.brushType
|
||||
}`,
|
||||
description: `将笔刷类型从 ${options.previousType || "?"} 设为 ${options.brushType}`,
|
||||
});
|
||||
|
||||
this.brushType = options.brushType;
|
||||
@@ -192,9 +183,7 @@ export class TextureCommand extends BaseBrushCommand {
|
||||
super({
|
||||
...options,
|
||||
name: options.enabled ? "启用笔刷材质" : "禁用笔刷材质",
|
||||
description: options.enabled
|
||||
? `启用材质: ${options.path || "[默认]"}`
|
||||
: "禁用笔刷材质",
|
||||
description: options.enabled ? `启用材质: ${options.path || "[默认]"}` : "禁用笔刷材质",
|
||||
});
|
||||
|
||||
this.enabled = options.enabled;
|
||||
@@ -260,9 +249,7 @@ export class BrushPresetCommand extends BaseBrushCommand {
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
const presetName =
|
||||
typeof options.preset === "object"
|
||||
? options.preset.name
|
||||
: `预设 ${options.preset}`;
|
||||
typeof options.preset === "object" ? options.preset.name : `预设 ${options.preset}`;
|
||||
|
||||
super({
|
||||
...options,
|
||||
@@ -303,14 +290,10 @@ export class BrushPresetCommand extends BaseBrushCommand {
|
||||
this.brushStore.applyPreset(this.preset);
|
||||
} else if (typeof this.preset === "object") {
|
||||
// 应用自定义预设对象
|
||||
if (this.preset.size !== undefined)
|
||||
this.brushStore.setBrushSize(this.preset.size);
|
||||
if (this.preset.color !== undefined)
|
||||
this.brushStore.setBrushColor(this.preset.color);
|
||||
if (this.preset.opacity !== undefined)
|
||||
this.brushStore.setBrushOpacity(this.preset.opacity);
|
||||
if (this.preset.type !== undefined)
|
||||
this.brushStore.setBrushType(this.preset.type);
|
||||
if (this.preset.size !== undefined) this.brushStore.setBrushSize(this.preset.size);
|
||||
if (this.preset.color !== undefined) this.brushStore.setBrushColor(this.preset.color);
|
||||
if (this.preset.opacity !== undefined) this.brushStore.setBrushOpacity(this.preset.opacity);
|
||||
if (this.preset.type !== undefined) this.brushStore.setBrushType(this.preset.type);
|
||||
|
||||
if (this.preset.textureEnabled !== undefined) {
|
||||
this.brushStore.setTextureEnabled(this.preset.textureEnabled);
|
||||
@@ -542,8 +525,7 @@ export class TexturePresetCommand extends BaseBrushCommand {
|
||||
* @param {Object} options.brushManager 笔刷管理器实例
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
const presetName =
|
||||
typeof options.preset === "object" ? options.preset.name : options.preset;
|
||||
const presetName = typeof options.preset === "object" ? options.preset.name : options.preset;
|
||||
|
||||
super({
|
||||
...options,
|
||||
@@ -614,10 +596,7 @@ export class TextureUploadCommand extends BaseBrushCommand {
|
||||
});
|
||||
|
||||
this.file = options.file;
|
||||
this.name =
|
||||
options.name ||
|
||||
options.file?.name?.replace(/\.[^/.]+$/, "") ||
|
||||
"自定义纹理";
|
||||
this.name = options.name || options.file?.name?.replace(/\.[^/.]+$/, "") || "自定义纹理";
|
||||
this.category = options.category || "自定义材质";
|
||||
this.texturePresetManager = options.texturePresetManager;
|
||||
this.brushManager = options.brushManager;
|
||||
|
||||
@@ -24,8 +24,7 @@ export class ClearSelectionContentCommand extends Command {
|
||||
|
||||
this.oldLayer = [...this.layers.value]; // 获取原图层对象
|
||||
|
||||
const { layer } =
|
||||
findLayerRecursively(this.layers.value, this.targetLayerId) || {};
|
||||
const { layer } = findLayerRecursively(this.layers.value, this.targetLayerId) || {};
|
||||
|
||||
// 栅格化相关属性
|
||||
this.originalLayerBackup = null;
|
||||
@@ -37,17 +36,10 @@ export class ClearSelectionContentCommand extends Command {
|
||||
|
||||
// this.originalLayerObject = fabric.util.object.clone(originalLayerObject); // 获取原图层对象
|
||||
|
||||
this.oldLayerObjects = originalLayerObject.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"layerName",
|
||||
]); // 获取原图层的所有对象
|
||||
this.oldLayerObjects = originalLayerObject.toObject(["id", "layerId", "layerName"]); // 获取原图层的所有对象
|
||||
|
||||
this.rasterizedImage = null;
|
||||
this.targetLayer = findLayerRecursively(
|
||||
this.canvas,
|
||||
this.targetLayerId
|
||||
)?.layer;
|
||||
this.targetLayer = findLayerRecursively(this.canvas, this.targetLayerId)?.layer;
|
||||
|
||||
this.layerRasterized = false;
|
||||
|
||||
@@ -88,8 +80,7 @@ export class ClearSelectionContentCommand extends Command {
|
||||
}
|
||||
|
||||
// 确定目标图层
|
||||
const layerId =
|
||||
this.targetLayerId || this.layerManager.getActiveLayerId();
|
||||
const layerId = this.targetLayerId || this.layerManager.getActiveLayerId();
|
||||
this.targetLayer = this.layerManager.getLayerById(layerId);
|
||||
if (!this.targetLayer) {
|
||||
console.error("无法清除选区内容:目标图层无效");
|
||||
@@ -107,9 +98,7 @@ export class ClearSelectionContentCommand extends Command {
|
||||
}
|
||||
|
||||
// 创建反转选区(保留选区外的内容)
|
||||
const invertedSelection = await this._createInvertedSelection(
|
||||
this.selectionObject
|
||||
);
|
||||
const invertedSelection = await this._createInvertedSelection(this.selectionObject);
|
||||
if (!invertedSelection) {
|
||||
console.error("创建反转选区失败");
|
||||
return false;
|
||||
@@ -137,10 +126,7 @@ export class ClearSelectionContentCommand extends Command {
|
||||
|
||||
// 恢复原图层状态
|
||||
// 移除栅格化后的图像
|
||||
if (
|
||||
this.rasterizedImage &&
|
||||
this.canvas.getObjects().includes(this.rasterizedImage)
|
||||
) {
|
||||
if (this.rasterizedImage && this.canvas.getObjects().includes(this.rasterizedImage)) {
|
||||
this.canvas.remove(this.rasterizedImage);
|
||||
}
|
||||
|
||||
@@ -199,10 +185,7 @@ export class ClearSelectionContentCommand extends Command {
|
||||
let scaleFactor = this.baseResolutionScale;
|
||||
if (this.highResolutionEnabled) {
|
||||
const currentZoom = this.canvas.getZoom?.() || 1;
|
||||
scaleFactor = Math.max(
|
||||
scaleFactor || this.canvas?.getRetinaScaling?.(),
|
||||
currentZoom
|
||||
);
|
||||
scaleFactor = Math.max(scaleFactor || this.canvas?.getRetinaScaling?.(), currentZoom);
|
||||
scaleFactor = Math.min(scaleFactor, 3);
|
||||
}
|
||||
|
||||
@@ -286,9 +269,7 @@ export class ClearSelectionContentCommand extends Command {
|
||||
layerBounds.left + layerBounds.width
|
||||
} ${layerBounds.top} L ${layerBounds.left + layerBounds.width} ${
|
||||
layerBounds.top + layerBounds.height
|
||||
} L ${layerBounds.left} ${layerBounds.top + layerBounds.height} Z ${
|
||||
selectionObject.path
|
||||
}`;
|
||||
} L ${layerBounds.left} ${layerBounds.top + layerBounds.height} Z ${selectionObject.path}`;
|
||||
|
||||
const invertedPath = new fabric.Path(pathString, {
|
||||
fillRule: "evenodd",
|
||||
@@ -329,14 +310,8 @@ export class ClearSelectionContentCommand extends Command {
|
||||
if (!bounds) {
|
||||
bounds = { ...objBounds };
|
||||
} else {
|
||||
const right = Math.max(
|
||||
bounds.left + bounds.width,
|
||||
objBounds.left + objBounds.width
|
||||
);
|
||||
const bottom = Math.max(
|
||||
bounds.top + bounds.height,
|
||||
objBounds.top + objBounds.height
|
||||
);
|
||||
const right = Math.max(bounds.left + bounds.width, objBounds.left + objBounds.width);
|
||||
const bottom = Math.max(bounds.top + bounds.height, objBounds.top + objBounds.height);
|
||||
|
||||
bounds.left = Math.min(bounds.left, objBounds.left);
|
||||
bounds.top = Math.min(bounds.top, objBounds.top);
|
||||
@@ -370,15 +345,10 @@ export class ClearSelectionContentCommand extends Command {
|
||||
// 递归获取图层及其子图层的所有对象
|
||||
const collectLayerObjects = (currentLayer) => {
|
||||
// 处理图层的fabricObjects
|
||||
if (
|
||||
currentLayer.fabricObjects &&
|
||||
Array.isArray(currentLayer.fabricObjects)
|
||||
) {
|
||||
if (currentLayer.fabricObjects && Array.isArray(currentLayer.fabricObjects)) {
|
||||
currentLayer.fabricObjects.forEach((fabricObj) => {
|
||||
if (fabricObj && fabricObj.id) {
|
||||
const realObject = canvasObjects.find(
|
||||
(canvasObj) => canvasObj.id === fabricObj.id
|
||||
);
|
||||
const realObject = canvasObjects.find((canvasObj) => canvasObj.id === fabricObj.id);
|
||||
if (realObject && realObject.visible !== false) {
|
||||
objects.push(realObject);
|
||||
}
|
||||
@@ -420,16 +390,12 @@ export class ClearSelectionContentCommand extends Command {
|
||||
}
|
||||
|
||||
// 移除栅格化后的图像
|
||||
if (
|
||||
this.rasterizedImage &&
|
||||
this.canvas.getObjects().includes(this.rasterizedImage)
|
||||
) {
|
||||
if (this.rasterizedImage && this.canvas.getObjects().includes(this.rasterizedImage)) {
|
||||
this.canvas.remove(this.rasterizedImage);
|
||||
}
|
||||
|
||||
// 恢复图层的fabricObjects
|
||||
this.targetLayer.fabricObjects =
|
||||
this.originalLayerBackup.fabricObjects || [];
|
||||
this.targetLayer.fabricObjects = this.originalLayerBackup.fabricObjects || [];
|
||||
|
||||
// 重新创建并添加对象到画布
|
||||
if (this.targetLayer.fabricObjects.length > 0) {
|
||||
|
||||
@@ -109,10 +109,7 @@ export class CompositeCommand extends Command {
|
||||
|
||||
console.log(`✅ 子命令执行成功: ${command.constructor.name}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`❌ 子命令执行失败: ${command.constructor.name}`,
|
||||
error
|
||||
);
|
||||
console.error(`❌ 子命令执行失败: ${command.constructor.name}`, error);
|
||||
|
||||
// 执行失败时,撤销已执行的命令
|
||||
await this._rollbackExecutedCommands();
|
||||
@@ -142,9 +139,7 @@ export class CompositeCommand extends Command {
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`↩️ 开始撤销复合命令,共 ${this.executedCommands.length} 个子命令`
|
||||
);
|
||||
console.log(`↩️ 开始撤销复合命令,共 ${this.executedCommands.length} 个子命令`);
|
||||
|
||||
try {
|
||||
// 逆序撤销已执行的命令
|
||||
@@ -164,10 +159,7 @@ export class CompositeCommand extends Command {
|
||||
results.push(finalResult);
|
||||
console.log(`✅ 子命令撤销成功: ${command.constructor.name}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`❌ 子命令撤销失败: ${command.constructor.name}`,
|
||||
error
|
||||
);
|
||||
console.error(`❌ 子命令撤销失败: ${command.constructor.name}`, error);
|
||||
// 撤销失败不中断整个撤销过程,但要记录错误
|
||||
}
|
||||
} else {
|
||||
@@ -203,10 +195,7 @@ export class CompositeCommand extends Command {
|
||||
}
|
||||
console.log(`✅ 子命令回滚成功: ${command.constructor.name}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`❌ 子命令回滚失败: ${command.constructor.name}`,
|
||||
error
|
||||
);
|
||||
console.error(`❌ 子命令回滚失败: ${command.constructor.name}`, error);
|
||||
// 回滚失败不中断整个回滚过程
|
||||
}
|
||||
}
|
||||
@@ -238,9 +227,7 @@ export class CompositeCommand extends Command {
|
||||
commandCount: this.commands.length,
|
||||
executedCount: this.executedCommands.length,
|
||||
isExecuting: this.isExecuting,
|
||||
subCommands: this.commands.map((cmd) =>
|
||||
cmd.getInfo ? cmd.getInfo() : cmd.constructor.name
|
||||
),
|
||||
subCommands: this.commands.map((cmd) => (cmd.getInfo ? cmd.getInfo() : cmd.constructor.name)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,9 +85,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
this.layers.value.forEach((layer) => {
|
||||
if (layer.fabricObject) {
|
||||
states[layer.id] = {
|
||||
isInCanvas: this.canvas
|
||||
? this.canvas.contains(layer.fabricObject)
|
||||
: false,
|
||||
isInCanvas: this.canvas ? this.canvas.contains(layer.fabricObject) : false,
|
||||
parentGroupId: null,
|
||||
visible: layer.fabricObject.visible,
|
||||
};
|
||||
@@ -127,11 +125,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
* 验证移动的有效性
|
||||
*/
|
||||
validateMove() {
|
||||
const layer = this.findLayer(
|
||||
this.layerId,
|
||||
this.fromContainerType,
|
||||
this.fromParentId
|
||||
);
|
||||
const layer = this.findLayer(this.layerId, this.fromContainerType, this.fromParentId);
|
||||
|
||||
if (!layer) {
|
||||
throw new Error(`找不到要移动的图层: ${this.layerId}`);
|
||||
@@ -153,9 +147,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
|
||||
// 检查目标父图层是否为组
|
||||
if (this.toContainerType === "child") {
|
||||
const targetParent = this.layers.value.find(
|
||||
(layer) => layer.id === this.toParentId
|
||||
);
|
||||
const targetParent = this.layers.value.find((layer) => layer.id === this.toParentId);
|
||||
if (!targetParent || !isGroupLayer(targetParent)) {
|
||||
throw new Error("目标图层不是组图层");
|
||||
}
|
||||
@@ -198,15 +190,9 @@ export class CrossLevelMoveCommand extends Command {
|
||||
|
||||
try {
|
||||
// 根据移动类型执行对应操作
|
||||
if (
|
||||
this.fromContainerType === "root" &&
|
||||
this.toContainerType === "child"
|
||||
) {
|
||||
if (this.fromContainerType === "root" && this.toContainerType === "child") {
|
||||
this.moveRootToGroup(draggedLayer);
|
||||
} else if (
|
||||
this.fromContainerType === "child" &&
|
||||
this.toContainerType === "root"
|
||||
) {
|
||||
} else if (this.fromContainerType === "child" && this.toContainerType === "root") {
|
||||
this.moveGroupToRoot(draggedLayer);
|
||||
} else if (
|
||||
this.fromContainerType === "child" &&
|
||||
@@ -228,6 +214,17 @@ export class CrossLevelMoveCommand extends Command {
|
||||
await this.layerManager?.updateLayersObjectsInteractivity();
|
||||
this.canvas?.renderAll();
|
||||
|
||||
// 生成缩略图
|
||||
this.fromParentId &&
|
||||
this.layerManager?.canvasManager?.thumbnailManager?.generateLayerThumbnail?.(
|
||||
this.fromParentId
|
||||
);
|
||||
|
||||
this.toParentId &&
|
||||
this.layerManager?.canvasManager?.thumbnailManager?.generateLayerThumbnail?.(
|
||||
this.toParentId
|
||||
);
|
||||
|
||||
console.log("✅ 跨层级移动命令执行成功");
|
||||
return true;
|
||||
} catch (error) {
|
||||
@@ -266,7 +263,6 @@ export class CrossLevelMoveCommand extends Command {
|
||||
this.restoreFabricObjectStates(this.beforeState.fabricObjects);
|
||||
|
||||
await this.layerManager?.updateLayersObjectsInteractivity();
|
||||
this.canvas?.renderAll();
|
||||
// 刷新画布
|
||||
this.canvas?.renderAll();
|
||||
console.log("✅ 跨层级移动命令撤销成功");
|
||||
@@ -299,9 +295,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
|
||||
// 根据图层的parentId重新放置
|
||||
if (layer.parentId) {
|
||||
const parentLayer = this.layers.value.find(
|
||||
(l) => l.id === layer.parentId
|
||||
);
|
||||
const parentLayer = this.layers.value.find((l) => l.id === layer.parentId);
|
||||
if (
|
||||
parentLayer &&
|
||||
parentLayer.fabricObject &&
|
||||
@@ -396,14 +390,9 @@ export class CrossLevelMoveCommand extends Command {
|
||||
layer.children = layerData.children
|
||||
.map((childData) => {
|
||||
// 从原始图层数组中查找子图层
|
||||
let childLayer = originalLayers.find(
|
||||
(l) => l.id === childData.id
|
||||
);
|
||||
let childLayer = originalLayers.find((l) => l.id === childData.id);
|
||||
if (!childLayer) {
|
||||
childLayer = this.findLayerInOriginalStructure(
|
||||
childData.id,
|
||||
originalLayers
|
||||
);
|
||||
childLayer = this.findLayerInOriginalStructure(childData.id, originalLayers);
|
||||
}
|
||||
if (childLayer) {
|
||||
// 更新子图层属性
|
||||
@@ -465,9 +454,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
// 根据目标状态放置对象
|
||||
if (targetState.parentGroupId) {
|
||||
// 应该在特定组中
|
||||
const parentLayer = this.layers.value.find(
|
||||
(l) => l.id === targetState.parentGroupId
|
||||
);
|
||||
const parentLayer = this.layers.value.find((l) => l.id === targetState.parentGroupId);
|
||||
if (
|
||||
parentLayer &&
|
||||
parentLayer.fabricObject &&
|
||||
@@ -532,12 +519,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
*/
|
||||
safeRemoveFromContainer(fabricObject, container, containerName) {
|
||||
return this.safeFabricOperation(() => {
|
||||
if (
|
||||
container &&
|
||||
container.remove &&
|
||||
container.contains &&
|
||||
container.contains(fabricObject)
|
||||
) {
|
||||
if (container && container.remove && container.contains && container.contains(fabricObject)) {
|
||||
container.remove(fabricObject);
|
||||
console.log(`✅ 成功从${containerName}移除对象`);
|
||||
return true;
|
||||
@@ -556,11 +538,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
// 从所有组中移除
|
||||
this.layers.value.forEach((layer) => {
|
||||
if (layer.fabricObject && layer.fabricObject.type === "group") {
|
||||
this.safeRemoveFromContainer(
|
||||
fabricObject,
|
||||
layer.fabricObject,
|
||||
`组${layer.id}`
|
||||
);
|
||||
this.safeRemoveFromContainer(fabricObject, layer.fabricObject, `组${layer.id}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -575,9 +553,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
newIndex: this.newIndex,
|
||||
});
|
||||
|
||||
const targetParent = this.layers.value.find(
|
||||
(layer) => layer.id === this.toParentId
|
||||
);
|
||||
const targetParent = this.layers.value.find((layer) => layer.id === this.toParentId);
|
||||
if (!targetParent) {
|
||||
throw new Error(`找不到目标父图层: ${this.toParentId}`);
|
||||
}
|
||||
@@ -588,9 +564,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
}
|
||||
|
||||
// 从顶级图层数组中移除
|
||||
const rootIndex = this.layers.value.findIndex(
|
||||
(layer) => layer.id === draggedLayer.id
|
||||
);
|
||||
const rootIndex = this.layers.value.findIndex((layer) => layer.id === draggedLayer.id);
|
||||
if (rootIndex !== -1) {
|
||||
this.layers.value.splice(rootIndex, 1);
|
||||
console.log(`🗑️ 从顶级图层数组中移除图层 ${draggedLayer.id}`);
|
||||
@@ -599,20 +573,14 @@ export class CrossLevelMoveCommand extends Command {
|
||||
// 更新图层关系
|
||||
draggedLayer.parentId = this.toParentId;
|
||||
targetParent.children.splice(this.newIndex, 0, draggedLayer);
|
||||
console.log(
|
||||
`📂 将图层 ${draggedLayer.id} 添加到父图层 ${this.toParentId} 的children中`
|
||||
);
|
||||
console.log(`📂 将图层 ${draggedLayer.id} 添加到父图层 ${this.toParentId} 的children中`);
|
||||
|
||||
// 处理fabric对象的层级关系
|
||||
if (draggedLayer.fabricObject && targetParent.fabricObject) {
|
||||
console.log(`🎨 处理fabric对象层级关系`);
|
||||
|
||||
// 从画布中移除
|
||||
this.safeRemoveFromContainer(
|
||||
draggedLayer.fabricObject,
|
||||
this.canvas,
|
||||
"画布"
|
||||
);
|
||||
this.safeRemoveFromContainer(draggedLayer.fabricObject, this.canvas, "画布");
|
||||
|
||||
// 添加到父组
|
||||
this.safeAddToContainer(
|
||||
@@ -635,22 +603,16 @@ export class CrossLevelMoveCommand extends Command {
|
||||
newIndex: this.newIndex,
|
||||
});
|
||||
|
||||
const sourceParent = this.layers.value.find(
|
||||
(layer) => layer.id === this.fromParentId
|
||||
);
|
||||
const sourceParent = this.layers.value.find((layer) => layer.id === this.fromParentId);
|
||||
if (!sourceParent || !sourceParent.children) {
|
||||
throw new Error(`找不到源父图层或其children数组: ${this.fromParentId}`);
|
||||
}
|
||||
|
||||
// 从源父图层的children中移除
|
||||
const childIndex = sourceParent.children.findIndex(
|
||||
(child) => child.id === draggedLayer.id
|
||||
);
|
||||
const childIndex = sourceParent.children.findIndex((child) => child.id === draggedLayer.id);
|
||||
if (childIndex !== -1) {
|
||||
sourceParent.children.splice(childIndex, 1);
|
||||
console.log(
|
||||
`🗑️ 从父图层 ${this.fromParentId} 的children中移除图层 ${draggedLayer.id}`
|
||||
);
|
||||
console.log(`🗑️ 从父图层 ${this.fromParentId} 的children中移除图层 ${draggedLayer.id}`);
|
||||
}
|
||||
|
||||
// 处理fabric对象的层级关系
|
||||
@@ -675,9 +637,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
// 计算在顶级图层中的插入位置
|
||||
const targetIndex = Math.min(this.newIndex, this.layers.value.length);
|
||||
this.layers.value.splice(targetIndex, 0, draggedLayer);
|
||||
console.log(
|
||||
`📂 将图层 ${draggedLayer.id} 添加到顶级图层数组位置 ${targetIndex}`
|
||||
);
|
||||
console.log(`📂 将图层 ${draggedLayer.id} 添加到顶级图层数组位置 ${targetIndex}`);
|
||||
|
||||
console.log("✅ 组内图层移动到顶级完成");
|
||||
}
|
||||
@@ -693,26 +653,18 @@ export class CrossLevelMoveCommand extends Command {
|
||||
newIndex: this.newIndex,
|
||||
});
|
||||
|
||||
const sourceParent = this.layers.value.find(
|
||||
(layer) => layer.id === this.fromParentId
|
||||
);
|
||||
const targetParent = this.layers.value.find(
|
||||
(layer) => layer.id === this.toParentId
|
||||
);
|
||||
const sourceParent = this.layers.value.find((layer) => layer.id === this.fromParentId);
|
||||
const targetParent = this.layers.value.find((layer) => layer.id === this.toParentId);
|
||||
|
||||
if (!sourceParent || !targetParent) {
|
||||
throw new Error("找不到源父图层或目标父图层");
|
||||
}
|
||||
|
||||
// 从源父图层中移除
|
||||
const childIndex = sourceParent.children.findIndex(
|
||||
(child) => child.id === draggedLayer.id
|
||||
);
|
||||
const childIndex = sourceParent.children.findIndex((child) => child.id === draggedLayer.id);
|
||||
if (childIndex !== -1) {
|
||||
sourceParent.children.splice(childIndex, 1);
|
||||
console.log(
|
||||
`🗑️ 从源父图层 ${this.fromParentId} 中移除图层 ${draggedLayer.id}`
|
||||
);
|
||||
console.log(`🗑️ 从源父图层 ${this.fromParentId} 中移除图层 ${draggedLayer.id}`);
|
||||
|
||||
// 从源父组的fabricObject中移除
|
||||
if (draggedLayer.fabricObject && sourceParent.fabricObject) {
|
||||
@@ -726,9 +678,7 @@ export class CrossLevelMoveCommand extends Command {
|
||||
|
||||
// 更新图层的parentId
|
||||
draggedLayer.parentId = this.toParentId;
|
||||
console.log(
|
||||
`🔗 更新图层 ${draggedLayer.id} 的parentId为 ${this.toParentId}`
|
||||
);
|
||||
console.log(`🔗 更新图层 ${draggedLayer.id} 的parentId为 ${this.toParentId}`);
|
||||
|
||||
// 确保目标父图层有children数组
|
||||
if (!targetParent.children) {
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
createLayer,
|
||||
findInChildLayers,
|
||||
LayerType,
|
||||
} from "../utils/layerHelper.js";
|
||||
import { createLayer, findInChildLayers, LayerType } from "../utils/layerHelper.js";
|
||||
import { createRasterizedImage } from "../utils/selectionToImage.js";
|
||||
import { CompositeCommand, Command } from "./Command.js";
|
||||
import { CreateImageLayerCommand } from "./LayerCommands.js";
|
||||
@@ -56,9 +52,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
const selectionObject = this.selectionManager.getSelectionObject();
|
||||
if (selectionObject) {
|
||||
try {
|
||||
this._clonedSelectionObject = await this._cloneObject(
|
||||
selectionObject
|
||||
);
|
||||
this._clonedSelectionObject = await this._cloneObject(selectionObject);
|
||||
console.log("套索抠图:选区对象已克隆保存");
|
||||
} catch (error) {
|
||||
console.error("套索抠图:克隆选区对象失败:", error);
|
||||
@@ -294,10 +288,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
await command.undo();
|
||||
console.log(`✅ 子命令撤销成功: ${command.constructor.name}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`❌ 子命令撤销失败: ${command.constructor.name}`,
|
||||
error
|
||||
);
|
||||
console.error(`❌ 子命令撤销失败: ${command.constructor.name}`, error);
|
||||
// 子命令撤销失败不中断整个撤销过程
|
||||
}
|
||||
}
|
||||
@@ -361,16 +352,11 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
// 递归获取图层及其子图层的所有对象
|
||||
const collectLayerObjects = (currentLayer) => {
|
||||
// 处理图层的fabricObjects
|
||||
if (
|
||||
currentLayer.fabricObjects &&
|
||||
Array.isArray(currentLayer.fabricObjects)
|
||||
) {
|
||||
if (currentLayer.fabricObjects && Array.isArray(currentLayer.fabricObjects)) {
|
||||
currentLayer.fabricObjects.forEach((fabricRef) => {
|
||||
if (fabricRef && fabricRef.id) {
|
||||
// 从画布中查找真实的对象
|
||||
const realObject = canvasObjects.find(
|
||||
(obj) => obj.id === fabricRef.id
|
||||
);
|
||||
const realObject = canvasObjects.find((obj) => obj.id === fabricRef.id);
|
||||
if (realObject && realObject.visible) {
|
||||
objects.push(realObject);
|
||||
}
|
||||
@@ -380,9 +366,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
|
||||
// 处理单个fabricObject(背景图层等)
|
||||
if (currentLayer.fabricObject && currentLayer.fabricObject.id) {
|
||||
const realObject = canvasObjects.find(
|
||||
(obj) => obj.id === currentLayer.fabricObject.id
|
||||
);
|
||||
const realObject = canvasObjects.find((obj) => obj.id === currentLayer.fabricObject.id);
|
||||
if (realObject && realObject.visible) {
|
||||
objects.push(realObject);
|
||||
}
|
||||
@@ -413,11 +397,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
* @returns {String} 抠图结果的DataURL
|
||||
* @private
|
||||
*/
|
||||
async _performCutoutWithRasterized(
|
||||
sourceObjects,
|
||||
selectionObject,
|
||||
selectionBounds
|
||||
) {
|
||||
async _performCutoutWithRasterized(sourceObjects, selectionObject, selectionBounds) {
|
||||
try {
|
||||
console.log("=== 开始使用createRasterizedImage执行抠图 ===");
|
||||
console.log(`源对象数量: ${sourceObjects.length}`);
|
||||
@@ -456,10 +436,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
|
||||
// 如果createRasterizedImage失败,回退到原始方法
|
||||
console.log("⚠️ 回退到原始抠图方法...");
|
||||
return await this._performCutout(
|
||||
{ fabricObjects: sourceObjects },
|
||||
selectionObject
|
||||
);
|
||||
return await this._performCutout({ fabricObjects: sourceObjects }, selectionObject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,9 +467,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
|
||||
try {
|
||||
// 收集源图层中的可见对象
|
||||
const visibleObjects = sourceLayer.fabricObjects.filter(
|
||||
(obj) => obj.visible
|
||||
);
|
||||
const visibleObjects = sourceLayer.fabricObjects.filter((obj) => obj.visible);
|
||||
|
||||
if (visibleObjects.length === 0) {
|
||||
throw new Error("源图层没有可见对象");
|
||||
@@ -545,10 +520,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
let highResolutionScale = 1;
|
||||
if (this.highResolutionEnabled) {
|
||||
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||
highResolutionScale = Math.max(
|
||||
this.baseResolutionScale,
|
||||
devicePixelRatio * 2
|
||||
);
|
||||
highResolutionScale = Math.max(this.baseResolutionScale, devicePixelRatio * 2);
|
||||
}
|
||||
|
||||
// 创建用于导出的高分辨率canvas
|
||||
@@ -559,12 +531,8 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
colorSpace: "srgb",
|
||||
});
|
||||
|
||||
const actualWidth = Math.round(
|
||||
renderBounds.width * highResolutionScale
|
||||
);
|
||||
const actualHeight = Math.round(
|
||||
renderBounds.height * highResolutionScale
|
||||
);
|
||||
const actualWidth = Math.round(renderBounds.width * highResolutionScale);
|
||||
const actualHeight = Math.round(renderBounds.height * highResolutionScale);
|
||||
|
||||
exportCanvas.width = actualWidth;
|
||||
exportCanvas.height = actualHeight;
|
||||
@@ -773,17 +741,14 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
}
|
||||
});
|
||||
} else if (objectType === "polygon") {
|
||||
fabric.Polygon.fromObject(
|
||||
this.serializedSelectionObject,
|
||||
(polygon) => {
|
||||
if (polygon) {
|
||||
console.log("多边形选区对象反序列化成功");
|
||||
resolve(polygon);
|
||||
} else {
|
||||
reject(new Error("多边形选区对象反序列化失败"));
|
||||
}
|
||||
fabric.Polygon.fromObject(this.serializedSelectionObject, (polygon) => {
|
||||
if (polygon) {
|
||||
console.log("多边形选区对象反序列化成功");
|
||||
resolve(polygon);
|
||||
} else {
|
||||
reject(new Error("多边形选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
} else if (objectType === "rect") {
|
||||
fabric.Rect.fromObject(this.serializedSelectionObject, (rect) => {
|
||||
if (rect) {
|
||||
@@ -794,30 +759,24 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
}
|
||||
});
|
||||
} else if (objectType === "ellipse" || objectType === "circle") {
|
||||
fabric.Ellipse.fromObject(
|
||||
this.serializedSelectionObject,
|
||||
(ellipse) => {
|
||||
if (ellipse) {
|
||||
console.log("椭圆选区对象反序列化成功");
|
||||
resolve(ellipse);
|
||||
} else {
|
||||
reject(new Error("椭圆选区对象反序列化失败"));
|
||||
}
|
||||
fabric.Ellipse.fromObject(this.serializedSelectionObject, (ellipse) => {
|
||||
if (ellipse) {
|
||||
console.log("椭圆选区对象反序列化成功");
|
||||
resolve(ellipse);
|
||||
} else {
|
||||
reject(new Error("椭圆选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// 通用对象反序列化
|
||||
fabric.util.enlivenObjects(
|
||||
[this.serializedSelectionObject],
|
||||
(objects) => {
|
||||
if (objects && objects.length > 0) {
|
||||
console.log("通用选区对象反序列化成功");
|
||||
resolve(objects[0]);
|
||||
} else {
|
||||
reject(new Error("通用选区对象反序列化失败"));
|
||||
}
|
||||
fabric.util.enlivenObjects([this.serializedSelectionObject], (objects) => {
|
||||
if (objects && objects.length > 0) {
|
||||
console.log("通用选区对象反序列化成功");
|
||||
resolve(objects[0]);
|
||||
} else {
|
||||
reject(new Error("通用选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
createLayer,
|
||||
findInChildLayers,
|
||||
LayerType,
|
||||
} from "../utils/layerHelper.js";
|
||||
import { createLayer, findInChildLayers, LayerType } from "../utils/layerHelper.js";
|
||||
import { createRasterizedImage } from "../utils/selectionToImage.js";
|
||||
import { CompositeCommand, Command } from "./Command.js";
|
||||
import { CreateImageLayerCommand } from "./LayerCommands.js";
|
||||
@@ -59,9 +55,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
const selectionObject = this.selectionManager.getSelectionObject();
|
||||
if (selectionObject) {
|
||||
try {
|
||||
this._clonedSelectionObject = await this._cloneObject(
|
||||
selectionObject
|
||||
);
|
||||
this._clonedSelectionObject = await this._cloneObject(selectionObject);
|
||||
console.log("剪切选区:选区对象已克隆保存");
|
||||
} catch (error) {
|
||||
console.error("剪切选区:克隆选区对象失败:", error);
|
||||
@@ -132,11 +126,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
}
|
||||
|
||||
// 步骤2: 对原图层进行栅格化处理,移除选区内容
|
||||
await this._rasterizeOriginalLayerWithCutout(
|
||||
sourceLayer,
|
||||
sourceObjects,
|
||||
selectionObject
|
||||
);
|
||||
await this._rasterizeOriginalLayerWithCutout(sourceLayer, sourceObjects, selectionObject);
|
||||
|
||||
// 步骤3: 创建图像图层命令
|
||||
const createImageLayerCmd = new CreateImageLayerCommand({
|
||||
@@ -246,10 +236,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
console.log(`✅ 子命令撤销成功: ${command.constructor.name}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`❌ 子命令撤销失败: ${command.constructor.name}`,
|
||||
error
|
||||
);
|
||||
console.error(`❌ 子命令撤销失败: ${command.constructor.name}`, error);
|
||||
// 子命令撤销失败不中断整个撤销过程
|
||||
}
|
||||
}
|
||||
@@ -313,17 +300,14 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
await this._restoreObjectsFromBackup(sourceLayer);
|
||||
} else {
|
||||
// 备用方案:恢复原始的fabricObjects数组
|
||||
sourceLayer.fabricObjects =
|
||||
this.originalLayerBackup.fabricObjects || [];
|
||||
sourceLayer.fabricObjects = this.originalLayerBackup.fabricObjects || [];
|
||||
|
||||
if (sourceLayer.fabricObjects.length > 0) {
|
||||
await this._restoreLayerObjects(sourceLayer);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`✅ 原图层状态恢复完成,恢复了 ${sourceLayer.fabricObjects.length} 个对象`
|
||||
);
|
||||
console.log(`✅ 原图层状态恢复完成,恢复了 ${sourceLayer.fabricObjects.length} 个对象`);
|
||||
} catch (error) {
|
||||
console.error("恢复原图层状态失败:", error);
|
||||
throw error;
|
||||
@@ -337,78 +321,68 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
*/
|
||||
async _restoreObjectsFromBackup(layer) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (
|
||||
!this.originalLayerObjectsData ||
|
||||
this.originalLayerObjectsData.length === 0
|
||||
) {
|
||||
if (!this.originalLayerObjectsData || this.originalLayerObjectsData.length === 0) {
|
||||
console.warn("没有对象备份数据");
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(
|
||||
`开始从备份恢复 ${this.originalLayerObjectsData.length} 个对象...`
|
||||
);
|
||||
console.log(`开始从备份恢复 ${this.originalLayerObjectsData.length} 个对象...`);
|
||||
|
||||
// 使用fabric.util.enlivenObjects重建对象
|
||||
fabric.util.enlivenObjects(
|
||||
this.originalLayerObjectsData,
|
||||
(restoredObjects) => {
|
||||
try {
|
||||
let successCount = 0;
|
||||
fabric.util.enlivenObjects(this.originalLayerObjectsData, (restoredObjects) => {
|
||||
try {
|
||||
let successCount = 0;
|
||||
|
||||
restoredObjects.forEach((obj, index) => {
|
||||
if (obj) {
|
||||
// 确保对象有正确的属性
|
||||
obj.set({
|
||||
layerId: layer.id,
|
||||
layerName: layer.name,
|
||||
selectable: true,
|
||||
evented: true,
|
||||
visible: true,
|
||||
});
|
||||
restoredObjects.forEach((obj, index) => {
|
||||
if (obj) {
|
||||
// 确保对象有正确的属性
|
||||
obj.set({
|
||||
layerId: layer.id,
|
||||
layerName: layer.name,
|
||||
selectable: true,
|
||||
evented: true,
|
||||
visible: true,
|
||||
});
|
||||
|
||||
// 添加到画布
|
||||
this.canvas.add(obj);
|
||||
// 添加到画布
|
||||
this.canvas.add(obj);
|
||||
|
||||
// 添加到图层的fabricObjects数组
|
||||
layer.fabricObjects.push(
|
||||
obj.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"layerName",
|
||||
"parentId",
|
||||
"selectable",
|
||||
"evented",
|
||||
"visible",
|
||||
])
|
||||
);
|
||||
// 添加到图层的fabricObjects数组
|
||||
layer.fabricObjects.push(
|
||||
obj.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"layerName",
|
||||
"parentId",
|
||||
"selectable",
|
||||
"evented",
|
||||
"visible",
|
||||
])
|
||||
);
|
||||
|
||||
successCount++;
|
||||
console.log(
|
||||
`恢复对象 ${index + 1}/${restoredObjects.length}: ${
|
||||
obj.id || obj.type
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
console.warn(`对象 ${index + 1} 恢复失败`);
|
||||
}
|
||||
});
|
||||
successCount++;
|
||||
console.log(
|
||||
`恢复对象 ${index + 1}/${restoredObjects.length}: ${obj.id || obj.type}`
|
||||
);
|
||||
} else {
|
||||
console.warn(`对象 ${index + 1} 恢复失败`);
|
||||
}
|
||||
});
|
||||
|
||||
// 重新渲染画布
|
||||
this.canvas.renderAll();
|
||||
// 重新渲染画布
|
||||
this.canvas.renderAll();
|
||||
|
||||
console.log(
|
||||
`✅ 成功恢复了 ${successCount}/${this.originalLayerObjectsData.length} 个对象`
|
||||
);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
console.error("处理恢复的对象时出错:", error);
|
||||
reject(error);
|
||||
}
|
||||
console.log(
|
||||
`✅ 成功恢复了 ${successCount}/${this.originalLayerObjectsData.length} 个对象`
|
||||
);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
console.error("处理恢复的对象时出错:", error);
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("恢复对象时出错:", error);
|
||||
reject(error);
|
||||
@@ -474,11 +448,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
* @returns {fabric.Image} 抠图结果的fabric图像对象
|
||||
* @private
|
||||
*/
|
||||
async _performCutoutWithRasterized(
|
||||
sourceObjects,
|
||||
selectionObject,
|
||||
selectionBounds
|
||||
) {
|
||||
async _performCutoutWithRasterized(sourceObjects, selectionObject, selectionBounds) {
|
||||
try {
|
||||
console.log("=== 开始使用createRasterizedImage执行剪切抠图 ===");
|
||||
console.log(`源对象数量: ${sourceObjects.length}`);
|
||||
@@ -488,10 +458,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
let scaleFactor = this.baseResolutionScale;
|
||||
if (this.highResolutionEnabled) {
|
||||
const currentZoom = this.canvas.getZoom?.() || 1;
|
||||
scaleFactor = Math.max(
|
||||
scaleFactor || this.canvas?.getRetinaScaling?.(),
|
||||
currentZoom
|
||||
);
|
||||
scaleFactor = Math.max(scaleFactor || this.canvas?.getRetinaScaling?.(), currentZoom);
|
||||
scaleFactor = Math.min(scaleFactor, 3);
|
||||
}
|
||||
|
||||
@@ -535,15 +502,10 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
// 递归获取图层及其子图层的所有对象
|
||||
const collectLayerObjects = (currentLayer) => {
|
||||
// 处理图层的fabricObjects
|
||||
if (
|
||||
currentLayer.fabricObjects &&
|
||||
Array.isArray(currentLayer.fabricObjects)
|
||||
) {
|
||||
if (currentLayer.fabricObjects && Array.isArray(currentLayer.fabricObjects)) {
|
||||
currentLayer.fabricObjects.forEach((fabricObj) => {
|
||||
if (fabricObj && fabricObj.id) {
|
||||
const realObject = canvasObjects.find(
|
||||
(canvasObj) => canvasObj.id === fabricObj.id
|
||||
);
|
||||
const realObject = canvasObjects.find((canvasObj) => canvasObj.id === fabricObj.id);
|
||||
if (realObject && realObject.visible !== false) {
|
||||
objects.push(realObject);
|
||||
}
|
||||
@@ -649,17 +611,14 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
}
|
||||
});
|
||||
} else if (objectType === "polygon") {
|
||||
fabric.Polygon.fromObject(
|
||||
this.serializedSelectionObject,
|
||||
(polygon) => {
|
||||
if (polygon) {
|
||||
console.log("多边形选区对象反序列化成功");
|
||||
resolve(polygon);
|
||||
} else {
|
||||
reject(new Error("多边形选区对象反序列化失败"));
|
||||
}
|
||||
fabric.Polygon.fromObject(this.serializedSelectionObject, (polygon) => {
|
||||
if (polygon) {
|
||||
console.log("多边形选区对象反序列化成功");
|
||||
resolve(polygon);
|
||||
} else {
|
||||
reject(new Error("多边形选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
} else if (objectType === "rect") {
|
||||
fabric.Rect.fromObject(this.serializedSelectionObject, (rect) => {
|
||||
if (rect) {
|
||||
@@ -670,30 +629,24 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
}
|
||||
});
|
||||
} else if (objectType === "ellipse" || objectType === "circle") {
|
||||
fabric.Ellipse.fromObject(
|
||||
this.serializedSelectionObject,
|
||||
(ellipse) => {
|
||||
if (ellipse) {
|
||||
console.log("椭圆选区对象反序列化成功");
|
||||
resolve(ellipse);
|
||||
} else {
|
||||
reject(new Error("椭圆选区对象反序列化失败"));
|
||||
}
|
||||
fabric.Ellipse.fromObject(this.serializedSelectionObject, (ellipse) => {
|
||||
if (ellipse) {
|
||||
console.log("椭圆选区对象反序列化成功");
|
||||
resolve(ellipse);
|
||||
} else {
|
||||
reject(new Error("椭圆选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// 通用对象反序列化
|
||||
fabric.util.enlivenObjects(
|
||||
[this.serializedSelectionObject],
|
||||
(objects) => {
|
||||
if (objects && objects.length > 0) {
|
||||
console.log("通用选区对象反序列化成功");
|
||||
resolve(objects[0]);
|
||||
} else {
|
||||
reject(new Error("通用选区对象反序列化失败"));
|
||||
}
|
||||
fabric.util.enlivenObjects([this.serializedSelectionObject], (objects) => {
|
||||
if (objects && objects.length > 0) {
|
||||
console.log("通用选区对象反序列化成功");
|
||||
resolve(objects[0]);
|
||||
} else {
|
||||
reject(new Error("通用选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -761,9 +714,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
|
||||
this.originalLayerRasterized = false; // 标记原图层是否已栅格化
|
||||
|
||||
console.log(
|
||||
`✅ 原图层状态已备份,对象数量: ${this.originalLayerObjectsData.length}`
|
||||
);
|
||||
console.log(`✅ 原图层状态已备份,对象数量: ${this.originalLayerObjectsData.length}`);
|
||||
} catch (error) {
|
||||
console.error("备份原图层状态失败:", error);
|
||||
throw error;
|
||||
@@ -777,11 +728,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
|
||||
* @param {Object} selectionObject 选区对象
|
||||
* @private
|
||||
*/
|
||||
async _rasterizeOriginalLayerWithCutout(
|
||||
sourceLayer,
|
||||
sourceObjects,
|
||||
selectionObject
|
||||
) {
|
||||
async _rasterizeOriginalLayerWithCutout(sourceLayer, sourceObjects, selectionObject) {
|
||||
try {
|
||||
console.log("=== 开始对原图层进行栅格化处理,移除选区内容 ===");
|
||||
|
||||
|
||||
@@ -92,9 +92,6 @@ export class EraserCommand extends Command {
|
||||
if (!this.layerManager) return;
|
||||
|
||||
const canvasObjects = this.canvas.getObjects();
|
||||
restoreObjectLayerAssociations(
|
||||
this.layerManager?.layers?.value,
|
||||
canvasObjects
|
||||
);
|
||||
restoreObjectLayerAssociations(this.layerManager?.layers?.value, canvasObjects);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { generateId } from "../utils/helper";
|
||||
import {
|
||||
createLayer,
|
||||
findLayerRecursively,
|
||||
LayerType,
|
||||
OperationType,
|
||||
} from "../utils/layerHelper";
|
||||
import { createLayer, findLayerRecursively, LayerType, OperationType } from "../utils/layerHelper";
|
||||
import { Command } from "./Command";
|
||||
import {
|
||||
findObjectById,
|
||||
@@ -33,14 +28,12 @@ export class MergeGroupLayerCommand extends Command {
|
||||
this.originalObjects = [...this.canvas.getObjects()];
|
||||
this.flattenedLayer = null;
|
||||
this.flattenedLayerId =
|
||||
generateId("flattened_") ||
|
||||
`flattened_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
generateId("flattened_") || `flattened_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
|
||||
this.existingGroupId = null; // 用于查找现有组对象
|
||||
// 组对象相关
|
||||
this.newGroupId =
|
||||
generateId("group") ||
|
||||
`group_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
generateId("group") || `group_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
@@ -172,15 +165,11 @@ export class MergeGroupLayerCommand extends Command {
|
||||
});
|
||||
|
||||
// 获取源图层在数组中的索引
|
||||
const sourceIndex = this.layers.value.findIndex(
|
||||
(l) => l.id === this.layerId
|
||||
);
|
||||
const sourceIndex = this.layers.value.findIndex((l) => l.id === this.layerId);
|
||||
|
||||
// 移除所有相关图层
|
||||
const layerIdsToRemove = layersToFlatten.map((layer) => layer.id);
|
||||
this.layers.value = this.layers.value.filter(
|
||||
(layer) => !layerIdsToRemove.includes(layer.id)
|
||||
);
|
||||
this.layers.value = this.layers.value.filter((layer) => !layerIdsToRemove.includes(layer.id));
|
||||
|
||||
// 在原位置插入展平后的图层
|
||||
this.layers.value.splice(sourceIndex, 0, this.flattenedLayer);
|
||||
@@ -202,11 +191,7 @@ export class MergeGroupLayerCommand extends Command {
|
||||
}
|
||||
|
||||
async undo() {
|
||||
if (
|
||||
!this.flattenedLayer ||
|
||||
!this.originalLayers ||
|
||||
!this.originalObjectStates
|
||||
) {
|
||||
if (!this.flattenedLayer || !this.originalLayers || !this.originalObjectStates) {
|
||||
console.warn("没有可撤销的数据");
|
||||
return;
|
||||
}
|
||||
@@ -324,10 +309,7 @@ export class MergeGroupLayerCommand extends Command {
|
||||
groupObjects.forEach((obj) => {
|
||||
try {
|
||||
// 计算对象的绝对位置
|
||||
const absolutePosition = this._calculateObjectAbsolutePosition(
|
||||
obj,
|
||||
groupObject
|
||||
);
|
||||
const absolutePosition = this._calculateObjectAbsolutePosition(obj, groupObject);
|
||||
|
||||
// 使用removeWithUpdate移除对象,这会自动恢复对象的独立状态
|
||||
groupObject.removeWithUpdate(obj);
|
||||
@@ -382,10 +364,7 @@ export class MergeGroupLayerCommand extends Command {
|
||||
const objectPoint = new fabric.Point(obj.left || 0, obj.top || 0);
|
||||
|
||||
// 应用组的变换矩阵计算绝对位置
|
||||
const absolutePoint = fabric.util.transformPoint(
|
||||
objectPoint,
|
||||
groupTransform
|
||||
);
|
||||
const absolutePoint = fabric.util.transformPoint(objectPoint, groupTransform);
|
||||
|
||||
// 计算缩放比例
|
||||
const totalScaleX = (group.scaleX || 1) * (obj.scaleX || 1);
|
||||
@@ -483,9 +462,7 @@ export class MergeGroupLayerCommand extends Command {
|
||||
canvasObj.layerId = layer.id;
|
||||
canvasObj.layerName = layer.name;
|
||||
|
||||
console.log(
|
||||
`🔗 恢复对象 ${canvasObj.id} 与图层 ${layer.name} 的关联`
|
||||
);
|
||||
console.log(`🔗 恢复对象 ${canvasObj.id} 与图层 ${layer.name} 的关联`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import {
|
||||
createLayer,
|
||||
findInChildLayers,
|
||||
LayerType,
|
||||
} from "../utils/layerHelper.js";
|
||||
import { createLayer, findInChildLayers, LayerType } from "../utils/layerHelper.js";
|
||||
import { createRasterizedImage } from "../utils/selectionToImage.js";
|
||||
import { CompositeCommand, Command } from "./Command.js";
|
||||
import {
|
||||
CreateImageLayerCommand,
|
||||
RemoveLayerCommand,
|
||||
} from "./LayerCommands.js";
|
||||
import { CreateImageLayerCommand, RemoveLayerCommand } from "./LayerCommands.js";
|
||||
import { fabric } from "fabric-with-all";
|
||||
import { generateId } from "../utils/helper.js";
|
||||
|
||||
@@ -65,9 +58,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
const selectionObject = this.selectionManager.getSelectionObject();
|
||||
if (selectionObject) {
|
||||
try {
|
||||
this._clonedSelectionObject = await this._cloneObject(
|
||||
selectionObject
|
||||
);
|
||||
this._clonedSelectionObject = await this._cloneObject(selectionObject);
|
||||
console.log("套索抠图:选区对象已克隆保存");
|
||||
} catch (error) {
|
||||
console.error("套索抠图:克隆选区对象失败:", error);
|
||||
@@ -103,14 +94,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
const sourceObjects = this._getLayerObjects(activeLayer);
|
||||
this.originalCanvasObjects = sourceObjects; // 保存真实对象引用
|
||||
this.originalFabricObjects = sourceObjects.map((obj) =>
|
||||
obj.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"layerName",
|
||||
"parentId",
|
||||
"type",
|
||||
"custom",
|
||||
])
|
||||
obj.toObject(["id", "layerId", "layerName", "parentId", "type", "custom"])
|
||||
);
|
||||
|
||||
console.log(
|
||||
@@ -353,10 +337,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
await command.undo();
|
||||
console.log(`✅ 子命令撤销成功: ${command.constructor.name}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`❌ 子命令撤销失败: ${command.constructor.name}`,
|
||||
error
|
||||
);
|
||||
console.error(`❌ 子命令撤销失败: ${command.constructor.name}`, error);
|
||||
// 子命令撤销失败不中断整个撤销过程
|
||||
}
|
||||
}
|
||||
@@ -433,16 +414,11 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
// 递归获取图层及其子图层的所有对象
|
||||
const collectLayerObjects = (currentLayer) => {
|
||||
// 处理图层的fabricObjects
|
||||
if (
|
||||
currentLayer.fabricObjects &&
|
||||
Array.isArray(currentLayer.fabricObjects)
|
||||
) {
|
||||
if (currentLayer.fabricObjects && Array.isArray(currentLayer.fabricObjects)) {
|
||||
currentLayer.fabricObjects.forEach((fabricRef) => {
|
||||
if (fabricRef && fabricRef.id) {
|
||||
// 从画布中查找真实的对象
|
||||
const realObject = canvasObjects.find(
|
||||
(obj) => obj.id === fabricRef.id
|
||||
);
|
||||
const realObject = canvasObjects.find((obj) => obj.id === fabricRef.id);
|
||||
if (realObject && realObject.visible) {
|
||||
objects.push(realObject);
|
||||
}
|
||||
@@ -452,9 +428,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
// 处理单个fabricObject(背景图层等)
|
||||
if (currentLayer.fabricObject && currentLayer.fabricObject.id) {
|
||||
const realObject = canvasObjects.find(
|
||||
(obj) => obj.id === currentLayer.fabricObject.id
|
||||
);
|
||||
const realObject = canvasObjects.find((obj) => obj.id === currentLayer.fabricObject.id);
|
||||
if (realObject && realObject.visible) {
|
||||
objects.push(realObject);
|
||||
}
|
||||
@@ -485,11 +459,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
* @returns {String} 抠图结果的DataURL
|
||||
* @private
|
||||
*/
|
||||
async _performCutoutWithRasterized(
|
||||
sourceObjects,
|
||||
selectionObject,
|
||||
selectionBounds
|
||||
) {
|
||||
async _performCutoutWithRasterized(sourceObjects, selectionObject, selectionBounds) {
|
||||
try {
|
||||
console.log("=== 开始使用createRasterizedImage执行抠图 ===");
|
||||
console.log(`源对象数量: ${sourceObjects.length}`);
|
||||
@@ -528,10 +498,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
// 如果createRasterizedImage失败,回退到原始方法
|
||||
console.log("⚠️ 回退到原始抠图方法...");
|
||||
return await this._performCutout(
|
||||
{ fabricObjects: sourceObjects },
|
||||
selectionObject
|
||||
);
|
||||
return await this._performCutout({ fabricObjects: sourceObjects }, selectionObject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,9 +529,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
try {
|
||||
// 收集源图层中的可见对象
|
||||
const visibleObjects = sourceLayer.fabricObjects.filter(
|
||||
(obj) => obj.visible
|
||||
);
|
||||
const visibleObjects = sourceLayer.fabricObjects.filter((obj) => obj.visible);
|
||||
|
||||
if (visibleObjects.length === 0) {
|
||||
throw new Error("源图层没有可见对象");
|
||||
@@ -617,10 +582,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
let highResolutionScale = 1;
|
||||
if (this.highResolutionEnabled) {
|
||||
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||
highResolutionScale = Math.max(
|
||||
this.baseResolutionScale,
|
||||
devicePixelRatio * 2
|
||||
);
|
||||
highResolutionScale = Math.max(this.baseResolutionScale, devicePixelRatio * 2);
|
||||
}
|
||||
|
||||
// 创建用于导出的高分辨率canvas
|
||||
@@ -631,12 +593,8 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
colorSpace: "srgb",
|
||||
});
|
||||
|
||||
const actualWidth = Math.round(
|
||||
renderBounds.width * highResolutionScale
|
||||
);
|
||||
const actualHeight = Math.round(
|
||||
renderBounds.height * highResolutionScale
|
||||
);
|
||||
const actualWidth = Math.round(renderBounds.width * highResolutionScale);
|
||||
const actualHeight = Math.round(renderBounds.height * highResolutionScale);
|
||||
|
||||
exportCanvas.width = actualWidth;
|
||||
exportCanvas.height = actualHeight;
|
||||
@@ -845,17 +803,14 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
}
|
||||
});
|
||||
} else if (objectType === "polygon") {
|
||||
fabric.Polygon.fromObject(
|
||||
this.serializedSelectionObject,
|
||||
(polygon) => {
|
||||
if (polygon) {
|
||||
console.log("多边形选区对象反序列化成功");
|
||||
resolve(polygon);
|
||||
} else {
|
||||
reject(new Error("多边形选区对象反序列化失败"));
|
||||
}
|
||||
fabric.Polygon.fromObject(this.serializedSelectionObject, (polygon) => {
|
||||
if (polygon) {
|
||||
console.log("多边形选区对象反序列化成功");
|
||||
resolve(polygon);
|
||||
} else {
|
||||
reject(new Error("多边形选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
} else if (objectType === "rect") {
|
||||
fabric.Rect.fromObject(this.serializedSelectionObject, (rect) => {
|
||||
if (rect) {
|
||||
@@ -866,30 +821,24 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
}
|
||||
});
|
||||
} else if (objectType === "ellipse" || objectType === "circle") {
|
||||
fabric.Ellipse.fromObject(
|
||||
this.serializedSelectionObject,
|
||||
(ellipse) => {
|
||||
if (ellipse) {
|
||||
console.log("椭圆选区对象反序列化成功");
|
||||
resolve(ellipse);
|
||||
} else {
|
||||
reject(new Error("椭圆选区对象反序列化失败"));
|
||||
}
|
||||
fabric.Ellipse.fromObject(this.serializedSelectionObject, (ellipse) => {
|
||||
if (ellipse) {
|
||||
console.log("椭圆选区对象反序列化成功");
|
||||
resolve(ellipse);
|
||||
} else {
|
||||
reject(new Error("椭圆选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// 通用对象反序列化
|
||||
fabric.util.enlivenObjects(
|
||||
[this.serializedSelectionObject],
|
||||
(objects) => {
|
||||
if (objects && objects.length > 0) {
|
||||
console.log("通用选区对象反序列化成功");
|
||||
resolve(objects[0]);
|
||||
} else {
|
||||
reject(new Error("通用选区对象反序列化失败"));
|
||||
}
|
||||
fabric.util.enlivenObjects([this.serializedSelectionObject], (objects) => {
|
||||
if (objects && objects.length > 0) {
|
||||
console.log("通用选区对象反序列化成功");
|
||||
resolve(objects[0]);
|
||||
} else {
|
||||
reject(new Error("通用选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -913,11 +862,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
// 1. 恢复图层到原位置
|
||||
if (this.originalLayerIndex !== -1) {
|
||||
this.layerManager.layers.value.splice(
|
||||
this.originalLayerIndex,
|
||||
0,
|
||||
this.originalLayer
|
||||
);
|
||||
this.layerManager.layers.value.splice(this.originalLayerIndex, 0, this.originalLayer);
|
||||
} else {
|
||||
// 如果没有保存索引,添加到末尾
|
||||
this.layerManager.layers.value.push(this.originalLayer);
|
||||
@@ -925,9 +870,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
// 2. 恢复fabric对象到画布
|
||||
if (this.originalFabricObjects.length > 0) {
|
||||
console.log(
|
||||
`↩️ 恢复 ${this.originalFabricObjects.length} 个fabric对象`
|
||||
);
|
||||
console.log(`↩️ 恢复 ${this.originalFabricObjects.length} 个fabric对象`);
|
||||
|
||||
// 使用fabric.util.enlivenObjects批量反序列化对象
|
||||
await new Promise((resolve, reject) => {
|
||||
@@ -1076,12 +1019,7 @@ export class ClearSelectionCommand extends Command {
|
||||
// 序列化选区对象和相关状态
|
||||
this.originalSelectionState = {
|
||||
// 选区对象的序列化数据
|
||||
selectionObjectData: selectionObject.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"layerName",
|
||||
"parentId",
|
||||
]),
|
||||
selectionObjectData: selectionObject.toObject(["id", "layerId", "layerName", "parentId"]),
|
||||
// 选区路径数据
|
||||
selectionPath: this.selectionManager.getSelectionPath(),
|
||||
// 羽化值
|
||||
@@ -1144,13 +1082,8 @@ export class ClearSelectionCommand extends Command {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
selectionObjectData,
|
||||
featherAmount,
|
||||
selectionStyle,
|
||||
position,
|
||||
managerState,
|
||||
} = this.originalSelectionState;
|
||||
const { selectionObjectData, featherAmount, selectionStyle, position, managerState } =
|
||||
this.originalSelectionState;
|
||||
|
||||
// 根据选区对象类型进行反序列化
|
||||
const objectType = selectionObjectData.type;
|
||||
@@ -1196,9 +1129,7 @@ export class ClearSelectionCommand extends Command {
|
||||
|
||||
// 恢复阴影(羽化效果)
|
||||
if (selectionStyle.shadow) {
|
||||
restoredObject.shadow = new fabric.Shadow(
|
||||
selectionStyle.shadow
|
||||
);
|
||||
restoredObject.shadow = new fabric.Shadow(selectionStyle.shadow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1283,9 +1214,7 @@ export class ClearSelectionCommand extends Command {
|
||||
// 验证基本属性
|
||||
const originalId = this.originalSelectionState.selectionId;
|
||||
if (currentSelection.id !== originalId) {
|
||||
console.warn(
|
||||
`选区ID不匹配: 期望 ${originalId}, 实际 ${currentSelection.id}`
|
||||
);
|
||||
console.warn(`选区ID不匹配: 期望 ${originalId}, 实际 ${currentSelection.id}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1293,9 +1222,7 @@ export class ClearSelectionCommand extends Command {
|
||||
const currentFeather = this.selectionManager.getFeatherAmount();
|
||||
const originalFeather = this.originalSelectionState.featherAmount;
|
||||
if (currentFeather !== originalFeather) {
|
||||
console.warn(
|
||||
`羽化值不匹配: 期望 ${originalFeather}, 实际 ${currentFeather}`
|
||||
);
|
||||
console.warn(`羽化值不匹配: 期望 ${originalFeather}, 实际 ${currentFeather}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
import {
|
||||
createLayer,
|
||||
findInChildLayers,
|
||||
LayerType,
|
||||
OperationType,
|
||||
} from "../utils/layerHelper.js";
|
||||
import { createLayer, findInChildLayers, LayerType, OperationType } from "../utils/layerHelper.js";
|
||||
import { createRasterizedImage } from "../utils/selectionToImage.js";
|
||||
import { CompositeCommand, Command } from "./Command.js";
|
||||
import {
|
||||
CreateImageLayerCommand,
|
||||
RemoveLayerCommand,
|
||||
} from "./LayerCommands.js";
|
||||
import { CreateImageLayerCommand, RemoveLayerCommand } from "./LayerCommands.js";
|
||||
import { fabric } from "fabric-with-all";
|
||||
import { generateId } from "../utils/helper.js";
|
||||
import { ToolCommand } from "./ToolCommands.js";
|
||||
@@ -69,9 +61,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
const selectionObject = this.selectionManager.getSelectionObject();
|
||||
if (selectionObject) {
|
||||
try {
|
||||
this._clonedSelectionObject = await this._cloneObject(
|
||||
selectionObject
|
||||
);
|
||||
this._clonedSelectionObject = await this._cloneObject(selectionObject);
|
||||
console.log("套索抠图:选区对象已克隆保存");
|
||||
} catch (error) {
|
||||
console.error("套索抠图:克隆选区对象失败:", error);
|
||||
@@ -107,14 +97,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
const sourceObjects = this._getLayerObjects(activeLayer);
|
||||
this.originalCanvasObjects = sourceObjects; // 保存真实对象引用
|
||||
this.originalFabricObjects = sourceObjects.map((obj) =>
|
||||
obj.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"layerName",
|
||||
"parentId",
|
||||
"type",
|
||||
"custom",
|
||||
])
|
||||
obj.toObject(["id", "layerId", "layerName", "parentId", "type", "custom"])
|
||||
);
|
||||
|
||||
console.log(
|
||||
@@ -385,10 +368,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
await command.undo();
|
||||
console.log(`✅ 子命令撤销成功: ${command.constructor.name}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`❌ 子命令撤销失败: ${command.constructor.name}`,
|
||||
error
|
||||
);
|
||||
console.error(`❌ 子命令撤销失败: ${command.constructor.name}`, error);
|
||||
// 子命令撤销失败不中断整个撤销过程
|
||||
}
|
||||
}
|
||||
@@ -465,16 +445,11 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
// 递归获取图层及其子图层的所有对象
|
||||
const collectLayerObjects = (currentLayer) => {
|
||||
// 处理图层的fabricObjects
|
||||
if (
|
||||
currentLayer.fabricObjects &&
|
||||
Array.isArray(currentLayer.fabricObjects)
|
||||
) {
|
||||
if (currentLayer.fabricObjects && Array.isArray(currentLayer.fabricObjects)) {
|
||||
currentLayer.fabricObjects.forEach((fabricRef) => {
|
||||
if (fabricRef && fabricRef.id) {
|
||||
// 从画布中查找真实的对象
|
||||
const realObject = canvasObjects.find(
|
||||
(obj) => obj.id === fabricRef.id
|
||||
);
|
||||
const realObject = canvasObjects.find((obj) => obj.id === fabricRef.id);
|
||||
if (realObject && realObject.visible) {
|
||||
objects.push(realObject);
|
||||
}
|
||||
@@ -484,9 +459,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
// 处理单个fabricObject(背景图层等)
|
||||
if (currentLayer.fabricObject && currentLayer.fabricObject.id) {
|
||||
const realObject = canvasObjects.find(
|
||||
(obj) => obj.id === currentLayer.fabricObject.id
|
||||
);
|
||||
const realObject = canvasObjects.find((obj) => obj.id === currentLayer.fabricObject.id);
|
||||
if (realObject && realObject.visible) {
|
||||
objects.push(realObject);
|
||||
}
|
||||
@@ -517,11 +490,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
* @returns {String} 抠图结果的DataURL
|
||||
* @private
|
||||
*/
|
||||
async _performCutoutWithRasterized(
|
||||
sourceObjects,
|
||||
selectionObject,
|
||||
selectionBounds
|
||||
) {
|
||||
async _performCutoutWithRasterized(sourceObjects, selectionObject, selectionBounds) {
|
||||
try {
|
||||
console.log("=== 开始使用createRasterizedImage执行抠图 ===");
|
||||
console.log(`源对象数量: ${sourceObjects.length}`);
|
||||
@@ -560,10 +529,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
// 如果createRasterizedImage失败,回退到原始方法
|
||||
console.log("⚠️ 回退到原始抠图方法...");
|
||||
return await this._performCutout(
|
||||
{ fabricObjects: sourceObjects },
|
||||
selectionObject
|
||||
);
|
||||
return await this._performCutout({ fabricObjects: sourceObjects }, selectionObject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,9 +560,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
try {
|
||||
// 收集源图层中的可见对象
|
||||
const visibleObjects = sourceLayer.fabricObjects.filter(
|
||||
(obj) => obj.visible
|
||||
);
|
||||
const visibleObjects = sourceLayer.fabricObjects.filter((obj) => obj.visible);
|
||||
|
||||
if (visibleObjects.length === 0) {
|
||||
throw new Error("源图层没有可见对象");
|
||||
@@ -649,10 +613,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
let highResolutionScale = 1;
|
||||
if (this.highResolutionEnabled) {
|
||||
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||
highResolutionScale = Math.max(
|
||||
this.baseResolutionScale,
|
||||
devicePixelRatio * 2
|
||||
);
|
||||
highResolutionScale = Math.max(this.baseResolutionScale, devicePixelRatio * 2);
|
||||
}
|
||||
|
||||
// 创建用于导出的高分辨率canvas
|
||||
@@ -663,12 +624,8 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
colorSpace: "srgb",
|
||||
});
|
||||
|
||||
const actualWidth = Math.round(
|
||||
renderBounds.width * highResolutionScale
|
||||
);
|
||||
const actualHeight = Math.round(
|
||||
renderBounds.height * highResolutionScale
|
||||
);
|
||||
const actualWidth = Math.round(renderBounds.width * highResolutionScale);
|
||||
const actualHeight = Math.round(renderBounds.height * highResolutionScale);
|
||||
|
||||
exportCanvas.width = actualWidth;
|
||||
exportCanvas.height = actualHeight;
|
||||
@@ -877,17 +834,14 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
}
|
||||
});
|
||||
} else if (objectType === "polygon") {
|
||||
fabric.Polygon.fromObject(
|
||||
this.serializedSelectionObject,
|
||||
(polygon) => {
|
||||
if (polygon) {
|
||||
console.log("多边形选区对象反序列化成功");
|
||||
resolve(polygon);
|
||||
} else {
|
||||
reject(new Error("多边形选区对象反序列化失败"));
|
||||
}
|
||||
fabric.Polygon.fromObject(this.serializedSelectionObject, (polygon) => {
|
||||
if (polygon) {
|
||||
console.log("多边形选区对象反序列化成功");
|
||||
resolve(polygon);
|
||||
} else {
|
||||
reject(new Error("多边形选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
} else if (objectType === "rect") {
|
||||
fabric.Rect.fromObject(this.serializedSelectionObject, (rect) => {
|
||||
if (rect) {
|
||||
@@ -898,30 +852,24 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
}
|
||||
});
|
||||
} else if (objectType === "ellipse" || objectType === "circle") {
|
||||
fabric.Ellipse.fromObject(
|
||||
this.serializedSelectionObject,
|
||||
(ellipse) => {
|
||||
if (ellipse) {
|
||||
console.log("椭圆选区对象反序列化成功");
|
||||
resolve(ellipse);
|
||||
} else {
|
||||
reject(new Error("椭圆选区对象反序列化失败"));
|
||||
}
|
||||
fabric.Ellipse.fromObject(this.serializedSelectionObject, (ellipse) => {
|
||||
if (ellipse) {
|
||||
console.log("椭圆选区对象反序列化成功");
|
||||
resolve(ellipse);
|
||||
} else {
|
||||
reject(new Error("椭圆选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// 通用对象反序列化
|
||||
fabric.util.enlivenObjects(
|
||||
[this.serializedSelectionObject],
|
||||
(objects) => {
|
||||
if (objects && objects.length > 0) {
|
||||
console.log("通用选区对象反序列化成功");
|
||||
resolve(objects[0]);
|
||||
} else {
|
||||
reject(new Error("通用选区对象反序列化失败"));
|
||||
}
|
||||
fabric.util.enlivenObjects([this.serializedSelectionObject], (objects) => {
|
||||
if (objects && objects.length > 0) {
|
||||
console.log("通用选区对象反序列化成功");
|
||||
resolve(objects[0]);
|
||||
} else {
|
||||
reject(new Error("通用选区对象反序列化失败"));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -945,11 +893,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
// 1. 恢复图层到原位置
|
||||
if (this.originalLayerIndex !== -1) {
|
||||
this.layerManager.layers.value.splice(
|
||||
this.originalLayerIndex,
|
||||
0,
|
||||
this.originalLayer
|
||||
);
|
||||
this.layerManager.layers.value.splice(this.originalLayerIndex, 0, this.originalLayer);
|
||||
} else {
|
||||
// 如果没有保存索引,添加到末尾
|
||||
this.layerManager.layers.value.push(this.originalLayer);
|
||||
@@ -957,9 +901,7 @@ export class LassoCutoutCommand extends CompositeCommand {
|
||||
|
||||
// 2. 恢复fabric对象到画布
|
||||
if (this.originalFabricObjects.length > 0) {
|
||||
console.log(
|
||||
`↩️ 恢复 ${this.originalFabricObjects.length} 个fabric对象`
|
||||
);
|
||||
console.log(`↩️ 恢复 ${this.originalFabricObjects.length} 个fabric对象`);
|
||||
|
||||
// 使用fabric.util.enlivenObjects批量反序列化对象
|
||||
await new Promise((resolve, reject) => {
|
||||
@@ -1108,12 +1050,7 @@ export class ClearSelectionCommand extends Command {
|
||||
// 序列化选区对象和相关状态
|
||||
this.originalSelectionState = {
|
||||
// 选区对象的序列化数据
|
||||
selectionObjectData: selectionObject.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"layerName",
|
||||
"parentId",
|
||||
]),
|
||||
selectionObjectData: selectionObject.toObject(["id", "layerId", "layerName", "parentId"]),
|
||||
// 选区路径数据
|
||||
selectionPath: this.selectionManager.getSelectionPath(),
|
||||
// 羽化值
|
||||
@@ -1176,13 +1113,8 @@ export class ClearSelectionCommand extends Command {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
selectionObjectData,
|
||||
featherAmount,
|
||||
selectionStyle,
|
||||
position,
|
||||
managerState,
|
||||
} = this.originalSelectionState;
|
||||
const { selectionObjectData, featherAmount, selectionStyle, position, managerState } =
|
||||
this.originalSelectionState;
|
||||
|
||||
// 根据选区对象类型进行反序列化
|
||||
const objectType = selectionObjectData.type;
|
||||
@@ -1228,9 +1160,7 @@ export class ClearSelectionCommand extends Command {
|
||||
|
||||
// 恢复阴影(羽化效果)
|
||||
if (selectionStyle.shadow) {
|
||||
restoredObject.shadow = new fabric.Shadow(
|
||||
selectionStyle.shadow
|
||||
);
|
||||
restoredObject.shadow = new fabric.Shadow(selectionStyle.shadow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1315,9 +1245,7 @@ export class ClearSelectionCommand extends Command {
|
||||
// 验证基本属性
|
||||
const originalId = this.originalSelectionState.selectionId;
|
||||
if (currentSelection.id !== originalId) {
|
||||
console.warn(
|
||||
`选区ID不匹配: 期望 ${originalId}, 实际 ${currentSelection.id}`
|
||||
);
|
||||
console.warn(`选区ID不匹配: 期望 ${originalId}, 实际 ${currentSelection.id}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1325,9 +1253,7 @@ export class ClearSelectionCommand extends Command {
|
||||
const currentFeather = this.selectionManager.getFeatherAmount();
|
||||
const originalFeather = this.originalSelectionState.featherAmount;
|
||||
if (currentFeather !== originalFeather) {
|
||||
console.warn(
|
||||
`羽化值不匹配: 期望 ${originalFeather}, 实际 ${currentFeather}`
|
||||
);
|
||||
console.warn(`羽化值不匹配: 期望 ${originalFeather}, 实际 ${currentFeather}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { Command } from "./Command";
|
||||
import {
|
||||
createLayer,
|
||||
findLayerRecursively,
|
||||
LayerType,
|
||||
OperationType,
|
||||
} from "../utils/layerHelper";
|
||||
import { createLayer, findLayerRecursively, LayerType, OperationType } from "../utils/layerHelper";
|
||||
import { createStaticCanvas } from "../utils/canvasFactory";
|
||||
import { AddObjectToLayerCommand } from "./ObjectLayerCommands";
|
||||
import { ToolCommand } from "./ToolCommands";
|
||||
import {
|
||||
findObjectById,
|
||||
generateId,
|
||||
getObjectZIndex,
|
||||
insertObjectAtZIndex,
|
||||
objectIsInCanvas,
|
||||
optimizeCanvasRendering,
|
||||
removeCanvasObjectByObject,
|
||||
@@ -112,15 +109,11 @@ export class AddLayerCommand extends Command {
|
||||
parentLayer.children = parentLayer.children || [];
|
||||
parentLayer.children.splice(insertIndex, 0, newLayer);
|
||||
|
||||
console.log(
|
||||
`新图层已插入到子图层位置: ${insertIndex} (父图层: ${parentLayer.name})`
|
||||
);
|
||||
console.log(`新图层已插入到子图层位置: ${insertIndex} (父图层: ${parentLayer.name})`);
|
||||
} else {
|
||||
// 当前激活图层是一级图层
|
||||
// 在一级图层中,插入到激活图层之上
|
||||
const activeLayerIndex = layers.findIndex(
|
||||
(layer) => layer.id === currentActiveLayerId
|
||||
);
|
||||
const activeLayerIndex = layers.findIndex((layer) => layer.id === currentActiveLayerId);
|
||||
insertIndex = Math.max(0, activeLayerIndex);
|
||||
layers.splice(insertIndex, 0, newLayer);
|
||||
|
||||
@@ -273,9 +266,7 @@ export class PasteLayerCommand extends Command {
|
||||
try {
|
||||
objects.forEach((obj) => {
|
||||
// 生成新的对象ID
|
||||
const newObjId = `obj_${Date.now()}_${Math.floor(
|
||||
Math.random() * 1000
|
||||
)}`;
|
||||
const newObjId = `obj_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
obj.id = newObjId;
|
||||
obj.layerId = this.newLayerId;
|
||||
obj.layerName = this.newLayer.name;
|
||||
@@ -337,9 +328,7 @@ export class PasteLayerCommand extends Command {
|
||||
if (!this.newLayer || !this.newLayerId) return;
|
||||
|
||||
// 从图层列表删除该图层
|
||||
const index = this.layers.value.findIndex(
|
||||
(layer) => layer.id === this.newLayerId
|
||||
);
|
||||
const index = this.layers.value.findIndex((layer) => layer.id === this.newLayerId);
|
||||
if (index !== -1) {
|
||||
this.layers.value.splice(index, 1);
|
||||
}
|
||||
@@ -405,9 +394,7 @@ export class RemoveLayerCommand extends Command {
|
||||
this.activeLayerId = options.activeLayerId;
|
||||
|
||||
// 查找要删除的图层
|
||||
this.layerIndex = this.layers.value.findIndex(
|
||||
(layer) => layer.id === this.layerId
|
||||
);
|
||||
this.layerIndex = this.layers.value.findIndex((layer) => layer.id === this.layerId);
|
||||
this.removedLayer = this.layers.value[this.layerIndex];
|
||||
this.isActiveLayer = this.layerId === this.activeLayerId.value;
|
||||
|
||||
@@ -474,9 +461,7 @@ export class RemoveLayerCommand extends Command {
|
||||
// 如果删除的是当前活动图层,需要更新活动图层
|
||||
if (this.isActiveLayer) {
|
||||
// 查找最近的非背景层作为新的活动图层
|
||||
const newActiveLayer = this.layers.value.find(
|
||||
(layer) => !layer.isBackground
|
||||
);
|
||||
const newActiveLayer = this.layers.value.find((layer) => !layer.isBackground);
|
||||
if (newActiveLayer) {
|
||||
this.activeLayerId.value = newActiveLayer.id;
|
||||
} else {
|
||||
@@ -554,30 +539,22 @@ export class MoveLayerCommand extends Command {
|
||||
|
||||
this.parentLayer = null; // 父图层
|
||||
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
|
||||
// 如果parent 有值 或者 layer 上有parentId 则视为子图层的置顶
|
||||
if (parent?.id) {
|
||||
// 查找子图层索引
|
||||
this.layerIndex = parent?.children?.findIndex(
|
||||
(layer) => layer.id === this.layerId
|
||||
);
|
||||
this.layerIndex = parent?.children?.findIndex((layer) => layer.id === this.layerId);
|
||||
this.parentLayer = parent;
|
||||
} else {
|
||||
// 查找图层索引
|
||||
this.layerIndex = this.layers.value.findIndex(
|
||||
(layer) => layer.id === this.layerId
|
||||
);
|
||||
this.layerIndex = this.layers.value.findIndex((layer) => layer.id === this.layerId);
|
||||
}
|
||||
|
||||
this.layer = layer;
|
||||
this.originalIndex = this.layerIndex;
|
||||
// 目标位置
|
||||
this.targetIndex =
|
||||
options.direction === "up" ? this.layerIndex - 1 : this.layerIndex + 1;
|
||||
this.targetIndex = options.direction === "up" ? this.layerIndex - 1 : this.layerIndex + 1;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
@@ -668,9 +645,7 @@ export class ToggleLayerVisibilityCommand extends Command {
|
||||
|
||||
// 更新画布上图层对象的可见性
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
const layerObjects = this.canvas.getObjects().filter((obj) => obj.layerId === this.layerId);
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.visible = this.layer.visible;
|
||||
});
|
||||
@@ -711,10 +686,7 @@ export class ToggleChildLayerVisibilityCommand extends Command {
|
||||
this.layerManager = options.layerManager;
|
||||
|
||||
// 查找父图层和子图层
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
this.parentLayer = parent;
|
||||
this.childLayer = layer;
|
||||
|
||||
@@ -731,9 +703,7 @@ export class ToggleChildLayerVisibilityCommand extends Command {
|
||||
|
||||
// 更新画布上图层对象的可见性
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
const layerObjects = this.canvas.getObjects().filter((obj) => obj.layerId === this.layerId);
|
||||
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.visible = this.childLayer.visible;
|
||||
@@ -792,9 +762,7 @@ export class RenameLayerCommand extends Command {
|
||||
|
||||
// 更新图层对象上的图层名称
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
const layerObjects = this.canvas.getObjects().filter((obj) => obj.layerId === this.layerId);
|
||||
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.layerName = this.newName;
|
||||
@@ -811,9 +779,7 @@ export class RenameLayerCommand extends Command {
|
||||
|
||||
// 恢复图层对象上的图层名称
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
const layerObjects = this.canvas.getObjects().filter((obj) => obj.layerId === this.layerId);
|
||||
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.layerName = this.oldName;
|
||||
@@ -848,10 +814,7 @@ export class LayerLockCommand extends Command {
|
||||
|
||||
// 查找图层(包括子图层)
|
||||
// 查找图层
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
this.layer = layer;
|
||||
this.parentLayer = parent || null; // 父图层
|
||||
this.oldLocked = this.layer ? this.layer.locked : null;
|
||||
@@ -869,11 +832,7 @@ export class LayerLockCommand extends Command {
|
||||
layer.locked = locked;
|
||||
|
||||
// 如果是组图层,递归更新所有子图层
|
||||
if (
|
||||
layer.type === "group" &&
|
||||
layer.children &&
|
||||
Array.isArray(layer.children)
|
||||
) {
|
||||
if (layer.type === "group" && layer.children && Array.isArray(layer.children)) {
|
||||
layer.children.forEach((child) => {
|
||||
this._updateLayerLockState(child, locked);
|
||||
});
|
||||
@@ -895,11 +854,7 @@ export class LayerLockCommand extends Command {
|
||||
// 更新画布上对象的可选择状态
|
||||
await this.layerManager?.updateLayersObjectsInteractivity();
|
||||
|
||||
console.log(
|
||||
`${newLocked ? "锁定" : "解锁"}图层: ${this.layer.name} (ID: ${
|
||||
this.layerId
|
||||
})`
|
||||
);
|
||||
console.log(`${newLocked ? "锁定" : "解锁"}图层: ${this.layer.name} (ID: ${this.layerId})`);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -911,9 +866,7 @@ export class LayerLockCommand extends Command {
|
||||
// 更新画布上对象的可选择状态
|
||||
await this.layerManager?.updateLayersObjectsInteractivity();
|
||||
|
||||
console.log(
|
||||
`恢复图层锁定状态: ${this.layer.name} (锁定: ${this.oldLocked})`
|
||||
);
|
||||
console.log(`恢复图层锁定状态: ${this.layer.name} (锁定: ${this.oldLocked})`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -961,9 +914,7 @@ export class SetLayerOpacityCommand extends Command {
|
||||
|
||||
// 更新画布上对象的不透明度
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
const layerObjects = this.canvas.getObjects().filter((obj) => obj.layerId === this.layerId);
|
||||
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.opacity = this.opacity;
|
||||
@@ -982,9 +933,7 @@ export class SetLayerOpacityCommand extends Command {
|
||||
|
||||
// 更新画布上对象的不透明度
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
const layerObjects = this.canvas.getObjects().filter((obj) => obj.layerId === this.layerId);
|
||||
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.opacity = this.oldOpacity;
|
||||
@@ -1038,9 +987,7 @@ export class SetLayerBlendModeCommand extends Command {
|
||||
|
||||
// 更新画布上对象的混合模式
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
const layerObjects = this.canvas.getObjects().filter((obj) => obj.layerId === this.layerId);
|
||||
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.globalCompositeOperation = this.blendMode;
|
||||
@@ -1059,9 +1006,7 @@ export class SetLayerBlendModeCommand extends Command {
|
||||
|
||||
// 更新画布上对象的混合模式
|
||||
if (this.canvas) {
|
||||
const layerObjects = this.canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.layerId === this.layerId);
|
||||
const layerObjects = this.canvas.getObjects().filter((obj) => obj.layerId === this.layerId);
|
||||
|
||||
layerObjects.forEach((obj) => {
|
||||
obj.globalCompositeOperation = this.oldBlendMode;
|
||||
@@ -1101,17 +1046,11 @@ export class MergeLayersCommand extends Command {
|
||||
// 备份原图层
|
||||
this.originalLayers = [...this.layers.value];
|
||||
// 新图层ID
|
||||
this.newLayerId = `merged_layer_${Date.now()}_${Math.floor(
|
||||
Math.random() * 1000
|
||||
)}`;
|
||||
this.newLayerId = `merged_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
}
|
||||
|
||||
execute() {
|
||||
if (
|
||||
!this.layerIds ||
|
||||
!Array.isArray(this.layerIds) ||
|
||||
this.layerIds.length < 2
|
||||
) {
|
||||
if (!this.layerIds || !Array.isArray(this.layerIds) || this.layerIds.length < 2) {
|
||||
console.error("合并图层至少需要两个图层");
|
||||
return null;
|
||||
}
|
||||
@@ -1132,6 +1071,14 @@ export class MergeLayersCommand extends Command {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 查找所有要组合的图层
|
||||
const layersToGroup = this.layerIds
|
||||
.map((id) => {
|
||||
const tempLayer = this.layers.value.find((layer) => layer.id === id); // 需要给子图层加上parentId
|
||||
return tempLayer ? { ...tempLayer, parentId: this.groupId } : false;
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
const topLayerIndex = Math.min(
|
||||
...layersToGroup.map((layer) =>
|
||||
this.layers.value.findIndex((fLayer) => fLayer.id === layer.id)
|
||||
@@ -1164,9 +1111,7 @@ export class MergeLayersCommand extends Command {
|
||||
});
|
||||
|
||||
// 移除原图层
|
||||
this.layers.value = this.layers.value.filter(
|
||||
(layer) => !this.layerIds.includes(layer.id)
|
||||
);
|
||||
this.layers.value = this.layers.value.filter((layer) => !this.layerIds.includes(layer.id));
|
||||
|
||||
// 插入新图层
|
||||
this.layers.value.splice(topLayerIndex, 0, mergedLayer);
|
||||
@@ -1227,18 +1172,13 @@ export class GroupLayersCommand extends Command {
|
||||
this.originalLayers = [...this.layers.value];
|
||||
// 新组ID
|
||||
this.groupId =
|
||||
generateId("group_layer_") ||
|
||||
`group_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
generateId("group_layer_") || `group_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
|
||||
this.originalActiveLayerId = this.activeLayerId.value; // 备份原活动图层ID
|
||||
}
|
||||
|
||||
async execute() {
|
||||
if (
|
||||
!this.layerIds ||
|
||||
!Array.isArray(this.layerIds) ||
|
||||
this.layerIds.length < 2
|
||||
) {
|
||||
if (!this.layerIds || !Array.isArray(this.layerIds) || this.layerIds.length < 2) {
|
||||
console.error("组合图层至少需要两个图层");
|
||||
return null;
|
||||
}
|
||||
@@ -1282,9 +1222,7 @@ export class GroupLayersCommand extends Command {
|
||||
});
|
||||
|
||||
// 移除原图层
|
||||
this.layers.value = this.layers.value.filter(
|
||||
(layer) => !this.layerIds.includes(layer.id)
|
||||
);
|
||||
this.layers.value = this.layers.value.filter((layer) => !this.layerIds.includes(layer.id));
|
||||
|
||||
// 插入新组图层
|
||||
this.layers.value.splice(topLayerIndex, 0, groupLayer);
|
||||
@@ -1338,9 +1276,7 @@ export class UngroupLayersCommand extends Command {
|
||||
|
||||
async execute() {
|
||||
// 查找组图层
|
||||
const groupIndex = this.layers.value.findIndex(
|
||||
(layer) => layer.id === this.groupId
|
||||
);
|
||||
const groupIndex = this.layers.value.findIndex((layer) => layer.id === this.groupId);
|
||||
|
||||
if (groupIndex === -1) {
|
||||
console.error(`找不到组图层 ${this.groupId}`);
|
||||
@@ -1361,11 +1297,11 @@ export class UngroupLayersCommand extends Command {
|
||||
this.layers.value.splice(
|
||||
groupIndex,
|
||||
1,
|
||||
...groupLayer.children?.map((child) => {
|
||||
...(groupLayer?.children?.map((child) => {
|
||||
// 为子图层添加parentId
|
||||
delete child.parentId; // 删除parentId属性
|
||||
return { ...child };
|
||||
})
|
||||
}) || {})
|
||||
);
|
||||
// 更新当前活动图层为第一个子图层
|
||||
if (this.childLayerIds.length > 0 && this.activeLayerId) {
|
||||
@@ -1411,18 +1347,14 @@ export class MergeLayerObjectsCommand extends Command {
|
||||
// 备份原始对象,用于撤销
|
||||
if (this.activeLayer && Array.isArray(this.activeLayer.fabricObjects)) {
|
||||
this.originalObjects =
|
||||
this.canvas
|
||||
?.getObjects()
|
||||
?.filter((fItem) => fItem.layerId === this.activeLayer.id) || [];
|
||||
this.canvas?.getObjects()?.filter((fItem) => fItem.layerId === this.activeLayer.id) || [];
|
||||
} else {
|
||||
this.originalObjects = [];
|
||||
}
|
||||
|
||||
// 新合并图像对象
|
||||
this.mergedImage = null;
|
||||
this.newImageId = `merged_image_${Date.now()}_${Math.floor(
|
||||
Math.random() * 1000
|
||||
)}`;
|
||||
this.newImageId = `merged_image_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
@@ -1458,10 +1390,7 @@ export class MergeLayerObjectsCommand extends Command {
|
||||
|
||||
// 异步处理图像合并
|
||||
try {
|
||||
const mergedImage = await this._createMergedImageAsync(
|
||||
objectsToMerge,
|
||||
bounds
|
||||
);
|
||||
const mergedImage = await this._createMergedImageAsync(objectsToMerge, bounds);
|
||||
this._setupMergedImage(mergedImage, bounds);
|
||||
this._replaceObjects(mergedImage);
|
||||
|
||||
@@ -1611,9 +1540,7 @@ export class MergeLayerObjectsCommand extends Command {
|
||||
});
|
||||
|
||||
tempCanvas.add(clonedObj);
|
||||
console.log(
|
||||
`添加对象 ${index + 1}/${objects.length}: ${obj.type || "unknown"}`
|
||||
);
|
||||
console.log(`添加对象 ${index + 1}/${objects.length}: ${obj.type || "unknown"}`);
|
||||
} catch (error) {
|
||||
console.error(`添加对象到临时画布时发生错误:`, error);
|
||||
}
|
||||
@@ -1672,10 +1599,7 @@ export class MergeLayerObjectsCommand extends Command {
|
||||
});
|
||||
|
||||
// 如果有新的图像对象,也要移除
|
||||
if (
|
||||
this.fabricImage &&
|
||||
this.canvas.getObjects().includes(this.fabricImage)
|
||||
) {
|
||||
if (this.fabricImage && this.canvas.getObjects().includes(this.fabricImage)) {
|
||||
this.canvas.remove(this.fabricImage);
|
||||
}
|
||||
|
||||
@@ -1691,9 +1615,7 @@ export class MergeLayerObjectsCommand extends Command {
|
||||
// 更新缩略图
|
||||
if (this.canvas.thumbnailManager) {
|
||||
setTimeout(() => {
|
||||
this.canvas.thumbnailManager.generateLayerThumbnail(
|
||||
this.activeLayer.id
|
||||
);
|
||||
this.canvas.thumbnailManager.generateLayerThumbnail(this.activeLayer.id);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
@@ -1737,9 +1659,7 @@ export class MergeLayerObjectsCommand extends Command {
|
||||
// 更新缩略图
|
||||
if (this.canvas.thumbnailManager) {
|
||||
setTimeout(() => {
|
||||
this.canvas.thumbnailManager.generateLayerThumbnail(
|
||||
this.activeLayer.id
|
||||
);
|
||||
this.canvas.thumbnailManager.generateLayerThumbnail(this.activeLayer.id);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
@@ -1827,8 +1747,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
||||
this.existingGroupId = null;
|
||||
this.groupObjectId = null;
|
||||
this.newGroupId =
|
||||
generateId("group") ||
|
||||
`group_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
generateId("group") || `group_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
this.wasGroupCreated = false;
|
||||
|
||||
// 保存原始位置信息
|
||||
@@ -1889,10 +1808,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
||||
const newObjectsToAdd = [];
|
||||
if (this.fabricImage) {
|
||||
// 如果是重做,恢复新对象的原始位置
|
||||
if (
|
||||
!this.isFirstExecution &&
|
||||
this.newObjectPositions.has(this.fabricImage.id)
|
||||
) {
|
||||
if (!this.isFirstExecution && this.newObjectPositions.has(this.fabricImage.id)) {
|
||||
const savedPosition = this.newObjectPositions.get(this.fabricImage.id);
|
||||
this.fabricImage.set({
|
||||
left: savedPosition.left,
|
||||
@@ -1905,9 +1821,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
||||
flipX: savedPosition.flipX,
|
||||
flipY: savedPosition.flipY,
|
||||
});
|
||||
console.log(
|
||||
`🔄 重做时恢复新对象位置: (${savedPosition.left}, ${savedPosition.top})`
|
||||
);
|
||||
console.log(`🔄 重做时恢复新对象位置: (${savedPosition.left}, ${savedPosition.top})`);
|
||||
}
|
||||
|
||||
newObjectsToAdd.push(this.fabricImage);
|
||||
@@ -1960,9 +1874,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
||||
|
||||
if (!this.existingGroupId) {
|
||||
const groupObjects =
|
||||
this.activeLayer.fabricObjects.find(
|
||||
(obj) => obj && obj.type === "group"
|
||||
) || null;
|
||||
this.activeLayer.fabricObjects.find((obj) => obj && obj.type === "group") || null;
|
||||
|
||||
this.existingGroupId = groupObjects?.id || null;
|
||||
}
|
||||
@@ -2062,9 +1974,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
||||
|
||||
// 更新图层的对象列表
|
||||
// this.activeLayer.fabricObjects = [groupObject];
|
||||
this.activeLayer.fabricObjects = [
|
||||
groupObject.toObject(["id", "layerId", "layerName"]),
|
||||
];
|
||||
this.activeLayer.fabricObjects = [groupObject.toObject(["id", "layerId", "layerName"])];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2150,10 +2060,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
||||
restorePosition = { ...originalPosition };
|
||||
} else {
|
||||
// 计算对象在画布中的当前绝对位置
|
||||
restorePosition = this._calculateObjectAbsolutePosition(
|
||||
obj,
|
||||
groupObject
|
||||
);
|
||||
restorePosition = this._calculateObjectAbsolutePosition(obj, groupObject);
|
||||
}
|
||||
|
||||
objectsToRestore.push({
|
||||
@@ -2208,9 +2115,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
||||
restoredObjects.push(obj);
|
||||
|
||||
console.log(
|
||||
`✅ 恢复原始对象 ${obj.id || obj.type} 到位置 (${position.left}, ${
|
||||
position.top
|
||||
})`
|
||||
`✅ 恢复原始对象 ${obj.id || obj.type} 到位置 (${position.left}, ${position.top})`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(`恢复对象 ${obj.id || obj.type} 时发生错误:`, error);
|
||||
@@ -2270,10 +2175,7 @@ export class LayerObjectsToGroupCommand extends Command {
|
||||
const objectPoint = new fabric.Point(obj.left || 0, obj.top || 0);
|
||||
|
||||
// 应用组的变换矩阵计算绝对位置
|
||||
const absolutePoint = fabric.util.transformPoint(
|
||||
objectPoint,
|
||||
groupTransform
|
||||
);
|
||||
const absolutePoint = fabric.util.transformPoint(objectPoint, groupTransform);
|
||||
|
||||
// 计算缩放比例
|
||||
const totalScaleX = (group.scaleX || 1) * (obj.scaleX || 1);
|
||||
@@ -2441,8 +2343,7 @@ export class CreateImageLayerCommand extends Command {
|
||||
|
||||
// 存储执行过程中的结果
|
||||
this.newLayerId =
|
||||
generateId("layer_image_") ||
|
||||
`layer_image_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
generateId("layer_image_") || `layer_image_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
this.commands = [];
|
||||
this.executedCommands = [];
|
||||
}
|
||||
@@ -2457,8 +2358,7 @@ export class CreateImageLayerCommand extends Command {
|
||||
this.executedCommands = [];
|
||||
|
||||
// 生成图层名称
|
||||
const fileName =
|
||||
this.layerName || `图片 ${new Date().toLocaleTimeString()}`;
|
||||
const fileName = this.layerName || `图片 ${new Date().toLocaleTimeString()}`;
|
||||
|
||||
this.fabricImage.set({
|
||||
id: this.imageId,
|
||||
@@ -2529,9 +2429,7 @@ export class CreateImageLayerCommand extends Command {
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`↩️ 开始撤销创建图片图层操作,共 ${this.executedCommands.length} 个子命令`
|
||||
);
|
||||
console.log(`↩️ 开始撤销创建图片图层操作,共 ${this.executedCommands.length} 个子命令`);
|
||||
|
||||
try {
|
||||
// 逆序撤销已执行的命令
|
||||
@@ -2547,10 +2445,7 @@ export class CreateImageLayerCommand extends Command {
|
||||
}
|
||||
console.log(`✅ 子命令撤销成功: ${command.constructor.name}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`❌ 子命令撤销失败: ${command.constructor.name}`,
|
||||
error
|
||||
);
|
||||
console.error(`❌ 子命令撤销失败: ${command.constructor.name}`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2583,10 +2478,7 @@ export class CreateImageLayerCommand extends Command {
|
||||
}
|
||||
console.log(`✅ 子命令回滚成功: ${command.constructor.name}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`❌ 子命令回滚失败: ${command.constructor.name}`,
|
||||
error
|
||||
);
|
||||
console.error(`❌ 子命令回滚失败: ${command.constructor.name}`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2721,9 +2613,7 @@ export class ReorderChildLayersCommand extends Command {
|
||||
|
||||
async execute() {
|
||||
// 查找父图层
|
||||
const parentLayer = this.layers.value.find(
|
||||
(layer) => layer.id === this.parentId
|
||||
);
|
||||
const parentLayer = this.layers.value.find((layer) => layer.id === this.parentId);
|
||||
if (!parentLayer) return false;
|
||||
|
||||
// 获取子图层
|
||||
@@ -2873,15 +2763,11 @@ export class CutLayerCommand extends Command {
|
||||
|
||||
// 生成新图层ID和名称
|
||||
this.newLayerId =
|
||||
generateId("layer_") ||
|
||||
`layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
generateId("layer_") || `layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
const sourceLayer = layer;
|
||||
const parentLayer = parent;
|
||||
|
||||
@@ -2908,9 +2794,7 @@ export class CutLayerCommand extends Command {
|
||||
blendMode: sourceLayer.blendMode,
|
||||
fabricObjects: [],
|
||||
children: sourceLayer.children ? [...sourceLayer.children] : [],
|
||||
layerProperties: sourceLayer.layerProperties
|
||||
? { ...sourceLayer.layerProperties }
|
||||
: {},
|
||||
layerProperties: sourceLayer.layerProperties ? { ...sourceLayer.layerProperties } : {},
|
||||
metadata: sourceLayer.metadata ? { ...sourceLayer.metadata } : {},
|
||||
parentId: parentLayer ? parentLayer.id : undefined, // 保持父图层关系
|
||||
});
|
||||
@@ -2920,11 +2804,8 @@ export class CutLayerCommand extends Command {
|
||||
|
||||
if (parentLayer) {
|
||||
// 处理子图层:在父图层的children数组中插入
|
||||
const sourceChildIndex = parentLayer.children.findIndex(
|
||||
(child) => child.id === this.layerId
|
||||
);
|
||||
insertIndex =
|
||||
this.insertIndex !== null ? this.insertIndex : sourceChildIndex + 1;
|
||||
const sourceChildIndex = parentLayer.children.findIndex((child) => child.id === this.layerId);
|
||||
insertIndex = this.insertIndex !== null ? this.insertIndex : sourceChildIndex + 1;
|
||||
|
||||
// 插入到父图层的children数组中
|
||||
parentLayer.children.splice(insertIndex, 0, this.newLayer);
|
||||
@@ -2933,11 +2814,8 @@ export class CutLayerCommand extends Command {
|
||||
this.childInsertIndex = insertIndex;
|
||||
} else {
|
||||
// 处理主图层:在主图层数组中插入
|
||||
const sourceIndex = this.layers.value.findIndex(
|
||||
(l) => l.id === this.layerId
|
||||
);
|
||||
insertIndex =
|
||||
this.insertIndex !== null ? this.insertIndex : sourceIndex + 1;
|
||||
const sourceIndex = this.layers.value.findIndex((l) => l.id === this.layerId);
|
||||
insertIndex = this.insertIndex !== null ? this.insertIndex : sourceIndex + 1;
|
||||
|
||||
// 插入到主图层数组中
|
||||
this.layers.value.splice(insertIndex, 0, this.newLayer);
|
||||
@@ -2956,9 +2834,7 @@ export class CutLayerCommand extends Command {
|
||||
// 重新渲染画布
|
||||
await this.layerManager?.updateLayersObjectsInteractivity(false);
|
||||
|
||||
console.log(
|
||||
`已复制图层:${newName} ${this.isChildLayer ? "(子图层)" : "(主图层)"}`
|
||||
);
|
||||
console.log(`已复制图层:${newName} ${this.isChildLayer ? "(子图层)" : "(主图层)"}`);
|
||||
return this.newLayerId;
|
||||
}
|
||||
|
||||
@@ -2975,9 +2851,7 @@ export class CutLayerCommand extends Command {
|
||||
}
|
||||
} else {
|
||||
// 撤销主图层:从主图层数组中删除
|
||||
const index = this.layers.value.findIndex(
|
||||
(l) => l.id === this.newLayerId
|
||||
);
|
||||
const index = this.layers.value.findIndex((l) => l.id === this.newLayerId);
|
||||
if (index !== -1) {
|
||||
this.layers.value.splice(index, 1);
|
||||
}
|
||||
@@ -3007,9 +2881,7 @@ export class CutLayerCommand extends Command {
|
||||
fabric.util.enlivenObjects(serializedObjects, (objects) => {
|
||||
objects.forEach((obj) => {
|
||||
// 生成新的对象ID
|
||||
const newObjId = `obj_${Date.now()}_${Math.floor(
|
||||
Math.random() * 1000
|
||||
)}`;
|
||||
const newObjId = `obj_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
obj.id = newObjId;
|
||||
obj.layerId = this.newLayerId;
|
||||
obj.layerName = this.newLayer.name;
|
||||
@@ -3066,8 +2938,7 @@ export class CreateAdjustmentLayerCommand extends Command {
|
||||
this.newLayer = null;
|
||||
// 生成新图层ID
|
||||
this.newLayerId =
|
||||
generateId("adj_layer_") ||
|
||||
`adj_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
generateId("adj_layer_") || `adj_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
}
|
||||
|
||||
execute() {
|
||||
@@ -3089,9 +2960,7 @@ export class CreateAdjustmentLayerCommand extends Command {
|
||||
|
||||
// 计算插入位置
|
||||
const insertIndex =
|
||||
this.insertIndex !== null
|
||||
? this.insertIndex
|
||||
: this._getInsertIndexAboveActiveLayer();
|
||||
this.insertIndex !== null ? this.insertIndex : this._getInsertIndexAboveActiveLayer();
|
||||
|
||||
// 插入新图层
|
||||
this.layers.value.splice(insertIndex, 0, this.newLayer);
|
||||
@@ -3155,9 +3024,7 @@ export class ApplyLayerStyleCommand extends Command {
|
||||
return;
|
||||
}
|
||||
this.layer = layer;
|
||||
this.oldStyles = this.layer
|
||||
? { ...(this.layer.layerProperties?.styles || {}) }
|
||||
: {};
|
||||
this.oldStyles = this.layer ? { ...(this.layer.layerProperties?.styles || {}) } : {};
|
||||
}
|
||||
|
||||
execute() {
|
||||
@@ -3296,9 +3163,7 @@ export class LayerClippingMaskCommand extends Command {
|
||||
|
||||
if (this.maskLayerId) {
|
||||
// 创建剪贴蒙版
|
||||
const maskLayer = this.layers.value.find(
|
||||
(l) => l.id === this.maskLayerId
|
||||
);
|
||||
const maskLayer = this.layers.value.find((l) => l.id === this.maskLayerId);
|
||||
if (!maskLayer) {
|
||||
console.error(`蒙版图层 ${this.maskLayerId} 不存在`);
|
||||
return false;
|
||||
@@ -3525,19 +3390,14 @@ export class ChangeFixedImageCommand extends Command {
|
||||
this.retryCount = attempt;
|
||||
|
||||
if (attempt === this.maxRetries) {
|
||||
throw new Error(
|
||||
`图像加载失败,已重试${this.maxRetries}次: ${error.message}`
|
||||
);
|
||||
throw new Error(`图像加载失败,已重试${this.maxRetries}次: ${error.message}`);
|
||||
}
|
||||
|
||||
// 指数退避重试
|
||||
const delay = Math.pow(2, attempt) * 1000;
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
|
||||
console.warn(
|
||||
`图像加载重试 ${attempt + 1}/${this.maxRetries}:`,
|
||||
error.message
|
||||
);
|
||||
console.warn(`图像加载重试 ${attempt + 1}/${this.maxRetries}:`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3545,9 +3405,7 @@ export class ChangeFixedImageCommand extends Command {
|
||||
loadImage() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
reject(
|
||||
new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`)
|
||||
);
|
||||
reject(new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`));
|
||||
}, this.timeoutMs);
|
||||
|
||||
fabric.Image.fromURL(
|
||||
@@ -3585,15 +3443,9 @@ export class ChangeFixedImageCommand extends Command {
|
||||
|
||||
// 移除旧对象(如果存在)
|
||||
if (this.previousObjectId) {
|
||||
const { object: oldObject } = findObjectById(
|
||||
this.canvas,
|
||||
this.previousObjectId
|
||||
);
|
||||
const { object: oldObject } = findObjectById(this.canvas, this.previousObjectId);
|
||||
if (oldObject) {
|
||||
const removeSuccess = removeCanvasObjectByObject(
|
||||
this.canvas,
|
||||
oldObject
|
||||
);
|
||||
const removeSuccess = removeCanvasObjectByObject(this.canvas, oldObject);
|
||||
if (!removeSuccess) {
|
||||
console.warn("移除旧对象失败,但继续执行");
|
||||
}
|
||||
@@ -3650,97 +3502,75 @@ export class ChangeFixedImageCommand extends Command {
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fabric.util.enlivenObjects(
|
||||
[this.previousImage.objectData],
|
||||
async (objects) => {
|
||||
try {
|
||||
const restoredImage = objects[0];
|
||||
fabric.util.enlivenObjects([this.previousImage.objectData], async (objects) => {
|
||||
try {
|
||||
const restoredImage = objects[0];
|
||||
|
||||
await optimizeCanvasRendering(this.canvas, async () => {
|
||||
// 移除当前对象
|
||||
if (this.newObjectId) {
|
||||
const { object: currentObject } = findObjectById(
|
||||
this.canvas,
|
||||
this.newObjectId
|
||||
);
|
||||
if (currentObject) {
|
||||
removeCanvasObjectByObject(this.canvas, currentObject);
|
||||
}
|
||||
await optimizeCanvasRendering(this.canvas, async () => {
|
||||
// 移除当前对象
|
||||
if (this.newObjectId) {
|
||||
const { object: currentObject } = findObjectById(this.canvas, this.newObjectId);
|
||||
if (currentObject) {
|
||||
removeCanvasObjectByObject(this.canvas, currentObject);
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复之前的变换
|
||||
if (this.previousTransform) {
|
||||
restoredImage.set(this.previousTransform);
|
||||
}
|
||||
// 恢复之前的变换
|
||||
if (this.previousTransform) {
|
||||
restoredImage.set(this.previousTransform);
|
||||
}
|
||||
|
||||
// 设置图层属性
|
||||
restoredImage.set({
|
||||
id: this.previousObjectId,
|
||||
layerId: this.targetLayer.id,
|
||||
layerName: this.targetLayer.name,
|
||||
isBackground: this.targetLayer.isBackground,
|
||||
isFixed: this.targetLayer.isFixed,
|
||||
});
|
||||
|
||||
// 使用帮助函数在正确的z-index位置恢复对象
|
||||
if (
|
||||
this.previousZIndex !== undefined &&
|
||||
this.previousZIndex >= 0
|
||||
) {
|
||||
const insertSuccess = insertObjectAtZIndex(
|
||||
this.canvas,
|
||||
restoredImage,
|
||||
this.previousZIndex,
|
||||
false
|
||||
);
|
||||
if (insertSuccess) {
|
||||
console.log(`恢复图像到z-index位置: ${this.previousZIndex}`);
|
||||
} else {
|
||||
// 如果插入失败,回退到普通添加
|
||||
this.canvas.add(restoredImage);
|
||||
console.log("z-index恢复失败,恢复图像添加到顶层");
|
||||
}
|
||||
} else {
|
||||
// 如果没有保存的z-index,添加到顶层
|
||||
this.canvas.add(restoredImage);
|
||||
console.log("恢复图像添加到顶层");
|
||||
}
|
||||
|
||||
restoredImage.setCoords();
|
||||
|
||||
// 更新引用
|
||||
this.targetLayer.fabricObject = restoredImage.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"type",
|
||||
]);
|
||||
this.layerManager.updateLayerObject(
|
||||
this.targetLayer.id,
|
||||
restoredImage
|
||||
);
|
||||
// 设置图层属性
|
||||
restoredImage.set({
|
||||
id: this.previousObjectId,
|
||||
layerId: this.targetLayer.id,
|
||||
layerName: this.targetLayer.name,
|
||||
isBackground: this.targetLayer.isBackground,
|
||||
isFixed: this.targetLayer.isFixed,
|
||||
});
|
||||
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
// 使用帮助函数在正确的z-index位置恢复对象
|
||||
if (this.previousZIndex !== undefined && this.previousZIndex >= 0) {
|
||||
const insertSuccess = insertObjectAtZIndex(
|
||||
this.canvas,
|
||||
restoredImage,
|
||||
this.previousZIndex,
|
||||
false
|
||||
);
|
||||
if (insertSuccess) {
|
||||
console.log(`恢复图像到z-index位置: ${this.previousZIndex}`);
|
||||
} else {
|
||||
// 如果插入失败,回退到普通添加
|
||||
this.canvas.add(restoredImage);
|
||||
console.log("z-index恢复失败,恢复图像添加到顶层");
|
||||
}
|
||||
} else {
|
||||
// 如果没有保存的z-index,添加到顶层
|
||||
this.canvas.add(restoredImage);
|
||||
console.log("恢复图像添加到顶层");
|
||||
}
|
||||
|
||||
restoredImage.setCoords();
|
||||
|
||||
// 更新引用
|
||||
this.targetLayer.fabricObject = restoredImage.toObject(["id", "layerId", "type"]);
|
||||
this.layerManager.updateLayerObject(this.targetLayer.id, restoredImage);
|
||||
});
|
||||
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async removeCurrentImage() {
|
||||
await optimizeCanvasRendering(this.canvas, async () => {
|
||||
if (this.newObjectId) {
|
||||
const { object: currentObject } = findObjectById(
|
||||
this.canvas,
|
||||
this.newObjectId
|
||||
);
|
||||
const { object: currentObject } = findObjectById(this.canvas, this.newObjectId);
|
||||
if (currentObject) {
|
||||
const removeSuccess = removeCanvasObjectByObject(
|
||||
this.canvas,
|
||||
currentObject
|
||||
);
|
||||
const removeSuccess = removeCanvasObjectByObject(this.canvas, currentObject);
|
||||
if (removeSuccess) {
|
||||
this.targetLayer.fabricObject = null;
|
||||
this.layerManager.updateLayerObject(this.targetLayer.id, null);
|
||||
@@ -3797,10 +3627,7 @@ export class AddImageToLayerCommand extends Command {
|
||||
this.validateInputs();
|
||||
|
||||
// 查找目标图层
|
||||
const { layer } = findLayerRecursively(
|
||||
this.layerManager?.layers?.value || [],
|
||||
this.layerId
|
||||
);
|
||||
const { layer } = findLayerRecursively(this.layerManager?.layers?.value || [], this.layerId);
|
||||
|
||||
this.targetLayer = layer;
|
||||
|
||||
@@ -3859,10 +3686,7 @@ export class AddImageToLayerCommand extends Command {
|
||||
this.canvas.remove(this.addedObject);
|
||||
|
||||
// 从图层管理器中移除
|
||||
this.layerManager.removeObjectFromLayer(
|
||||
this.addedObject.id,
|
||||
this.layerId
|
||||
);
|
||||
this.layerManager.removeObjectFromLayer(this.addedObject.id, this.layerId);
|
||||
|
||||
this.isExecuted = false;
|
||||
|
||||
@@ -3925,19 +3749,14 @@ export class AddImageToLayerCommand extends Command {
|
||||
this.retryCount = attempt;
|
||||
|
||||
if (attempt === this.maxRetries) {
|
||||
throw new Error(
|
||||
`图像加载失败,已重试${this.maxRetries}次: ${error.message}`
|
||||
);
|
||||
throw new Error(`图像加载失败,已重试${this.maxRetries}次: ${error.message}`);
|
||||
}
|
||||
|
||||
// 指数退避重试
|
||||
const delay = Math.pow(2, attempt) * 1000;
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
|
||||
console.warn(
|
||||
`图像加载重试 ${attempt + 1}/${this.maxRetries}:`,
|
||||
error.message
|
||||
);
|
||||
console.warn(`图像加载重试 ${attempt + 1}/${this.maxRetries}:`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3945,9 +3764,7 @@ export class AddImageToLayerCommand extends Command {
|
||||
loadImage() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
reject(
|
||||
new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`)
|
||||
);
|
||||
reject(new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`));
|
||||
}, this.timeoutMs);
|
||||
|
||||
fabric.Image.fromURL(
|
||||
@@ -4057,9 +3874,7 @@ export class RemoveChildLayerCommand extends Command {
|
||||
this.parentLayer = parent;
|
||||
|
||||
this.childIndex =
|
||||
this.parentLayer?.children?.findIndex(
|
||||
(child) => child.id === this.layerId
|
||||
) ?? -1;
|
||||
this.parentLayer?.children?.findIndex((child) => child.id === this.layerId) ?? -1;
|
||||
this.removedChild = this.parentLayer?.children?.[this.childIndex];
|
||||
this.isActiveLayer = this.layerId === this.activeLayerId.value;
|
||||
|
||||
@@ -4074,10 +3889,7 @@ export class RemoveChildLayerCommand extends Command {
|
||||
}
|
||||
|
||||
// 从画布中移除子图层中的所有对象
|
||||
if (
|
||||
this.removedChild.fabricObjects &&
|
||||
this.removedChild.fabricObjects.length > 0
|
||||
) {
|
||||
if (this.removedChild.fabricObjects && this.removedChild.fabricObjects.length > 0) {
|
||||
this.removedChild.fabricObjects.forEach((obj) => {
|
||||
const { object } = findObjectById(this.canvas, obj.id);
|
||||
if (object) {
|
||||
@@ -4096,9 +3908,7 @@ export class RemoveChildLayerCommand extends Command {
|
||||
this.activeLayerId.value = this.parentLayer.children[0].id;
|
||||
} else {
|
||||
this.activeLayerId.value =
|
||||
this.layers.value.find(
|
||||
(layer) => !layer.isBackground || !layer.isFixed
|
||||
)?.[0]?.id || null;
|
||||
this.layers.value.find((layer) => !layer.isBackground || !layer.isFixed)?.[0]?.id || null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4233,10 +4043,7 @@ export class ChildLayerLockCommand extends Command {
|
||||
this.layerManager = options.layerManager;
|
||||
|
||||
// 查找父图层和子图层
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
this.parentLayer = parent;
|
||||
this.childLayer = layer;
|
||||
this.oldLocked = this.childLayer ? this.childLayer.locked : null;
|
||||
|
||||
@@ -21,9 +21,7 @@ export class LiquifyCommand extends Command {
|
||||
constructor(options) {
|
||||
super({
|
||||
name: options.name || `液化操作: ${options.mode || "未知模式"}`,
|
||||
description:
|
||||
options.description ||
|
||||
`使用${options.mode || "未知模式"}模式进行液化操作`,
|
||||
description: options.description || `使用${options.mode || "未知模式"}模式进行液化操作`,
|
||||
});
|
||||
|
||||
this.canvas = options.canvas;
|
||||
@@ -96,9 +94,7 @@ export class LiquifyCommand extends Command {
|
||||
// 对于图像对象,我们需要保存src和元数据
|
||||
const state = {
|
||||
src: this.targetObject.getSrc ? this.targetObject.getSrc() : null,
|
||||
element: this.targetObject._element
|
||||
? this.targetObject._element.cloneNode(true)
|
||||
: null,
|
||||
element: this.targetObject._element ? this.targetObject._element.cloneNode(true) : null,
|
||||
filters: this.targetObject.filters ? [...this.targetObject.filters] : [],
|
||||
originalData: this.originalData,
|
||||
targetLayerId: this.targetLayerId,
|
||||
@@ -172,10 +168,7 @@ export class LiquifyCommand extends Command {
|
||||
// 确保图层引用更新
|
||||
const layer = this.layerManager.getLayerById(this.targetLayerId);
|
||||
if (layer) {
|
||||
if (
|
||||
layer.type === "background" &&
|
||||
layer.fabricObject === this.targetObject
|
||||
) {
|
||||
if (layer.type === "background" && layer.fabricObject === this.targetObject) {
|
||||
layer.fabricObject = img;
|
||||
} else if (layer.fabricObjects) {
|
||||
const objIndex = layer.fabricObjects.indexOf(this.targetObject);
|
||||
@@ -251,9 +244,7 @@ export class LiquifyDeformCommand extends LiquifyCommand {
|
||||
super({
|
||||
...options,
|
||||
name: `液化变形: ${options.mode || "未知模式"}`,
|
||||
description: `在(${options.x}, ${options.y})应用${
|
||||
options.mode || "未知模式"
|
||||
}变形`,
|
||||
description: `在(${options.x}, ${options.y})应用${options.mode || "未知模式"}变形`,
|
||||
});
|
||||
|
||||
this.x = options.x;
|
||||
@@ -343,9 +334,7 @@ export class LiquifyDeformCommand extends LiquifyCommand {
|
||||
layer.fabricObject = img;
|
||||
} else if (layer.fabricObjects) {
|
||||
const objIndex = layer.fabricObjects.findIndex(
|
||||
(obj) =>
|
||||
obj === this.savedState?.originalObject ||
|
||||
obj === this.targetObject
|
||||
(obj) => obj === this.savedState?.originalObject || obj === this.targetObject
|
||||
);
|
||||
if (objIndex !== -1) {
|
||||
layer.fabricObjects[objIndex] = img;
|
||||
@@ -374,8 +363,7 @@ export class CompositeLiquifyCommand extends Command {
|
||||
constructor(options) {
|
||||
super({
|
||||
name: options.name || "液化操作组合",
|
||||
description:
|
||||
options.description || `包含${options.commands?.length || 0}个液化操作`,
|
||||
description: options.description || `包含${options.commands?.length || 0}个液化操作`,
|
||||
});
|
||||
|
||||
this.commands = options.commands || [];
|
||||
@@ -551,10 +539,7 @@ export class LiquifyStateCommand extends Command {
|
||||
}
|
||||
|
||||
// 通过引用管理器更新图像数据
|
||||
await this.refManager.updateObjectImageData(
|
||||
this.objectRefId,
|
||||
this.finalImageData
|
||||
);
|
||||
await this.refManager.updateObjectImageData(this.objectRefId, this.finalImageData);
|
||||
|
||||
// 恢复液化管理器到最终状态
|
||||
if (this.liquifyManager && this.finalLiquifyState) {
|
||||
@@ -585,10 +570,7 @@ export class LiquifyStateCommand extends Command {
|
||||
}
|
||||
|
||||
// 通过引用管理器恢复到初始快照
|
||||
await this.refManager.restoreFromSnapshot(
|
||||
this.objectRefId,
|
||||
this.initialSnapshotId
|
||||
);
|
||||
await this.refManager.restoreFromSnapshot(this.objectRefId, this.initialSnapshotId);
|
||||
|
||||
// 恢复液化管理器到初始状态 - 关键修复
|
||||
if (this.liquifyManager) {
|
||||
@@ -604,18 +586,16 @@ export class LiquifyStateCommand extends Command {
|
||||
|
||||
// 强制设置原始图像数据为初始状态
|
||||
if (this.liquifyManager.enhancedManager) {
|
||||
this.liquifyManager.enhancedManager.originalImageData =
|
||||
this.initialImageData;
|
||||
this.liquifyManager.enhancedManager.currentImageData =
|
||||
this._cloneImageData(this.initialImageData);
|
||||
this.liquifyManager.enhancedManager.originalImageData = this.initialImageData;
|
||||
this.liquifyManager.enhancedManager.currentImageData = this._cloneImageData(
|
||||
this.initialImageData
|
||||
);
|
||||
|
||||
// 重置激活渲染器的数据
|
||||
if (this.liquifyManager.enhancedManager.activeRenderer) {
|
||||
const renderer = this.liquifyManager.enhancedManager.activeRenderer;
|
||||
renderer.originalImageData = this.initialImageData;
|
||||
renderer.currentImageData = this._cloneImageData(
|
||||
this.initialImageData
|
||||
);
|
||||
renderer.currentImageData = this._cloneImageData(this.initialImageData);
|
||||
|
||||
// 重置CPU渲染器的网格和变形历史
|
||||
if (renderer.reset) {
|
||||
@@ -741,8 +721,7 @@ export class LiquifyStateCommand extends Command {
|
||||
timestamp: Date.now(),
|
||||
properties: this.refManager._captureObjectState(fabricObject),
|
||||
imageData: this.initialImageData,
|
||||
eventListeners:
|
||||
this.refManager.eventListeners.get(this.objectRefId) || {},
|
||||
eventListeners: this.refManager.eventListeners.get(this.objectRefId) || {},
|
||||
};
|
||||
|
||||
this.refManager.stateSnapshots.set(this.initialSnapshotId, snapshot);
|
||||
@@ -772,8 +751,7 @@ export class LiquifyStateCommand extends Command {
|
||||
timestamp: Date.now(),
|
||||
properties: this.refManager._captureObjectState(fabricObject),
|
||||
imageData: this.finalImageData,
|
||||
eventListeners:
|
||||
this.refManager.eventListeners.get(this.objectRefId) || {},
|
||||
eventListeners: this.refManager.eventListeners.get(this.objectRefId) || {},
|
||||
};
|
||||
|
||||
this.refManager.stateSnapshots.set(this.finalSnapshotId, snapshot);
|
||||
@@ -804,8 +782,7 @@ export class LiquifyStateCommand extends Command {
|
||||
// 捕获当前渲染器状态
|
||||
activeRendererState: null,
|
||||
// 捕获目标对象引用
|
||||
targetObjectRef:
|
||||
this.liquifyManager.targetObject ?? enhancedManager.targetObject,
|
||||
targetObjectRef: this.liquifyManager.targetObject ?? enhancedManager.targetObject,
|
||||
// 捕获初始化状态
|
||||
initialized: this.liquifyManager.initialized || false,
|
||||
};
|
||||
@@ -832,13 +809,9 @@ export class LiquifyStateCommand extends Command {
|
||||
params: { ...renderer.params },
|
||||
currentMode: renderer.currentMode,
|
||||
// 对于CPU渲染器,还需要保存网格状态
|
||||
meshState: renderer.mesh
|
||||
? this._captureMeshState(renderer.mesh)
|
||||
: null,
|
||||
meshState: renderer.mesh ? this._captureMeshState(renderer.mesh) : null,
|
||||
// 保存变形历史
|
||||
deformHistory: renderer.deformHistory
|
||||
? [...renderer.deformHistory]
|
||||
: [],
|
||||
deformHistory: renderer.deformHistory ? [...renderer.deformHistory] : [],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -871,9 +844,7 @@ export class LiquifyStateCommand extends Command {
|
||||
this.realtimeUpdater.targetObject = this.liquifyManager.targetObject;
|
||||
// 如果有setTargetObject方法,调用它
|
||||
if (typeof this.realtimeUpdater.setTargetObject === "function") {
|
||||
this.realtimeUpdater.setTargetObject(
|
||||
this.liquifyManager.targetObject
|
||||
);
|
||||
this.realtimeUpdater.setTargetObject(this.liquifyManager.targetObject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,10 +882,8 @@ export class LiquifyStateCommand extends Command {
|
||||
} else if (renderer.mesh && renderer._initMesh) {
|
||||
// 如果没有保存的网格状态,重新初始化网格
|
||||
renderer._initMesh(
|
||||
rendererState.originalImageData?.width ||
|
||||
renderer.originalImageData?.width,
|
||||
rendererState.originalImageData?.height ||
|
||||
renderer.originalImageData?.height
|
||||
rendererState.originalImageData?.width || renderer.originalImageData?.width,
|
||||
rendererState.originalImageData?.height || renderer.originalImageData?.height
|
||||
);
|
||||
}
|
||||
|
||||
@@ -978,13 +947,7 @@ export class LiquifyStateCommand extends Command {
|
||||
* @private
|
||||
*/
|
||||
_restoreMeshState(mesh, meshState) {
|
||||
if (
|
||||
!mesh ||
|
||||
!meshState ||
|
||||
!Array.isArray(mesh) ||
|
||||
!Array.isArray(meshState)
|
||||
)
|
||||
return;
|
||||
if (!mesh || !meshState || !Array.isArray(mesh) || !Array.isArray(meshState)) return;
|
||||
|
||||
for (let i = 0; i < Math.min(mesh.length, meshState.length); i++) {
|
||||
for (let j = 0; j < Math.min(mesh[i].length, meshState[i].length); j++) {
|
||||
@@ -1043,8 +1006,7 @@ export class BatchLiquifyStateCommand extends Command {
|
||||
constructor(options) {
|
||||
super({
|
||||
name: options.name || "批量液化操作",
|
||||
description:
|
||||
options.description || `批量液化${options.commands?.length || 0}个对象`,
|
||||
description: options.description || `批量液化${options.commands?.length || 0}个对象`,
|
||||
});
|
||||
|
||||
this.commands = options.commands || [];
|
||||
@@ -1117,9 +1079,7 @@ export class BatchLiquifyStateCommand extends Command {
|
||||
* @returns {Boolean} 是否有效
|
||||
*/
|
||||
isValid() {
|
||||
return (
|
||||
this.commands.length > 0 && this.commands.every((cmd) => cmd.isValid())
|
||||
);
|
||||
return this.commands.length > 0 && this.commands.every((cmd) => cmd.isValid());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,11 +34,7 @@ export class SetActiveLayerCommand extends Command {
|
||||
}
|
||||
|
||||
execute() {
|
||||
const { layer } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId,
|
||||
this.parentId
|
||||
);
|
||||
const { layer } = findLayerRecursively(this.layers.value, this.layerId, this.parentId);
|
||||
this.newLayer = layer;
|
||||
|
||||
if (!this.newLayer) {
|
||||
@@ -68,10 +64,7 @@ export class SetActiveLayerCommand extends Command {
|
||||
this.canvas.discardActiveObject();
|
||||
|
||||
// 设置为新的图层下的对象为激活,但需要确保对象存在于画布上
|
||||
if (
|
||||
this.newLayer.fabricObjects &&
|
||||
this.newLayer.fabricObjects.length > 0
|
||||
) {
|
||||
if (this.newLayer.fabricObjects && this.newLayer.fabricObjects.length > 0) {
|
||||
const canvasObjects = this.canvas.getObjects();
|
||||
const validObjects = this.newLayer.fabricObjects.filter(
|
||||
(obj) => obj && canvasObjects.includes(obj)
|
||||
@@ -153,9 +146,7 @@ export class AddObjectToLayerCommand extends Command {
|
||||
this.layerManager = options.layerManager;
|
||||
|
||||
// 保存对象原始状态和ID
|
||||
this.objectId =
|
||||
this.fabricObject.id ||
|
||||
`obj_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
this.objectId = this.fabricObject.id || `obj_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
this.fabricObject.set({
|
||||
id: this.objectId,
|
||||
layerId: options.layerId,
|
||||
@@ -163,11 +154,7 @@ export class AddObjectToLayerCommand extends Command {
|
||||
});
|
||||
|
||||
// 保存完整的对象状态,包括位置和变换信息
|
||||
this.originalObjectState = this.fabricObject.toObject([
|
||||
"id",
|
||||
"layerId",
|
||||
"layerName",
|
||||
]);
|
||||
this.originalObjectState = this.fabricObject.toObject(["id", "layerId", "layerName"]);
|
||||
|
||||
// // 新增:保存详细的位置和变换信息,用于重做时恢复
|
||||
// this.originalPosition = {
|
||||
@@ -279,8 +266,7 @@ export class AddObjectToLayerCommand extends Command {
|
||||
// 将对象添加到图层的fabricObjects数组
|
||||
layer.fabricObjects = layer.fabricObjects || [];
|
||||
layer.fabricObjects.push(
|
||||
this.fabricObject?.toObject?.(["id", "layerId", "layerName"]) ||
|
||||
this.fabricObject
|
||||
this.fabricObject?.toObject?.(["id", "layerId", "layerName"]) || this.fabricObject
|
||||
);
|
||||
|
||||
await this.layerManager?.updateLayersObjectsInteractivity?.(false);
|
||||
@@ -327,16 +313,12 @@ export class AddObjectToLayerCommand extends Command {
|
||||
|
||||
// 从图层的fabricObjects数组中移除对象
|
||||
if (layer.fabricObjects) {
|
||||
layer.fabricObjects = layer.fabricObjects.filter(
|
||||
(obj) => obj.id !== this.objectId
|
||||
);
|
||||
layer.fabricObjects = layer.fabricObjects.filter((obj) => obj.id !== this.objectId);
|
||||
}
|
||||
// 优化渲染 - 统一批处理 支持异步回调
|
||||
optimizeCanvasRendering(this.canvas, async () => {
|
||||
// 从画布移除对象
|
||||
const object = this.canvas
|
||||
.getObjects()
|
||||
.find((obj) => obj.id === this.objectId);
|
||||
const object = this.canvas.getObjects().find((obj) => obj.id === this.objectId);
|
||||
if (object) {
|
||||
// 先丢弃活动对象,避免控制点渲染错误
|
||||
this.canvas.discardActiveObject();
|
||||
@@ -410,9 +392,7 @@ export class RemoveObjectFromLayerCommand extends Command {
|
||||
|
||||
// 从图层的fabricObjects数组移除对象
|
||||
if (layer.fabricObjects) {
|
||||
layer.fabricObjects = layer.fabricObjects.filter(
|
||||
(obj) => obj.id !== this.objectId
|
||||
);
|
||||
layer.fabricObjects = layer.fabricObjects.filter((obj) => obj.id !== this.objectId);
|
||||
}
|
||||
|
||||
// 更新画布
|
||||
@@ -639,19 +619,14 @@ export class ChangeFixedImageCommand extends Command {
|
||||
this.retryCount = attempt;
|
||||
|
||||
if (attempt === this.maxRetries) {
|
||||
throw new Error(
|
||||
`图像加载失败,已重试${this.maxRetries}次: ${error.message}`
|
||||
);
|
||||
throw new Error(`图像加载失败,已重试${this.maxRetries}次: ${error.message}`);
|
||||
}
|
||||
|
||||
// 指数退避重试
|
||||
const delay = Math.pow(2, attempt) * 1000;
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
|
||||
console.warn(
|
||||
`图像加载重试 ${attempt + 1}/${this.maxRetries}:`,
|
||||
error.message
|
||||
);
|
||||
console.warn(`图像加载重试 ${attempt + 1}/${this.maxRetries}:`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -659,9 +634,7 @@ export class ChangeFixedImageCommand extends Command {
|
||||
loadImage() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
reject(
|
||||
new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`)
|
||||
);
|
||||
reject(new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`));
|
||||
}, this.timeoutMs);
|
||||
|
||||
fabric.Image.fromURL(
|
||||
@@ -697,15 +670,9 @@ export class ChangeFixedImageCommand extends Command {
|
||||
|
||||
// 移除旧对象(如果存在)
|
||||
if (this.previousObjectId) {
|
||||
const { object: oldObject } = findObjectById(
|
||||
this.canvas,
|
||||
this.previousObjectId
|
||||
);
|
||||
const { object: oldObject } = findObjectById(this.canvas, this.previousObjectId);
|
||||
if (oldObject) {
|
||||
const removeSuccess = removeCanvasObjectByObject(
|
||||
this.canvas,
|
||||
oldObject
|
||||
);
|
||||
const removeSuccess = removeCanvasObjectByObject(this.canvas, oldObject);
|
||||
if (!removeSuccess) {
|
||||
console.warn("移除旧对象失败,但继续执行");
|
||||
}
|
||||
@@ -771,93 +738,75 @@ export class ChangeFixedImageCommand extends Command {
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fabric.util.enlivenObjects(
|
||||
[this.previousImage.objectData],
|
||||
async (objects) => {
|
||||
try {
|
||||
const restoredImage = objects[0];
|
||||
fabric.util.enlivenObjects([this.previousImage.objectData], async (objects) => {
|
||||
try {
|
||||
const restoredImage = objects[0];
|
||||
|
||||
await optimizeCanvasRendering(this.canvas, async () => {
|
||||
// 移除当前对象
|
||||
if (this.newObjectId) {
|
||||
const { object: currentObject } = findObjectById(
|
||||
this.canvas,
|
||||
this.newObjectId
|
||||
);
|
||||
if (currentObject) {
|
||||
removeCanvasObjectByObject(this.canvas, currentObject);
|
||||
}
|
||||
await optimizeCanvasRendering(this.canvas, async () => {
|
||||
// 移除当前对象
|
||||
if (this.newObjectId) {
|
||||
const { object: currentObject } = findObjectById(this.canvas, this.newObjectId);
|
||||
if (currentObject) {
|
||||
removeCanvasObjectByObject(this.canvas, currentObject);
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复之前的变换
|
||||
if (this.previousTransform) {
|
||||
restoredImage.set(this.previousTransform);
|
||||
}
|
||||
// 恢复之前的变换
|
||||
if (this.previousTransform) {
|
||||
restoredImage.set(this.previousTransform);
|
||||
}
|
||||
|
||||
// 设置图层属性
|
||||
restoredImage.set({
|
||||
id: this.previousObjectId,
|
||||
layerId: this.targetLayer.id,
|
||||
layerName: this.targetLayer.name,
|
||||
isBackground: this.targetLayer.isBackground,
|
||||
isFixed: this.targetLayer.isFixed,
|
||||
});
|
||||
|
||||
// 使用帮助函数在正确的z-index位置恢复对象
|
||||
if (
|
||||
this.previousZIndex !== undefined &&
|
||||
this.previousZIndex >= 0
|
||||
) {
|
||||
const insertSuccess = insertObjectAtZIndex(
|
||||
this.canvas,
|
||||
restoredImage,
|
||||
this.previousZIndex,
|
||||
false
|
||||
);
|
||||
if (insertSuccess) {
|
||||
console.log(`恢复图像到z-index位置: ${this.previousZIndex}`);
|
||||
} else {
|
||||
// 如果插入失败,回退到普通添加
|
||||
this.canvas.add(restoredImage);
|
||||
console.log("z-index恢复失败,恢复图像添加到顶层");
|
||||
}
|
||||
} else {
|
||||
// 如果没有保存的z-index,添加到顶层
|
||||
this.canvas.add(restoredImage);
|
||||
console.log("恢复图像添加到顶层");
|
||||
}
|
||||
|
||||
restoredImage.setCoords();
|
||||
|
||||
// 更新引用
|
||||
this.targetLayer.fabricObject = restoredImage;
|
||||
this.layerManager.updateLayerObject(
|
||||
this.targetLayer.id,
|
||||
restoredImage
|
||||
);
|
||||
// 设置图层属性
|
||||
restoredImage.set({
|
||||
id: this.previousObjectId,
|
||||
layerId: this.targetLayer.id,
|
||||
layerName: this.targetLayer.name,
|
||||
isBackground: this.targetLayer.isBackground,
|
||||
isFixed: this.targetLayer.isFixed,
|
||||
});
|
||||
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
// 使用帮助函数在正确的z-index位置恢复对象
|
||||
if (this.previousZIndex !== undefined && this.previousZIndex >= 0) {
|
||||
const insertSuccess = insertObjectAtZIndex(
|
||||
this.canvas,
|
||||
restoredImage,
|
||||
this.previousZIndex,
|
||||
false
|
||||
);
|
||||
if (insertSuccess) {
|
||||
console.log(`恢复图像到z-index位置: ${this.previousZIndex}`);
|
||||
} else {
|
||||
// 如果插入失败,回退到普通添加
|
||||
this.canvas.add(restoredImage);
|
||||
console.log("z-index恢复失败,恢复图像添加到顶层");
|
||||
}
|
||||
} else {
|
||||
// 如果没有保存的z-index,添加到顶层
|
||||
this.canvas.add(restoredImage);
|
||||
console.log("恢复图像添加到顶层");
|
||||
}
|
||||
|
||||
restoredImage.setCoords();
|
||||
|
||||
// 更新引用
|
||||
this.targetLayer.fabricObject = restoredImage;
|
||||
this.layerManager.updateLayerObject(this.targetLayer.id, restoredImage);
|
||||
});
|
||||
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async removeCurrentImage() {
|
||||
await optimizeCanvasRendering(this.canvas, async () => {
|
||||
if (this.newObjectId) {
|
||||
const { object: currentObject } = findObjectById(
|
||||
this.canvas,
|
||||
this.newObjectId
|
||||
);
|
||||
const { object: currentObject } = findObjectById(this.canvas, this.newObjectId);
|
||||
if (currentObject) {
|
||||
const removeSuccess = removeCanvasObjectByObject(
|
||||
this.canvas,
|
||||
currentObject
|
||||
);
|
||||
const removeSuccess = removeCanvasObjectByObject(this.canvas, currentObject);
|
||||
if (removeSuccess) {
|
||||
this.targetLayer.fabricObject = null;
|
||||
this.layerManager.updateLayerObject(this.targetLayer.id, null);
|
||||
@@ -976,10 +925,7 @@ export class AddImageToLayerCommand extends Command {
|
||||
this.canvas.remove(this.addedObject);
|
||||
|
||||
// 从图层管理器中移除
|
||||
this.layerManager.removeObjectFromLayer(
|
||||
this.addedObject.id,
|
||||
this.layerId
|
||||
);
|
||||
this.layerManager.removeObjectFromLayer(this.addedObject.id, this.layerId);
|
||||
|
||||
this.isExecuted = false;
|
||||
|
||||
@@ -1042,19 +988,14 @@ export class AddImageToLayerCommand extends Command {
|
||||
this.retryCount = attempt;
|
||||
|
||||
if (attempt === this.maxRetries) {
|
||||
throw new Error(
|
||||
`图像加载失败,已重试${this.maxRetries}次: ${error.message}`
|
||||
);
|
||||
throw new Error(`图像加载失败,已重试${this.maxRetries}次: ${error.message}`);
|
||||
}
|
||||
|
||||
// 指数退避重试
|
||||
const delay = Math.pow(2, attempt) * 1000;
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
|
||||
console.warn(
|
||||
`图像加载重试 ${attempt + 1}/${this.maxRetries}:`,
|
||||
error.message
|
||||
);
|
||||
console.warn(`图像加载重试 ${attempt + 1}/${this.maxRetries}:`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1062,9 +1003,7 @@ export class AddImageToLayerCommand extends Command {
|
||||
loadImage() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
reject(
|
||||
new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`)
|
||||
);
|
||||
reject(new Error(`图像加载超时 (${this.timeoutMs}ms): ${this.imageUrl}`));
|
||||
}, this.timeoutMs);
|
||||
|
||||
fabric.Image.fromURL(
|
||||
@@ -1318,23 +1257,16 @@ export class MoveLayerToTopCommand extends Command {
|
||||
|
||||
this.parentLayer = null; // 父图层
|
||||
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
|
||||
// 如果parent 有值 或者 layer 上有parentId 则视为子图层的置顶
|
||||
if (parent?.id) {
|
||||
// 查找子图层索引
|
||||
this.layerIndex = parent?.children?.findIndex(
|
||||
(layer) => layer.id === this.layerId
|
||||
);
|
||||
this.layerIndex = parent?.children?.findIndex((layer) => layer.id === this.layerId);
|
||||
this.parentLayer = parent;
|
||||
} else {
|
||||
// 查找图层索引
|
||||
this.layerIndex = this.layers.value.findIndex(
|
||||
(layer) => layer.id === this.layerId
|
||||
);
|
||||
this.layerIndex = this.layers.value.findIndex((layer) => layer.id === this.layerId);
|
||||
}
|
||||
|
||||
this.layer = layer;
|
||||
@@ -1416,23 +1348,16 @@ export class MoveLayerToBottomCommand extends Command {
|
||||
|
||||
this.parentLayer = null; // 父图层
|
||||
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
|
||||
// 如果parent 有值 或者 layer 上有parentId 则视为子图层的置顶
|
||||
if (parent?.id) {
|
||||
// 查找子图层索引
|
||||
this.layerIndex = parent?.children?.findIndex(
|
||||
(layer) => layer.id === this.layerId
|
||||
);
|
||||
this.layerIndex = parent?.children?.findIndex((layer) => layer.id === this.layerId);
|
||||
this.parentLayer = parent;
|
||||
} else {
|
||||
// 查找图层索引
|
||||
this.layerIndex = this.layers.value.findIndex(
|
||||
(layer) => layer.id === this.layerId
|
||||
);
|
||||
this.layerIndex = this.layers.value.findIndex((layer) => layer.id === this.layerId);
|
||||
}
|
||||
|
||||
this.layer = layer;
|
||||
@@ -1473,9 +1398,7 @@ export class MoveLayerToBottomCommand extends Command {
|
||||
async undo() {
|
||||
if (this.originalIndex !== -1 && this.layer) {
|
||||
// 获取当前位置
|
||||
const currentIndex = this.layers.value.findIndex(
|
||||
(layer) => layer.id === this.layerId
|
||||
);
|
||||
const currentIndex = this.layers.value.findIndex((layer) => layer.id === this.layerId);
|
||||
|
||||
if (currentIndex !== -1) {
|
||||
// 移除当前位置
|
||||
@@ -1526,16 +1449,11 @@ export class MoveLayerToBottomCommand extends Command {
|
||||
|
||||
if (layer.isBackground && layer.fabricObject) {
|
||||
// 背景图层
|
||||
const originalObj = canvasObjects.find(
|
||||
(o) => o.id === layer.fabricObject.id
|
||||
);
|
||||
const originalObj = canvasObjects.find((o) => o.id === layer.fabricObject.id);
|
||||
if (originalObj) {
|
||||
this.canvas.add(originalObj);
|
||||
}
|
||||
} else if (
|
||||
Array.isArray(layer.fabricObjects) &&
|
||||
layer.fabricObjects.length > 0
|
||||
) {
|
||||
} else if (Array.isArray(layer.fabricObjects) && layer.fabricObjects.length > 0) {
|
||||
// 普通图层和固定图层
|
||||
layer.fabricObjects.forEach((obj) => {
|
||||
const originalObj = canvasObjects.find((o) => o.id === obj.id);
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { Command } from "./Command";
|
||||
import { fabric } from "fabric-with-all";
|
||||
import {
|
||||
LayerType,
|
||||
OperationType,
|
||||
createLayer,
|
||||
findLayerRecursively,
|
||||
} from "../utils/layerHelper";
|
||||
import { LayerType, OperationType, createLayer, findLayerRecursively } from "../utils/layerHelper";
|
||||
import {
|
||||
generateId,
|
||||
optimizeCanvasRendering,
|
||||
@@ -39,10 +34,7 @@ export class RasterizeLayerCommand extends Command {
|
||||
this.layerManager = options.layerManager;
|
||||
|
||||
// 查找目标图层
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
this.layer = layer;
|
||||
this.parentLayer = parent;
|
||||
this.isGroupLayer = this.layer?.children && this.layer.children.length > 0;
|
||||
@@ -102,9 +94,7 @@ export class RasterizeLayerCommand extends Command {
|
||||
|
||||
console.log(`✅ 图层 ${this.layer.name} 栅格化完成`);
|
||||
|
||||
this.canvas?.thumbnailManager?.generateLayerThumbnail?.(
|
||||
this.rasterizedLayerId
|
||||
);
|
||||
this.canvas?.thumbnailManager?.generateLayerThumbnail?.(this.rasterizedLayerId);
|
||||
return this.rasterizedLayerId;
|
||||
} catch (error) {
|
||||
console.error("栅格化图层失败:", error);
|
||||
@@ -350,10 +340,7 @@ export class RasterizeLayerCommand extends Command {
|
||||
*/
|
||||
_replaceLayerInStructure() {
|
||||
// 1.当前如果是子图层,则插入到子图层的位置
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
|
||||
let insertIndex = 0;
|
||||
// 说明是子图层
|
||||
@@ -374,11 +361,7 @@ export class RasterizeLayerCommand extends Command {
|
||||
if (insertIndex !== -1) {
|
||||
if (parent) {
|
||||
const pIndex = this.layers.value.findIndex((l) => l.id === parent.id);
|
||||
this.layers.value[pIndex].children?.splice?.(
|
||||
insertIndex,
|
||||
1,
|
||||
this.rasterizedLayer
|
||||
);
|
||||
this.layers.value[pIndex].children?.splice?.(insertIndex, 1, this.rasterizedLayer);
|
||||
} else {
|
||||
this.layers.value.splice(insertIndex, 1, this.rasterizedLayer);
|
||||
}
|
||||
@@ -396,14 +379,9 @@ export class RasterizeLayerCommand extends Command {
|
||||
async _getMaskObject() {
|
||||
// 如果图层有clippingMask,获取对应的fabric对象
|
||||
if (this.layer?.clippingMask) {
|
||||
const { object: maskObject } = findObjectById(
|
||||
this.canvas,
|
||||
this.layer.clippingMask.id
|
||||
);
|
||||
const { object: maskObject } = findObjectById(this.canvas, this.layer.clippingMask.id);
|
||||
if (maskObject) {
|
||||
console.log(
|
||||
`📎 找到遮罩对象: ${maskObject.id}, 类型: ${maskObject.type}`
|
||||
);
|
||||
console.log(`📎 找到遮罩对象: ${maskObject.id}, 类型: ${maskObject.type}`);
|
||||
return maskObject;
|
||||
}
|
||||
return await restoreFabricObject(this.layer.clippingMask);
|
||||
@@ -449,10 +427,7 @@ export class ExportLayerToImageCommand extends Command {
|
||||
this.layerManager = options.layerManager;
|
||||
|
||||
// 查找目标图层
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
this.layer = layer;
|
||||
this.parentLayer = parent;
|
||||
this.isGroupLayer = this.layer?.children && this.layer.children.length > 0;
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
findObjectById,
|
||||
generateId,
|
||||
optimizeCanvasRendering,
|
||||
} from "../utils/helper.js";
|
||||
import { findObjectById, generateId, optimizeCanvasRendering } from "../utils/helper.js";
|
||||
import { imageModeHandler } from "../utils/imageHelper.js";
|
||||
import { LayerType, OperationType } from "../utils/layerHelper.js";
|
||||
import { Command, CompositeCommand } from "./Command.js";
|
||||
@@ -58,9 +54,7 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
||||
const layers = this.layerManager.layers?.value || [];
|
||||
const backgroundLayer = layers.find((layer) => layer.isBackground);
|
||||
const fixedLayer = layers.find((layer) => layer.isFixed);
|
||||
const normalLayers = layers.filter(
|
||||
(layer) => !layer.isBackground && !layer.isFixed
|
||||
);
|
||||
const normalLayers = layers.filter((layer) => !layer.isBackground && !layer.isFixed);
|
||||
|
||||
if (!backgroundLayer || !fixedLayer || normalLayers.length === 0) {
|
||||
throw new Error("缺少必要的图层结构");
|
||||
@@ -76,9 +70,7 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
||||
}
|
||||
: null;
|
||||
|
||||
this.originalFixedObjects = fixedLayer.fabricObject
|
||||
? [fixedLayer.fabricObject]
|
||||
: [];
|
||||
this.originalFixedObjects = fixedLayer.fabricObject ? [fixedLayer.fabricObject] : [];
|
||||
|
||||
this.originalNormalObjects = normalLayer.fabricObjects
|
||||
? [...normalLayer.fabricObjects]
|
||||
@@ -118,11 +110,7 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
||||
await this._setupClothingImage(clothingImg, fixedLayer);
|
||||
|
||||
// 7. 设置红绿图到普通图层,位置和大小与衣服底图一致
|
||||
await this._setupRedGreenImage(
|
||||
redGreenImg,
|
||||
normalLayer,
|
||||
this.clothingImage
|
||||
);
|
||||
await this._setupRedGreenImage(redGreenImg, normalLayer, this.clothingImage);
|
||||
|
||||
// 4. 确保背景图层大小和衣服地图大小一致
|
||||
const backgroundObject = await this._setupBackgroundLayer(
|
||||
@@ -207,13 +195,9 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
||||
async _createAndActivateEmptyLayer() {
|
||||
// 创建新的空白图层
|
||||
const newLayerName = "绘制图层";
|
||||
const newLayerId = await this.layerManager.createLayer(
|
||||
newLayerName,
|
||||
LayerType.BITMAP,
|
||||
{
|
||||
undoable: false,
|
||||
}
|
||||
);
|
||||
const newLayerId = await this.layerManager.createLayer(newLayerName, LayerType.BITMAP, {
|
||||
undoable: false,
|
||||
});
|
||||
|
||||
// 设置为活动图层
|
||||
if (newLayerId) {
|
||||
@@ -228,19 +212,14 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
||||
await optimizeCanvasRendering(this.canvas, async () => {
|
||||
// 1. 恢复画布背景
|
||||
if (this.originalCanvasBackground !== null) {
|
||||
this.canvas.setBackgroundColor(
|
||||
this.originalCanvasBackground,
|
||||
() => {}
|
||||
);
|
||||
this.canvas.setBackgroundColor(this.originalCanvasBackground, () => {});
|
||||
}
|
||||
|
||||
// 2. 恢复图层对象
|
||||
const layers = this.layerManager.layers?.value || [];
|
||||
const backgroundLayer = layers.find((layer) => layer.isBackground);
|
||||
const fixedLayer = layers.find((layer) => layer.isFixed);
|
||||
const normalLayers = layers.filter(
|
||||
(layer) => !layer.isBackground && !layer.isFixed
|
||||
);
|
||||
const normalLayers = layers.filter((layer) => !layer.isBackground && !layer.isFixed);
|
||||
|
||||
// 移除当前添加的对象
|
||||
if (this.clothingImage) {
|
||||
@@ -252,9 +231,7 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
||||
|
||||
// 移除新创建的空白图层
|
||||
if (this.newEmptyLayerId) {
|
||||
const emptyLayerIndex = layers.findIndex(
|
||||
(layer) => layer.id === this.newEmptyLayerId
|
||||
);
|
||||
const emptyLayerIndex = layers.findIndex((layer) => layer.id === this.newEmptyLayerId);
|
||||
if (emptyLayerIndex !== -1) {
|
||||
layers.splice(emptyLayerIndex, 1);
|
||||
}
|
||||
@@ -270,9 +247,7 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
||||
// 恢复固定图层
|
||||
if (fixedLayer) {
|
||||
fixedLayer.fabricObject =
|
||||
this.originalFixedObjects.length > 0
|
||||
? this.originalFixedObjects[0]
|
||||
: null;
|
||||
this.originalFixedObjects.length > 0 ? this.originalFixedObjects[0] : null;
|
||||
|
||||
if (fixedLayer.fabricObject) {
|
||||
this.canvas.add(fixedLayer.fabricObject);
|
||||
@@ -311,8 +286,7 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
||||
|
||||
// 4. 恢复工具状态
|
||||
if (this.toolManager && this.originalToolState) {
|
||||
this.toolManager.isRedGreenMode =
|
||||
this.originalToolState.isRedGreenMode;
|
||||
this.toolManager.isRedGreenMode = this.originalToolState.isRedGreenMode;
|
||||
if (this.originalToolState.currentTool) {
|
||||
this.toolManager.setTool(this.originalToolState.currentTool);
|
||||
}
|
||||
@@ -434,10 +408,7 @@ export class BatchInitializeRedGreenModeCommand extends Command {
|
||||
|
||||
// 清除固定图层原有内容
|
||||
if (fixedLayer.fabricObject) {
|
||||
const { object } = findObjectById(
|
||||
this.canvas,
|
||||
fixedLayer.fabricObject.id
|
||||
);
|
||||
const { object } = findObjectById(this.canvas, fixedLayer.fabricObject.id);
|
||||
if (object) this.canvas.remove(object);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,9 +110,7 @@ export class AddToSelectionCommand extends Command {
|
||||
}
|
||||
|
||||
// 添加到选区
|
||||
const result = await this.selectionManager.addToSelection(
|
||||
this.newSelection
|
||||
);
|
||||
const result = await this.selectionManager.addToSelection(this.newSelection);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -155,9 +153,7 @@ export class RemoveFromSelectionCommand extends Command {
|
||||
}
|
||||
|
||||
// 从选区中移除
|
||||
const result = await this.selectionManager.removeFromSelection(
|
||||
this.removeSelection
|
||||
);
|
||||
const result = await this.selectionManager.removeFromSelection(this.removeSelection);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -203,9 +199,7 @@ export class FeatherSelectionCommand extends Command {
|
||||
}
|
||||
|
||||
// 应用羽化
|
||||
const result = await this.selectionManager.featherSelection(
|
||||
this.featherAmount
|
||||
);
|
||||
const result = await this.selectionManager.featherSelection(this.featherAmount);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -347,8 +341,7 @@ export class CopySelectionToNewLayerCommand extends CompositeCommand {
|
||||
}
|
||||
|
||||
// 确定源图层
|
||||
const sourceId =
|
||||
this.sourceLayerId || this.layerManager.getActiveLayerId();
|
||||
const sourceId = this.sourceLayerId || this.layerManager.getActiveLayerId();
|
||||
const sourceLayer = this.layerManager.getLayerById(sourceId);
|
||||
if (!sourceLayer || !sourceLayer.fabricObjects) {
|
||||
console.error("无法复制选区:源图层无效或为空");
|
||||
@@ -356,10 +349,7 @@ export class CopySelectionToNewLayerCommand extends CompositeCommand {
|
||||
}
|
||||
|
||||
// 创建新图层
|
||||
this.newLayerId = await this.layerManager.createLayer(
|
||||
this.newLayerName,
|
||||
LayerType.EMPTY
|
||||
);
|
||||
this.newLayerId = await this.layerManager.createLayer(this.newLayerName, LayerType.EMPTY);
|
||||
|
||||
// 获取选区内的对象
|
||||
const objectsToCopy = sourceLayer.fabricObjects.filter((obj) => {
|
||||
|
||||
@@ -401,9 +401,7 @@ export class CreateTextCommand extends Command {
|
||||
// 更新图层的对象列表
|
||||
if (layer) {
|
||||
layer.fabricObjects = layer.fabricObjects || [];
|
||||
layer.fabricObjects.push(
|
||||
this.textObject.toObject(["id", "layerId", "layerName"])
|
||||
);
|
||||
layer.fabricObjects.push(this.textObject.toObject(["id", "layerId", "layerName"]));
|
||||
}
|
||||
|
||||
// 现在可以安全地设置为活动图层
|
||||
@@ -416,9 +414,7 @@ export class CreateTextCommand extends Command {
|
||||
this.layerManager?.toolManager?.setTool?.(OperationType.SELECT);
|
||||
});
|
||||
|
||||
console.log(
|
||||
`✅ 文本对象已创建: "${finalOptions.text}",位置: (${this.x}, ${this.y})`
|
||||
);
|
||||
console.log(`✅ 文本对象已创建: "${finalOptions.text}",位置: (${this.x}, ${this.y})`);
|
||||
return this.textObject;
|
||||
} catch (error) {
|
||||
console.error("创建文本对象失败:", error);
|
||||
@@ -467,15 +463,11 @@ export class CreateTextCommand extends Command {
|
||||
parentLayer.children = parentLayer.children || [];
|
||||
parentLayer.children.splice(insertIndex, 0, newLayer);
|
||||
|
||||
console.log(
|
||||
`新图层已插入到子图层位置: ${insertIndex} (父图层: ${parentLayer.name})`
|
||||
);
|
||||
console.log(`新图层已插入到子图层位置: ${insertIndex} (父图层: ${parentLayer.name})`);
|
||||
} else {
|
||||
// 当前激活图层是一级图层
|
||||
// 在一级图层中,插入到激活图层之上
|
||||
const activeLayerIndex = layers.findIndex(
|
||||
(layer) => layer.id === currentActiveLayerId
|
||||
);
|
||||
const activeLayerIndex = layers.findIndex((layer) => layer.id === currentActiveLayerId);
|
||||
insertIndex = Math.max(0, activeLayerIndex);
|
||||
layers.splice(insertIndex, 0, newLayer);
|
||||
|
||||
@@ -551,9 +543,7 @@ export class CreateTextCommand extends Command {
|
||||
// 恢复原活动图层
|
||||
if (this.oldActiveLayerId && this.layerManager) {
|
||||
// 检查原活动图层是否还存在
|
||||
const originalLayer = this.layerManager.getLayerById(
|
||||
this.oldActiveLayerId
|
||||
);
|
||||
const originalLayer = this.layerManager.getLayerById(this.oldActiveLayerId);
|
||||
if (originalLayer) {
|
||||
this.layerManager.setActiveLayer(this.oldActiveLayerId);
|
||||
} else {
|
||||
@@ -603,9 +593,7 @@ export class CreateTextCommand extends Command {
|
||||
// 从子图层中移除
|
||||
if (positionInfo.parent.children && positionInfo.index >= 0) {
|
||||
positionInfo.parent.children.splice(positionInfo.index, 1);
|
||||
console.log(
|
||||
`已从子图层移除: ${this.layerId} (父图层: ${positionInfo.parent.name})`
|
||||
);
|
||||
console.log(`已从子图层移除: ${this.layerId} (父图层: ${positionInfo.parent.name})`);
|
||||
}
|
||||
} else {
|
||||
// 从一级图层中移除
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
import { findLayerRecursively } from "../utils/layerHelper";
|
||||
import { restoreFabricObject } from "../utils/objectHelper";
|
||||
import { Command } from "./Command";
|
||||
|
||||
/**
|
||||
* 更新组图层遮罩位置命令
|
||||
* 当组图层的对象移动时,同步更新遮罩的位置
|
||||
*/
|
||||
export class UpdateGroupMaskPositionCommand extends Command {
|
||||
constructor(options) {
|
||||
super({
|
||||
name: "更新组图层遮罩位置",
|
||||
saveState: true,
|
||||
});
|
||||
|
||||
this.canvas = options.canvas;
|
||||
this.layers = options.layers;
|
||||
this.layerManager = options.layerManager;
|
||||
this.layerId = options.layerId;
|
||||
this.deltaX = options.deltaX || 0;
|
||||
this.deltaY = options.deltaY || 0;
|
||||
this.maskInitialLeft = options.maskInitialLeft || 0;
|
||||
this.maskInitialTop = options.maskInitialTop || 0;
|
||||
this.isExecuteRealtime = options.isExecuteRealtime || false;
|
||||
this.activeSelection = this.canvas.getActiveObject() || {};
|
||||
|
||||
this.isFristExecute = true;
|
||||
|
||||
// 查找目标图层
|
||||
this.layer = findLayerRecursively(this.layers.value, this.layerId)?.layer;
|
||||
|
||||
if (!this.layer || !this.layer.clippingMask) {
|
||||
console.warn(`图层 ${this.layerId} 不存在或没有遮罩`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 保存原始遮罩位置(用于撤销)
|
||||
// 保存原始位置
|
||||
this.originalMaskPosition = {
|
||||
left: this.maskInitialLeft || 0,
|
||||
top: this.maskInitialTop || 0,
|
||||
};
|
||||
|
||||
// 收集当前选择的所有对象位置
|
||||
this.originalObjectsPostion = this.activeSelection.getObjects().map((obj) => {
|
||||
return {
|
||||
left: obj.left || 0,
|
||||
top: obj.top || 0,
|
||||
id: obj.id,
|
||||
};
|
||||
});
|
||||
|
||||
this.originalSelectionPosition = {
|
||||
left: this.activeSelection.left || 0,
|
||||
top: this.activeSelection.top || 0,
|
||||
};
|
||||
|
||||
console.log(
|
||||
`🛠️ 初始化更新组图层遮罩位置命令: ${this.name}, 图层ID: ${this.layerId}, 初始位置: (${this.originalMaskPosition.left}, ${this.originalMaskPosition.top})`
|
||||
);
|
||||
this.newMaskPosition = null;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
try {
|
||||
// 计算新位置
|
||||
const newLeft = this.maskInitialLeft + this.deltaX;
|
||||
const newTop = this.maskInitialTop + this.deltaY;
|
||||
|
||||
// 更新遮罩位置
|
||||
this.layer.clippingMask.left = newLeft;
|
||||
this.layer.clippingMask.top = newTop;
|
||||
|
||||
this.newMaskPosition = {
|
||||
left: newLeft,
|
||||
top: newTop,
|
||||
};
|
||||
|
||||
// 更新所有使用此遮罩的子图层对象
|
||||
await this._updateChildObjectsClipPath(this.layer, false, true);
|
||||
|
||||
this.isFristExecute = false;
|
||||
console.log(`✅ 组图层遮罩位置已更新: (${newLeft}, ${newTop})`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("更新组图层遮罩位置失败:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async undo() {
|
||||
try {
|
||||
if (!this.originalMaskPosition) {
|
||||
console.warn("没有原始遮罩位置数据,无法撤销");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 查找目标图层
|
||||
const layer = this.layers.value.find((l) => l.id === this.layerId);
|
||||
if (!layer || !layer.clippingMask) {
|
||||
console.warn(`图层 ${this.layerId} 不存在或没有遮罩`);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`↶ 撤销更新组图层遮罩位置: ${this.originalMaskPosition.left}, 图层ID: ${this.originalMaskPosition.top}`
|
||||
);
|
||||
// 恢复原始位置
|
||||
layer.clippingMask.left = this.originalMaskPosition.left;
|
||||
layer.clippingMask.top = this.originalMaskPosition.top;
|
||||
|
||||
// 更新所有使用此遮罩的子图层对象
|
||||
await this._updateChildObjectsClipPath(layer, true);
|
||||
// await this.layerManager.updateLayersObjectsInteractivity();
|
||||
// this.canvas.renderAll();
|
||||
|
||||
console.log(
|
||||
`↶ 组图层遮罩位置已恢复: (${this.originalMaskPosition.left}, ${this.originalMaskPosition.top})`
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("撤销组图层遮罩位置更新失败:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实时执行(不记录到历史记录)
|
||||
* 用于拖拽过程中的实时更新
|
||||
*/
|
||||
executeRealtime() {
|
||||
try {
|
||||
// 查找目标图层
|
||||
const layer = this.layers.value.find((l) => l.id === this.layerId);
|
||||
if (!layer || !layer.clippingMask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算新位置
|
||||
const newLeft = this.maskInitialLeft + this.deltaX;
|
||||
const newTop = this.maskInitialTop + this.deltaY;
|
||||
|
||||
// 更新遮罩位置
|
||||
layer.clippingMask.left = newLeft;
|
||||
layer.clippingMask.top = newTop;
|
||||
|
||||
// 更新所有使用此遮罩的子图层对象(不需要等待)
|
||||
this._updateChildObjectsClipPath(layer);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("实时更新组图层遮罩位置失败:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新子图层对象的裁剪路径
|
||||
* @param {Object} layer 组图层对象
|
||||
* @private
|
||||
*/
|
||||
async _updateChildObjectsClipPath(layer, isUndo = false, isExecute = false) {
|
||||
if (!layer.children || layer.children.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 重新创建遮罩对象
|
||||
const clippingMaskFabricObject = await restoreFabricObject(layer.clippingMask, this.canvas);
|
||||
|
||||
if (!clippingMaskFabricObject) {
|
||||
console.warn("无法恢复遮罩对象");
|
||||
return;
|
||||
}
|
||||
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
clippingMaskFabricObject.set({
|
||||
absolutePositioned: true,
|
||||
});
|
||||
|
||||
clippingMaskFabricObject.dirty = true;
|
||||
clippingMaskFabricObject.setCoords();
|
||||
|
||||
// 更新所有子图层对象的裁剪路径
|
||||
layer.children.forEach((childLayer) => {
|
||||
// 更新 fabricObjects 中的对象
|
||||
childLayer.fabricObjects?.forEach((obj) => {
|
||||
const fabricObject = this.canvas.getObjects().find((o) => o.id === obj.id);
|
||||
if (fabricObject) {
|
||||
fabricObject.clipPath = clippingMaskFabricObject;
|
||||
fabricObject.dirty = true;
|
||||
fabricObject.setCoords();
|
||||
}
|
||||
});
|
||||
|
||||
// 更新单个 fabricObject
|
||||
if (childLayer.fabricObject) {
|
||||
const fabricObject = this.canvas
|
||||
.getObjects()
|
||||
.find((o) => o.id === childLayer.fabricObject.id);
|
||||
if (fabricObject) {
|
||||
fabricObject.clipPath = clippingMaskFabricObject;
|
||||
fabricObject.dirty = true;
|
||||
fabricObject.setCoords();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (isUndo) {
|
||||
this.activeSelection.set({
|
||||
left: this.originalSelectionPosition.left - this.deltaX,
|
||||
top: this.originalSelectionPosition.top - this.deltaY,
|
||||
});
|
||||
this.activeSelection.dirty = true;
|
||||
this.activeSelection.setCoords();
|
||||
}
|
||||
|
||||
if (isExecute && !this.isFristExecute) {
|
||||
this.activeSelection.set({
|
||||
left: this.activeSelection.left + this.deltaX,
|
||||
top: this.activeSelection.top + this.deltaY,
|
||||
});
|
||||
this.activeSelection.dirty = true;
|
||||
this.activeSelection.setCoords();
|
||||
}
|
||||
|
||||
// 触发画布重新渲染
|
||||
this.canvas.renderAll();
|
||||
} catch (error) {
|
||||
console.error("更新子图层对象裁剪路径失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
getInfo() {
|
||||
return {
|
||||
name: this.name,
|
||||
layerId: this.layerId,
|
||||
deltaX: this.deltaX,
|
||||
deltaY: this.deltaY,
|
||||
originalPosition: this.originalMaskPosition,
|
||||
newPosition: this.newMaskPosition,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user