feat: 完善选区功能,新增组图层自由编辑
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user