import { Command } from "./Command"; import { findLayerRecursively } from "../utils/layerHelper"; import { fabric } from "fabric-with-all"; import { findObjectById, generateId, insertObjectAtZIndex, removeCanvasObjectByObject, } from "../utils/helper"; import { restoreFabricObject } from "../utils/objectHelper"; /** * 填充组图层背景命令 */ export class FillGroupLayerBackgroundCommand extends Command { constructor(options) { super({ name: "填充组图层背景", saveState: true }); this.canvas = options.canvas; this.layers = options.layers; this.canvasManager = options.canvasManager; this.layerId = options.layerId; this.fillColor = options.fillColor; this.oldFill = null; this.oldFillColor = null; this.newFill = null; const { layer, parent } = findLayerRecursively( this.layers.value, this.layerId ); this.layer = layer; this.parent = parent; this.group = null; this.originalfabricObjects = this._collectOriginalObjects(); // 记录所有的原始对象 // 计算所有对象的边界 this.originalInfo = this._getCurrentObjectsBoundingRect(); this.firstObj = null; // 用于存储组图层的原始对象 } async execute(isUndo = false) { const { layer, parent } = findLayerRecursively( this.layers.value, this.layerId ); this.layer = layer; this.parent = parent; console.log("==========",layer); if (!layer) return false; if(!isUndo){ this.oldFill = layer.fill ?? null; this.oldFillColor = layer.fillColor ?? null; if(this.oldFill){ // 移除旧的填充对象 removeCanvasObjectByObject(this.canvas, this.oldFill); } } const fillColor = isUndo ? this.oldFillColor : this.fillColor; // 构建填充对象 let clippingMaskFabricObject = null; if (layer.clippingMask) { clippingMaskFabricObject = await restoreFabricObject( layer.clippingMask, this.canvas ); clippingMaskFabricObject.clipPath = null; clippingMaskFabricObject.set({ absolutePositioned: true }); this.newFill = new fabric.Rect({ width: clippingMaskFabricObject.width, height: clippingMaskFabricObject.height, left: clippingMaskFabricObject.left || 0, top: clippingMaskFabricObject.top || 0, fill: fillColor, layerId: this.layerId, id: this.oldFill?.id || generateId("fill-"), selectable: false, evented: false, originX: clippingMaskFabricObject.originX || "center", originY: clippingMaskFabricObject.originY || "center", scaleX: clippingMaskFabricObject.scaleX || 1, scaleY: clippingMaskFabricObject.scaleY || 1, }); // this.newFill.clipPath = clippingMaskFabricObject; // this.newFill.dirty = true; // this.newFill.setCoords(); } else { const originalInfo = this.originalInfo; if (originalInfo) { this.newFill = new fabric.Rect({ width: originalInfo.width, height: originalInfo.height, left: originalInfo.left + originalInfo.width / 2 || 0, top: originalInfo.top + originalInfo.height / 2 || 0, fill: fillColor, layerId: this.layerId, id: this.oldFill?.id || generateId("fill-"), selectable: false, evented: false, originX: "center", originY: "center", }); } } // 判断fabricObjects是否是组对象 const firstObj = layer.fabricObjects?.[0] || null; // 如果没有找到第一个对象,则直接添加到当前画布 if (!firstObj) { if (this?.parent?.clippingMask) { clippingMaskFabricObject = await restoreFabricObject( this.parent.clippingMask, this.canvas ); clippingMaskFabricObject.clipPath = null; clippingMaskFabricObject.set({ absolutePositioned: true }); this.newFill = new fabric.Rect({ width: clippingMaskFabricObject.width, height: clippingMaskFabricObject.height, left: clippingMaskFabricObject.left || 0, top: clippingMaskFabricObject.top || 0, fill: fillColor, layerId: this.layerId, id: this.oldFill?.id || generateId("fill-"), selectable: false, evented: false, originX: clippingMaskFabricObject.originX || "center", originY: clippingMaskFabricObject.originY || "center", scaleX: clippingMaskFabricObject.scaleX || 1, scaleY: clippingMaskFabricObject.scaleY || 1, }); } else { this.newFill = new fabric.Rect({ width: this.canvasManager?.canvasWidth?.value || this.canvas.width, height: this.canvasManager?.canvasHeight?.value || this.canvas.height, left: this.canvas.width / 2 || 0, top: this.canvas.height / 2 || 0, fill: fillColor, layerId: this.layerId, id: this.oldFill?.id || generateId("fill-"), selectable: false, evented: false, originX: "center", originY: "center", }); } this.newFill.clipPath = clippingMaskFabricObject; // 设置填充的遮罩 this.newFill.dirty = true; // 标记为脏,以便重新 this.canvas.add(this.newFill); this.firstObj = this.newFill; layer.fabricObjects = [ this.newFill.toObject(["id", "layerId"]) || this.newFill, ]; layer.fill = this.newFill; // this.newFill.toObject(["id", "layerId"]); layer.fillColor = fillColor; // 取消激活对象 this.canvas.discardActiveObject(); // 取消当前活动对象 // 重新排序 await this.layerManager?.sortLayersWithTool?.(); // 更新画布上对象的可选择状态 await this.layerManager?.updateLayersObjectsInteractivity?.(); this.canvas.renderAll(); this.canvasManager.thumbnailManager?.generateLayerThumbnail( this.layer.id ); return false; } const canvasObj = findObjectById(this.canvas, firstObj?.id)?.object; if ( (canvasObj && canvasObj.type === "group") || canvasObj._objects?.length > 0 ) { this.newFill.set({ left: 0, top: 0, }); // 将新填充对象添加到组的最前面 // canvasObj._objects.unshift(this.newFill); canvasObj.insertAt(this.newFill, 0, false); // canvasObj.addWithUpdate(); canvasObj.setCoords(); canvasObj.setObjectsCoords(); canvasObj.dirty = true; // 标记为脏对象 // this.canvas.renderAll(); // this.group = canvasObj; } else if (layer.fabricObjects && layer.fabricObjects.length > 0) { // 普通对象,组成新组 const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId) || []; // layerObjects?.forEach((obj) => { // obj.clipPath = null; // obj.dirty = true; // obj.setCoords(); // }); let insertIndex = this.canvas.getObjects()?.findIndex((obj) => obj.id === firstObj?.id) ?? 0; insertIndex = insertIndex === -1 ? 0 : insertIndex; layerObjects.forEach((obj) => { obj.clipPath = null; }); this.group = new fabric.Group([this.newFill, ...layerObjects]); this.group.set({ id: layerObjects[0]?.id || generateId("group-"), layerId: this.layer?.id, }); // this.group.setCoords(); // this.group.setObjectsCoords(); // this.group.dirty = true; // 标记为脏对象 if (this.parent?.clippingMask) { const clipPath = await restoreFabricObject( this.parent?.clippingMask, this.canvas ); clipPath.clipPath = null; clipPath.set({ absolutePositioned: true }); this.group.clipPath = clipPath; } layer.fabricObjects = [ this.group.toObject(["id", "layerId"]) || this.group, ]; // removeCanvasObjectByObject(this.canvas, layerObjects?.[0]); insertObjectAtZIndex(this.canvas, this.group, insertIndex, false, true); } // this.group?.addWithUpdate?.(); // layer.fabricObjects = [this.group?.toObject?.(["id", "layerId"]) || this.group]; // this.canvas.renderAll(); layer.fill = this.newFill; // this.newFill.toObject(["id", "layerId"]); layer.fillColor = fillColor; // 取消激活对象 this.canvas.discardActiveObject(); // 取消当前活动对象 // 重新排序 await this.layerManager?.sortLayersWithTool?.(); // 更新画布上对象的可选择状态 await this.layerManager?.updateLayersObjectsInteractivity?.(); this.canvas.renderAll(); this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layer.id); return true; } async undo() { if (!this.originalInfo && this.layer.fill) { this.canvas.discardActiveObject(); this.canvas.remove(this.layer.fill); this.canvas.renderAll(); this.parent && this.canvasManager.thumbnailManager?.generateLayerThumbnail( this.parent.id ); this.canvasManager.thumbnailManager?.generateLayerThumbnail( this.layer.id ); this.layer.fabricObjects = []; return false; } // 判断fabricObjects是否是组对象 const firstObj = this.layer.fabricObjects?.[0]; const canvasObj = this.group || findObjectById(this.canvas, firstObj?.id)?.object; if ( (canvasObj && canvasObj.type === "group") || canvasObj?._objects?.length > 0 ) { // 移除新添加的填充对象 // if (canvasObj._objects?.[0] === this.newFill) { if (/^fill-/.test(canvasObj._objects?.[0]?.id)) { canvasObj._objects.shift(); canvasObj.addWithUpdate(); canvasObj.setCoords(); canvasObj.dirty = true; } this.canvas.renderAll(); } else if (this.group) { // 如果是新建的group,需要拆分还原 // 先移除新建的group this.canvas.remove(this.group); // 重新添加原始对象 this.originalfabricObjects.forEach((obj) => { if (!this.canvas.getObjects().includes(obj)) { this.canvas.add(obj); } }); this.canvas.renderAll(); this.group = null; } if(this.oldFill){ this.layer.fill = this.oldFill; this.layer.fillColor = this.oldFillColor; return this.execute(true); }else{ this.layer.fill = null; this.layer.fillColor = null; } this.canvas.discardActiveObject(); // 取消当前活动对象 // 重新排序 await this.layerManager?.sortLayersWithTool?.(); // 更新画布上对象的可选择状态 await this.layerManager?.updateLayersObjectsInteractivity?.(); this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layer.id); return true; } _collectOriginalObjects() { if (this.layer?.children && this.layer?.children.length > 0) { // 如果是组图层,收集所有子图层的fabric对象 return this.layer.children .flatMap((child) => child.fabricObjects || []) .map((obj) => { return findObjectById(this.canvas.value, obj.id)?.object || obj; }); } else if ( this.layer?.fabricObjects && this.layer?.fabricObjects?.length > 0 ) { // 如果是普通图层,直接返回其fabric对象 return this.layer.fabricObjects.map((obj) => { return findObjectById(this.canvas.value, obj.id)?.object || obj; }); } else { // 如果没有fabric对象,返回空数组 return []; } } // 获取当前所有对象的边界信息 _getCurrentObjectsBoundingRect() { // this.originalfabricObjects = this._collectOriginalObjects(); let minLeft = Infinity, minTop = Infinity, maxRight = -Infinity, maxBottom = -Infinity; console.log( "计算当前所有对象的边界信息:===>", this.originalfabricObjects.length ); this.originalfabricObjects?.forEach((obj) => { const { object } = findObjectById(this.canvas, obj.id) || {}; if (object) { const rect = object.getBoundingRect({ absolute: true, includeStroke: false, }); minLeft = Math.min(minLeft, rect.left); minTop = Math.min(minTop, rect.top); maxRight = Math.max(maxRight, rect.left + rect.width); maxBottom = Math.max(maxBottom, rect.top + rect.height); } }); if (minLeft === Infinity || minTop === Infinity) return null; return { left: minLeft, top: minTop, width: maxRight - minLeft, height: maxBottom - minTop, }; } }