feat: 完善选区功能,新增组图层自由编辑

This commit is contained in:
bighuixiang
2025-07-08 01:08:45 +08:00
parent 0615ab31f9
commit 5cc93aeba4
7 changed files with 1751 additions and 161 deletions

View File

@@ -0,0 +1,767 @@
import { Command } from "./Command";
import { isGroupLayer } from "../utils/layerHelper";
/**
* 跨层级移动命令基类
*/
export class CrossLevelMoveCommand extends Command {
constructor(options) {
super({
name: "跨层级移动",
undoable: true,
});
this.layers = options.layers;
this.layerManager = options.layerManager;
this.canvas = options.canvas;
// 移动相关参数
this.layerId = options.layerId;
this.fromContainerType = options.fromContainerType; // 'root' | 'child'
this.toContainerType = options.toContainerType; // 'root' | 'child'
this.fromParentId = options.fromParentId;
this.toParentId = options.toParentId;
this.newIndex = options.newIndex;
this.oldIndex = options.oldIndex;
// 保存状态用于撤销
this.beforeState = null;
this.afterState = null;
}
/**
* 保存移动前的状态
*/
saveBeforeState() {
this.beforeState = {
layerStructure: this.cloneLayerStructure(),
fabricObjects: this.saveFabricObjectStates(),
};
}
/**
* 保存移动后的状态
*/
saveAfterState() {
this.afterState = {
layerStructure: this.cloneLayerStructure(),
fabricObjects: this.saveFabricObjectStates(),
};
}
/**
* 克隆图层结构
*/
cloneLayerStructure() {
return JSON.parse(
JSON.stringify(
this.layers.value.map((layer) => ({
id: layer.id,
name: layer.name,
parentId: layer.parentId,
children: layer.children
? layer.children.map((child) => ({
id: child.id,
name: child.name,
parentId: child.parentId,
}))
: [],
isBackground: layer.isBackground,
isFixed: layer.isFixed,
visible: layer.visible,
locked: layer.locked,
}))
)
);
}
/**
* 保存fabric对象状态
*/
saveFabricObjectStates() {
const states = {};
// 只保存fabric对象的容器关系不保存具体的属性
this.layers.value.forEach((layer) => {
if (layer.fabricObject) {
states[layer.id] = {
isInCanvas: this.canvas
? this.canvas.contains(layer.fabricObject)
: false,
parentGroupId: null,
visible: layer.fabricObject.visible,
};
// 检查是否在某个组中
this.layers.value.forEach((otherLayer) => {
if (
otherLayer.fabricObject &&
otherLayer.fabricObject.type === "group" &&
otherLayer.fabricObject.contains &&
otherLayer.fabricObject.contains(layer.fabricObject)
) {
states[layer.id].parentGroupId = otherLayer.id;
states[layer.id].isInCanvas = false;
}
});
}
});
return states;
}
/**
* 查找图层
*/
findLayer(layerId, containerType, parentId) {
if (containerType === "root") {
return this.layers.value.find((layer) => layer.id === layerId);
} else if (containerType === "child" && parentId) {
const parent = this.layers.value.find((layer) => layer.id === parentId);
return parent?.children?.find((child) => child.id === layerId);
}
return null;
}
/**
* 验证移动的有效性
*/
validateMove() {
const layer = this.findLayer(
this.layerId,
this.fromContainerType,
this.fromParentId
);
if (!layer) {
throw new Error(`找不到要移动的图层: ${this.layerId}`);
}
// 检查是否为不可移动的图层
if (layer.isBackground || layer.isFixed) {
throw new Error("背景层和固定层不能移动");
}
// 检查是否试图将图层移动到自己的子层级中(防止循环引用)
if (
this.toContainerType === "child" &&
this.toParentId &&
this.isDescendantOf(this.toParentId, this.layerId)
) {
throw new Error("不能将图层移动到自己的子层级中");
}
// 检查目标父图层是否为组
if (this.toContainerType === "child") {
const targetParent = this.layers.value.find(
(layer) => layer.id === this.toParentId
);
if (!targetParent || !isGroupLayer(targetParent)) {
throw new Error("目标图层不是组图层");
}
}
return layer;
}
/**
* 检查是否为子层级关系(防止循环引用)
*/
isDescendantOf(ancestorId, layerId) {
const checkChildren = (children) => {
if (!children) return false;
for (const child of children) {
if (child.id === layerId) return true;
if (child.children && checkChildren(child.children)) return true;
}
return false;
};
const ancestor = this.layers.value.find((layer) => layer.id === ancestorId);
return ancestor ? checkChildren(ancestor.children) : false;
}
execute() {
console.log("🎯 执行跨层级移动命令:", {
layerId: this.layerId,
from: this.fromContainerType,
to: this.toContainerType,
fromParentId: this.fromParentId,
toParentId: this.toParentId,
});
// 验证移动
const draggedLayer = this.validateMove();
// 保存移动前状态
this.saveBeforeState();
try {
// 根据移动类型执行对应操作
if (
this.fromContainerType === "root" &&
this.toContainerType === "child"
) {
this.moveRootToGroup(draggedLayer);
} else if (
this.fromContainerType === "child" &&
this.toContainerType === "root"
) {
this.moveGroupToRoot(draggedLayer);
} else if (
this.fromContainerType === "child" &&
this.toContainerType === "child" &&
this.fromParentId !== this.toParentId
) {
this.moveGroupToGroup(draggedLayer);
}
// 保存移动后状态
this.saveAfterState();
// 刷新画布
if (this.canvas) {
this.canvas.renderAll();
console.log("🎨 画布已刷新");
}
console.log("✅ 跨层级移动命令执行成功");
return true;
} catch (error) {
console.error("❌ 跨层级移动命令执行失败:", error);
// 如果执行失败,尝试恢复到之前的状态
if (this.beforeState) {
try {
this.restoreLayerStructure(this.beforeState.layerStructure);
this.restoreFabricObjectStates(this.beforeState.fabricObjects);
if (this.canvas) {
this.canvas.renderAll();
}
console.log("🔄 已恢复到移动前状态");
} catch (restoreError) {
console.error("❌ 恢复状态失败:", restoreError);
}
}
throw error;
}
}
undo() {
if (!this.beforeState) {
throw new Error("没有保存的前置状态,无法撤销");
}
console.log("🔄 撤销跨层级移动命令");
try {
// 恢复图层结构
this.restoreLayerStructure(this.beforeState.layerStructure);
// 恢复fabric对象状态
this.restoreFabricObjectStates(this.beforeState.fabricObjects);
// 刷新画布
if (this.canvas) {
// 使用 requestAnimationFrame 确保DOM更新完成后再渲染
requestAnimationFrame(() => {
this.canvas.renderAll();
});
}
console.log("✅ 跨层级移动命令撤销成功");
return true;
} catch (error) {
console.error("❌ 跨层级移动命令撤销失败:", error);
// 尝试基本的恢复操作
try {
console.log("🔄 尝试基本恢复操作");
this.basicRestore();
} catch (restoreError) {
console.error("❌ 基本恢复也失败:", restoreError);
}
throw error;
}
}
/**
* 基本恢复操作(当标准撤销失败时使用)
*/
basicRestore() {
// 重新组织所有图层的fabric对象
this.layers.value.forEach((layer) => {
if (layer.fabricObject) {
try {
// 先从所有容器中移除
this.removeFromAllContainers(layer.fabricObject);
// 根据图层的parentId重新放置
if (layer.parentId) {
const parentLayer = this.layers.value.find(
(l) => l.id === layer.parentId
);
if (
parentLayer &&
parentLayer.fabricObject &&
parentLayer.fabricObject.type === "group"
) {
this.safeAddToContainer(
layer.fabricObject,
parentLayer.fabricObject,
`父组${layer.parentId}`
);
}
} else {
this.safeAddToContainer(layer.fabricObject, this.canvas, "画布");
}
} catch (error) {
console.error(`❌ 基本恢复图层 ${layer.id} 失败:`, error);
}
}
});
if (this.canvas) {
this.canvas.renderAll();
}
}
/**
* 重做命令
*/
redo() {
if (!this.afterState) {
throw new Error("没有保存的后置状态,无法重做");
}
console.log("🔄 重做跨层级移动命令");
try {
// 恢复图层结构
this.restoreLayerStructure(this.afterState.layerStructure);
// 恢复fabric对象状态
this.restoreFabricObjectStates(this.afterState.fabricObjects);
// 刷新画布
if (this.canvas) {
// 使用 requestAnimationFrame 确保DOM更新完成后再渲染
requestAnimationFrame(() => {
this.canvas.renderAll();
});
}
console.log("✅ 跨层级移动命令重做成功");
return true;
} catch (error) {
console.error("❌ 跨层级移动命令重做失败:", error);
// 尝试基本的恢复操作
try {
console.log("🔄 尝试基本恢复操作");
this.basicRestore();
} catch (restoreError) {
console.error("❌ 基本恢复也失败:", restoreError);
}
throw error;
}
}
/**
* 恢复图层结构
*/
restoreLayerStructure(layerStructure) {
// 保存原始图层数组的引用
const originalLayers = [...this.layers.value];
// 清空当前图层
this.layers.value.splice(0);
// 重建图层结构
layerStructure.forEach((layerData) => {
// 首先从原始图层数组中查找图层
let layer = originalLayers.find((l) => l.id === layerData.id);
// 如果没找到,尝试在嵌套结构中查找
if (!layer) {
layer = this.findLayerInOriginalStructure(layerData.id, originalLayers);
}
if (layer) {
// 更新图层属性
layer.parentId = layerData.parentId;
layer.visible = layerData.visible;
layer.locked = layerData.locked;
// 重建children数组
if (layerData.children && layerData.children.length > 0) {
layer.children = layerData.children
.map((childData) => {
// 从原始图层数组中查找子图层
let childLayer = originalLayers.find(
(l) => l.id === childData.id
);
if (!childLayer) {
childLayer = this.findLayerInOriginalStructure(
childData.id,
originalLayers
);
}
if (childLayer) {
// 更新子图层属性
childLayer.parentId = childData.parentId;
childLayer.visible = childData.visible;
childLayer.locked = childData.locked;
return childLayer;
}
return null;
})
.filter(Boolean);
} else {
layer.children = [];
}
this.layers.value.push(layer);
}
});
}
/**
* 在原始结构中查找图层
*/
findLayerInOriginalStructure(layerId, layers = null) {
const layersToSearch = layers || this.layers.value;
const findInLayers = (layersList) => {
for (const layer of layersList) {
if (layer.id === layerId) return layer;
if (layer.children) {
const found = findInLayers(layer.children);
if (found) return found;
}
}
return null;
};
return findInLayers(layersToSearch);
}
/**
* 恢复fabric对象状态
*/
restoreFabricObjectStates(fabricStates) {
if (!this.canvas || !fabricStates) return;
console.log("🔧 开始恢复fabric对象状态");
// 重新组织fabric对象的层级关系
this.layers.value.forEach((layer) => {
if (layer.fabricObject && fabricStates[layer.id]) {
const targetState = fabricStates[layer.id];
console.log(`🔍 恢复图层 ${layer.id} 的fabric对象状态:`, targetState);
try {
// 首先从所有容器中移除对象
this.removeFromAllContainers(layer.fabricObject);
// 根据目标状态放置对象
if (targetState.parentGroupId) {
// 应该在特定组中
const parentLayer = this.layers.value.find(
(l) => l.id === targetState.parentGroupId
);
if (
parentLayer &&
parentLayer.fabricObject &&
parentLayer.fabricObject.type === "group"
) {
this.safeAddToContainer(
layer.fabricObject,
parentLayer.fabricObject,
`父组${targetState.parentGroupId}`
);
}
} else if (targetState.isInCanvas) {
// 应该在画布中
this.safeAddToContainer(layer.fabricObject, this.canvas, "画布");
}
// 恢复可见性
if (layer.fabricObject.visible !== targetState.visible) {
layer.fabricObject.visible = targetState.visible;
}
} catch (error) {
console.error(`❌ 恢复图层 ${layer.id} 的fabric对象时出错:`, error);
}
}
});
// 强制重新渲染画布
if (this.canvas) {
this.canvas.renderAll();
console.log("✅ 画布已重新渲染");
}
}
/**
* 安全地处理fabric对象操作
*/
safeFabricOperation(operation, operationName = "fabric操作") {
try {
return operation();
} catch (error) {
console.error(`${operationName}失败:`, error);
return false;
}
}
/**
* 安全地添加fabric对象到容器
*/
safeAddToContainer(fabricObject, container, containerName) {
return this.safeFabricOperation(() => {
if (container && container.add && !container.contains(fabricObject)) {
container.add(fabricObject);
console.log(`✅ 成功将对象添加到${containerName}`);
return true;
}
return false;
}, `添加对象到${containerName}`);
}
/**
* 安全地从容器移除fabric对象
*/
safeRemoveFromContainer(fabricObject, container, containerName) {
return this.safeFabricOperation(() => {
if (
container &&
container.remove &&
container.contains &&
container.contains(fabricObject)
) {
container.remove(fabricObject);
console.log(`✅ 成功从${containerName}移除对象`);
return true;
}
return false;
}, `${containerName}移除对象`);
}
/**
* 从所有容器中移除fabric对象
*/
removeFromAllContainers(fabricObject) {
// 从画布中移除
this.safeRemoveFromContainer(fabricObject, this.canvas, "画布");
// 从所有组中移除
this.layers.value.forEach((layer) => {
if (layer.fabricObject && layer.fabricObject.type === "group") {
this.safeRemoveFromContainer(
fabricObject,
layer.fabricObject,
`${layer.id}`
);
}
});
}
/**
* 从顶级图层移动到组图层内
*/
moveRootToGroup(draggedLayer) {
console.log("📥 执行顶级图层移动到组内:", {
layerId: draggedLayer.id,
toParentId: this.toParentId,
newIndex: this.newIndex,
});
const targetParent = this.layers.value.find(
(layer) => layer.id === this.toParentId
);
if (!targetParent) {
throw new Error(`找不到目标父图层: ${this.toParentId}`);
}
// 确保父图层有children数组
if (!targetParent.children) {
targetParent.children = [];
}
// 从顶级图层数组中移除
const rootIndex = this.layers.value.findIndex(
(layer) => layer.id === draggedLayer.id
);
if (rootIndex !== -1) {
this.layers.value.splice(rootIndex, 1);
console.log(`🗑️ 从顶级图层数组中移除图层 ${draggedLayer.id}`);
}
// 更新图层关系
draggedLayer.parentId = this.toParentId;
targetParent.children.splice(this.newIndex, 0, draggedLayer);
console.log(
`📂 将图层 ${draggedLayer.id} 添加到父图层 ${this.toParentId} 的children中`
);
// 处理fabric对象的层级关系
if (draggedLayer.fabricObject && targetParent.fabricObject) {
console.log(`🎨 处理fabric对象层级关系`);
// 从画布中移除
this.safeRemoveFromContainer(
draggedLayer.fabricObject,
this.canvas,
"画布"
);
// 添加到父组
this.safeAddToContainer(
draggedLayer.fabricObject,
targetParent.fabricObject,
`父组${this.toParentId}`
);
}
console.log("✅ 顶级图层移动到组内完成");
}
/**
* 从组图层内移动到顶级图层
*/
moveGroupToRoot(draggedLayer) {
console.log("📤 执行组内图层移动到顶级:", {
layerId: draggedLayer.id,
fromParentId: this.fromParentId,
newIndex: this.newIndex,
});
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
);
if (childIndex !== -1) {
sourceParent.children.splice(childIndex, 1);
console.log(
`🗑️ 从父图层 ${this.fromParentId} 的children中移除图层 ${draggedLayer.id}`
);
}
// 处理fabric对象的层级关系
if (draggedLayer.fabricObject && sourceParent.fabricObject) {
console.log(`🎨 处理fabric对象层级关系`);
// 从父组中移除
this.safeRemoveFromContainer(
draggedLayer.fabricObject,
sourceParent.fabricObject,
`父组${this.fromParentId}`
);
// 添加到画布
this.safeAddToContainer(draggedLayer.fabricObject, this.canvas, "画布");
}
// 清除图层的parentId
delete draggedLayer.parentId;
console.log(`🔗 清除图层 ${draggedLayer.id} 的parentId`);
// 计算在顶级图层中的插入位置
const targetIndex = Math.min(this.newIndex, this.layers.value.length);
this.layers.value.splice(targetIndex, 0, draggedLayer);
console.log(
`📂 将图层 ${draggedLayer.id} 添加到顶级图层数组位置 ${targetIndex}`
);
console.log("✅ 组内图层移动到顶级完成");
}
/**
* 在不同组之间移动
*/
moveGroupToGroup(draggedLayer) {
console.log("🔄 执行在不同组间移动:", {
layerId: draggedLayer.id,
fromParentId: this.fromParentId,
toParentId: this.toParentId,
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
);
if (!sourceParent || !targetParent) {
throw new Error("找不到源父图层或目标父图层");
}
// 从源父图层中移除
const childIndex = sourceParent.children.findIndex(
(child) => child.id === draggedLayer.id
);
if (childIndex !== -1) {
sourceParent.children.splice(childIndex, 1);
console.log(
`🗑️ 从源父图层 ${this.fromParentId} 中移除图层 ${draggedLayer.id}`
);
// 从源父组的fabricObject中移除
if (draggedLayer.fabricObject && sourceParent.fabricObject) {
this.safeRemoveFromContainer(
draggedLayer.fabricObject,
sourceParent.fabricObject,
`源父组${this.fromParentId}`
);
}
}
// 更新图层的parentId
draggedLayer.parentId = this.toParentId;
console.log(
`🔗 更新图层 ${draggedLayer.id} 的parentId为 ${this.toParentId}`
);
// 确保目标父图层有children数组
if (!targetParent.children) {
targetParent.children = [];
}
// 将图层添加到目标组
targetParent.children.splice(this.newIndex, 0, draggedLayer);
console.log(
`📂 将图层 ${draggedLayer.id} 添加到目标父图层 ${this.toParentId} 的位置 ${this.newIndex}`
);
// 将图层的fabricObject添加到目标父组中
if (draggedLayer.fabricObject && targetParent.fabricObject) {
this.safeAddToContainer(
draggedLayer.fabricObject,
targetParent.fabricObject,
`目标父组${this.toParentId}`
);
}
console.log("✅ 不同组间移动完成");
}
}
/**
* 创建跨层级移动命令的工厂函数
*/
export function createCrossLevelMoveCommand(options) {
return new CrossLevelMoveCommand(options);
}

View File

@@ -46,35 +46,6 @@ export class RasterizeLayerCommand extends Command {
this.parentLayer = parent;
this.isGroupLayer = this.layer?.children && this.layer.children.length > 0;
// 保存原始状态用于撤销
this.originalLayers = [...this.layers.value];
this.originalCanvasObjects = [...this.canvas.getObjects()];
this.originalObjectStates = new Map();
// 栅格化结果
this.rasterizedImage = null;
this.rasterizedImageId = null;
// 生成新图层ID
this.rasterizedLayerId = generateId("rasterized_layer_");
this.resterizedId = generateId("rasterized_");
this.rasterizedLayer = null;
// 要栅格化的图层和对象
this.layersToRasterize = [];
this.objectsToRasterize = [];
}
async execute() {
// 查找目标图层
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;
if (!this.layer) {
throw new Error(`图层 ${this.layerId} 不存在`);
}
@@ -84,24 +55,42 @@ export class RasterizeLayerCommand extends Command {
throw new Error("背景图层和固定图层不能栅格化");
}
// 生成新图层ID
this.rasterizedLayerId = generateId("rasterized_layer_");
this.resterizedId = generateId("rasterized_");
this.rasterizedLayer = null;
// 要栅格化的图层和对象
this.layersToRasterize = [];
this.objectsToRasterize = [];
// 在构造函数中收集相关对象和保存状态
this._initializeCommand();
}
async execute() {
if (!this.layer) {
throw new Error(`图层 ${this.layerId} 不存在`);
}
if (this.objectsToRasterize.length === 0) {
throw new Error("图层没有内容可栅格化");
}
try {
// 收集要栅格化的图层和对象
this._collectLayersAndObjects();
if (this.objectsToRasterize.length === 0) {
throw new Error("图层没有内容可栅格化");
}
// 保存原始对象状态
this._saveOriginalObjectStates();
this.canvas.discardActiveObject();
this.canvas.renderAll();
// 检查是否有遮罩对象
const maskObject = this._getMaskObject();
// 创建栅格化图像
const rasterizedImage = await createRasterizedImage({
canvas: this.canvas,
fabricObjects: this.objectsToRasterize,
maskObject: maskObject,
preserveOriginalQuality: true, // 保持原始质量
isGroupWithMask: this.isGroupLayer && !!maskObject, // 标记是否为带遮罩的组
});
// 创建新的栅格化图层并替换原图层
@@ -123,30 +112,36 @@ export class RasterizeLayerCommand extends Command {
}
async undo() {
if (!this.originalLayers || !this.originalCanvasObjects) {
if (!this.originalObjectStates || this.originalObjectStates.size === 0) {
throw new Error("没有可恢复的原始数据");
}
try {
await optimizeCanvasRendering(this.canvas, async () => {
// 清空画布
this.canvas.discardActiveObject();
this.canvas.clear();
// 移除栅格化后的图像对象
if (this.rasterizedImage) {
removeCanvasObjectByObject(this.canvas, this.rasterizedImage);
}
// 恢复原始对象及其状态
this.originalCanvasObjects.forEach((obj) => {
// 如果保存了该对象的原始状态,则恢复状态
if (this.originalObjectStates.has(obj.id)) {
const originalState = this.originalObjectStates.get(obj.id);
obj.set(originalState);
// 恢复原始对象
this.originalObjectStates.forEach((originalState, objectId) => {
const { object } = findObjectById(this.canvas, objectId);
if (object) {
// 恢复对象状态
object.set(originalState);
object.setCoords();
} else {
// 如果对象不在画布上,重新添加
const originalObject = originalState._fabricObject;
if (originalObject) {
this.canvas.add(originalObject);
originalObject.setCoords();
}
}
this.canvas.add(obj);
obj.setCoords();
});
// 恢复原始图层结构
this.layers.value = [...this.originalLayers];
this.layers.value = [...this.originalLayerStructure];
// 恢复原活动图层
this.activeLayerId.value = this.layerId;
@@ -163,6 +158,67 @@ export class RasterizeLayerCommand extends Command {
}
}
/**
* 初始化命令,收集相关图层和对象,保存原始状态
* @private
*/
_initializeCommand() {
// 收集要栅格化的图层和对象
this._collectLayersAndObjects();
// 保存原始图层结构(深拷贝相关部分)
this._saveOriginalLayerStructure();
// 保存原始对象状态
this._saveOriginalObjectStates();
}
/**
* 保存原始图层结构
* @private
*/
_saveOriginalLayerStructure() {
// 只保存相关的图层结构,而不是整个图层数组
this.originalLayerStructure = JSON.parse(JSON.stringify(this.layers.value));
}
/**
* 保存原始对象状态
* @private
*/
_saveOriginalObjectStates() {
this.originalObjectStates = new Map();
this.objectsToRasterize.forEach((object) => {
if (object && object.id) {
// 深拷贝对象的重要属性
const originalState = {
left: object.left,
top: object.top,
scaleX: object.scaleX,
scaleY: object.scaleY,
angle: object.angle,
flipX: object.flipX,
flipY: object.flipY,
opacity: object.opacity,
originX: object.originX,
originY: object.originY,
layerId: object.layerId,
layerName: object.layerName,
width: object.width,
height: object.height,
strokeWidth: object.strokeWidth,
visible: object.visible,
// 保存对象引用以便撤销时重新添加
_fabricObject: object,
};
this.originalObjectStates.set(object.id, originalState);
}
});
console.log(`💾 保存了 ${this.originalObjectStates.size} 个对象的原始状态`);
}
/**
* 收集要栅格化的图层和对象
* @private
@@ -239,42 +295,15 @@ export class RasterizeLayerCommand extends Command {
return result;
}
/**
* 保存原始对象状态
* @private
*/
_saveOriginalObjectStates() {
this.objectsToRasterize.forEach((object) => {
if (object && object.id) {
const originalState = {
left: object.left,
top: object.top,
scaleX: object.scaleX,
scaleY: object.scaleY,
angle: object.angle,
flipX: object.flipX,
flipY: object.flipY,
opacity: object.opacity,
originX: object.originX,
originY: object.originY,
layerId: object.layerId,
layerName: object.layerName,
width: object.width,
height: object.height,
strokeWidth: object.strokeWidth,
visible: object.visible,
};
this.originalObjectStates.set(object.id, originalState);
}
});
}
/**
* 创建栅格化图层并替换原图层
* @param {fabric.Image} rasterizedImage 栅格化后的图像
* @private
*/
async _createRasterizedLayer(rasterizedImage) {
// 保存栅格化图像的引用用于撤销
this.rasterizedImage = rasterizedImage;
// 从画布中移除原有对象
this.objectsToRasterize.forEach((obj) => {
removeCanvasObjectByObject(this.canvas, obj);
@@ -304,6 +333,21 @@ export class RasterizeLayerCommand extends Command {
});
// 在适当位置添加新的栅格化图层
this._replaceLayerInStructure();
// 设置为活动图层
this.activeLayerId.value = this.rasterizedLayerId;
await this.layerManager?.updateLayersObjectsInteractivity(false);
console.log(`🎨 栅格化图层 ${this.rasterizedLayer.name} 创建完成`);
}
/**
* 在图层结构中替换原图层
* @private
*/
_replaceLayerInStructure() {
// 1.当前如果是子图层,则插入到子图层的位置
const { layer, parent } = findLayerRecursively(
this.layers.value,
@@ -334,35 +378,37 @@ export class RasterizeLayerCommand extends Command {
1,
this.rasterizedLayer
);
} else this.layers.value.splice(insertIndex, 1, this.rasterizedLayer);
} else {
this.layers.value.splice(insertIndex, 1, this.rasterizedLayer);
}
} else {
// 2.如果没有找到父图层,则添加到顶层
this.layers.value.unshift(this.rasterizedLayer);
}
}
// // 替换图层结构
// if (this.isGroupLayer) {
// // 组图层:移除所有相关图层
// const layerIdsToRemove = this.layersToRasterize.map((layer) => layer.id);
// this.layers.value = this.layers.value.filter(
// (layer) => !layerIdsToRemove.includes(layer.id)
// );
// } else {
// // 普通图层:移除原图层
// const layerIndex = this.layers.value.findIndex(
// (l) => l.id === this.layerId
// );
// if (layerIndex !== -1) {
// this.layers.value.splice(layerIndex, 1);
// }
// }
/**
* 获取遮罩对象
* @returns {Object|null} 遮罩对象或null
* @private
*/
_getMaskObject() {
// 如果图层有clippingMask获取对应的fabric对象
if (this.layer?.clippingMask?.id) {
const { object: maskObject } = findObjectById(
this.canvas,
this.layer.clippingMask.id
);
if (maskObject) {
console.log(
`📎 找到遮罩对象: ${maskObject.id}, 类型: ${maskObject.type}`
);
return maskObject;
}
}
// 设置为活动图层
this.activeLayerId.value = this.rasterizedLayerId;
await this.layerManager?.updateLayersObjectsInteractivity(false);
console.log(`🎨 栅格化图层 ${this.rasterizedLayer.name} 创建完成`);
console.log("📎 未找到遮罩对象");
return null;
}
getInfo() {
@@ -387,11 +433,11 @@ export class ExportLayerToImageCommand extends Command {
constructor(options) {
super({
name: "导出图层",
saveState: true,
saveState: false, // 导出不需要保存状态
});
this.canvas = options.canvas;
this.layers = options.layers;
this.layerId = options.layerId; // 指定要栅格化的图层ID
this.layerId = options.layerId; // 指定要导出的图层ID
// 是否包含锁定对象
this.hasLocked = options.hasLocked || true;
// 是否包含隐藏对象
@@ -409,48 +455,29 @@ export class ExportLayerToImageCommand extends Command {
this.parentLayer = parent;
this.isGroupLayer = this.layer?.children && this.layer.children.length > 0;
// 保存原始状态用于撤销
this.originalLayers = [...this.layers.value];
this.originalCanvasObjects = [...this.canvas.getObjects()];
this.originalObjectStates = new Map();
// 栅格化结果
this.rasterizedImage = null;
this.rasterizedImageId = null;
// 生成新图层ID
this.rasterizedLayerId = generateId("rasterized_layer_");
this.resterizedId = generateId("rasterized_");
this.rasterizedLayer = null;
// 要栅格化的图层和对象
this.layersToRasterize = [];
this.objectsToRasterize = [];
}
async execute() {
// 查找目标图层
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;
if (!this.layer) {
throw new Error(`图层 ${this.layerId} 不存在`);
}
// 要导出的图层和对象
this.layersToRasterize = [];
this.objectsToRasterize = [];
// 收集相关对象
this._collectLayersAndObjects();
}
async execute() {
if (!this.layer) {
throw new Error(`图层 ${this.layerId} 不存在`);
}
if (this.objectsToRasterize.length === 0) {
message.error("图层没有内容可导出");
throw new Error("图层没有内容可导出");
}
try {
// 收集要栅格化的图层和对象
this._collectLayersAndObjects();
if (this.objectsToRasterize.length === 0) {
message.error("图层没有内容可导出");
throw new Error("图层没有内容可导出");
}
// 保存原始对象状态
this.canvas.discardActiveObject();
this.canvas.renderAll();
@@ -563,8 +590,6 @@ export class ExportLayerToImageCommand extends Command {
name: this.name,
originalLayerId: this.layerId,
originalLayerName: this.layer?.name,
rasterizedLayerId: this.rasterizedLayerId,
rasterizedLayerName: this.rasterizedLayer?.name,
isGroupLayer: this.isGroupLayer,
objectCount: this.objectsToRasterize?.length || 0,
};