import { fabric } from "fabric-with-all"; import initAligningGuidelines, { initCenteringGuidelines, } from "../utils/helperLine"; import { ThumbnailManager } from "./ThumbnailManager"; import { ExportManager } from "./ExportManager"; import { isGroupLayer, OperationType, OperationTypes, } from "../utils/layerHelper"; import { AnimationManager } from "./animation/AnimationManager"; import { createCanvas } from "../utils/canvasFactory"; import { CanvasEventManager } from "./events/CanvasEventManager"; import CanvasConfig from "../config/canvasConfig"; import { RedGreenModeManager } from "./RedGreenModeManager"; import { EraserStateManager } from "./EraserStateManager"; import { deepClone, optimizeCanvasRendering } from "../utils/helper"; import { ChangeFixedImageCommand } from "../commands/ObjectLayerCommands"; import { isFunction } from "lodash-es"; import { restoreObjectLayerAssociations, simplifyLayers, validateLayerAssociations, } from "../utils/layerUtils"; export class CanvasManager { constructor(canvasElement, options) { this.canvasElement = canvasElement; this.width = options.width || 1024; this.height = options.height || 768; this.backgroundColor = options.backgroundColor || "#ffffff"; this.toolManager = options.toolManager || null; // 工具管理器引用 this.currentZoom = options.currentZoom || { value: 100 }; this.maskLayer = null; // 添加蒙层引用 this.editorMode = CanvasConfig.defaultTool; // 默认编辑器模式 this.layers = options.layers || null; // 图层引用 this.canvasWidth = options.canvasWidth || this.width; // 画布宽度 this.canvasHeight = options.canvasHeight || this.height; // 画布高度 this.canvasColor = options.canvasColor || "#ffffff"; // 画布背景颜色 this.enabledRedGreenMode = options.enabledRedGreenMode || false; // 是否启用红绿图模式 this.eraserStateManager = null; // 橡皮擦状态管理器引用 // 初始化画布 this.initializeCanvas(); } initializeCanvas() { console.log("fabric.version:", fabric.version); this.canvas = createCanvas(this.canvasElement, { width: this.width, height: this.height, preserveObjectStacking: true, enableRetinaScaling: true, stopContextMenu: true, fireRightClick: true, }); // 初始化动画管理器 this.animationManager = new AnimationManager(this.canvas, { currentZoom: this.currentZoom, wheelThrottleTime: 15, // 降低滚轮事件节流时间,提高响应性 defaultEase: "power2.lin", defaultDuration: 0.3, // 缩短默认动画时间 }); // 初始化缩略图管理器 this.thumbnailManager = new ThumbnailManager(this.canvas, { // 可以根据需求自定义选项 // layerThumbSize: { width: 32, height: 32 }, // elementThumbSize: { width: 32, height: 24 }, layers: this.layers, }); this.canvas.thumbnailManager = this.thumbnailManager; // 将缩略图管理器绑定到画布 // 设置画布辅助线 initAligningGuidelines(this.canvas); // 设置画布中心线 initCenteringGuidelines(this.canvas); // 初始化画布事件监听器 this._initCanvasEvents(); } /** * 初始化画布事件监听器 * 设置鼠标事件、键盘事件等 * @private */ _initCanvasEvents() { // 添加笔刷图像转换处理回调 this.canvas.onBrushImageConverted = async (fabricImage) => { // 如果图层管理器存在,将图像合并到当前活动图层 if (this.layerManager) { // 获取当前活动图层 const activeLayer = this.layerManager.getActiveLayer(); if (activeLayer) { // 确保新图像具有正确的图层信息 fabricImage.set({ layerId: activeLayer.id, layerName: activeLayer.name, id: fabricImage.id || `brush_img_${Date.now()}_${Math.floor(Math.random() * 1000)}`, }); // 执行高保真合并操作 await this.eventManager?.mergeLayerObjectsForPerformance?.({ fabricImage, activeLayer, }); this.thumbnailManager?.generateLayerThumbnail(activeLayer.id); // 返回true表示不要自动添加到画布,因为我们已经通过图层管理器处理了 return true; } else { console.warn("没有活动图层,使用默认行为添加图像"); } } // 返回false表示使用默认行为(直接添加到画布) return false; }; this.eraserStateManager = new EraserStateManager( this.canvas, this.layerManager ); // 监听擦除开始事件 this.canvas.on("erasing:start", () => { console.log("开始擦除"); this.eraserStateManager.startErasing(); }); // 监听擦除结束事件 this.canvas.on("erasing:end", async (e) => { console.log("擦除完成", e.targets); // 可以在这里保存状态到命令管理器 const affectedObjects = e.targets || []; const command = this.eraserStateManager.endErasing(affectedObjects); if (command && this.commandManager) { await this.commandManager?.executeCommand?.(command); } else { await command?.execute?.(); // 如果没有命令管理器,直接执行命令 } // 更新交互性 command && (await this.layerManager?.updateLayersObjectsInteractivity?.()); this.thumbnailManager?.generateLayerThumbnail( this.layerManager?.activeLayerId?.value ); }); } /** * 设置编辑器模式 * @param {string} mode 'draw'、'select'或'pan' */ toolChanged(mode) { if (!OperationTypes.includes(mode)) { console.warn(`不支持的编辑器模式: ${mode}`); return; } this.editorMode = mode; // 如果已创建事件管理器,更新它的编辑器模式 if (this.eventManager) { this.eventManager.setEditorMode(mode); } } setToolManager(toolManager) { this.toolManager = toolManager || null; // 工具管理器引用 // 更新红绿图模式管理器的工具管理器引用 if (this.redGreenModeManager) { this.redGreenModeManager.toolManager = this.toolManager; } // 如果已创建事件管理器,更新它的工具管理器引用 if (this.eventManager) { this.eventManager.toolManager = this.toolManager; } } setLayerManager(layerManager) { this.layerManager = layerManager || null; // 图层管理器引用 // 初始化导出管理器(需要在图层管理器设置后初始化) if (this.layerManager) { this.exportManager = new ExportManager(this, this.layerManager); } // 更新红绿图模式管理器的图层管理器引用 if (this.redGreenModeManager) { this.redGreenModeManager.layerManager = this.layerManager; } if (this.eraserStateManager) { this.eraserStateManager.setLayerManager(this.layerManager); } } /** * 设置命令管理器 * @param {Object} commandManager 命令管理器实例 */ setCommandManager(commandManager) { this.commandManager = commandManager; // 更新红绿图模式管理器的命令管理器引用 if (this.redGreenModeManager) { this.redGreenModeManager.commandManager = this.commandManager; } } /** * 设置液化管理器 * @param {Object} liquifyManager 液化管理器实例 */ setLiquifyManager(liquifyManager) { this.liquifyManager = liquifyManager; } /** * 设置选区管理器 * @param {Object} selectionManager 选区管理器实例 */ setSelectionManager(selectionManager) { this.selectionManager = selectionManager; // 如果已创建事件管理器,更新它的选区管理器引用 if (this.eventManager) { this.eventManager.selectionManager = this.selectionManager; } } // 设置红绿图模式管理器 setRedGreenModeManager(redGreenModeManager) { this.redGreenModeManager = redGreenModeManager; } setupCanvasEvents(activeElementId, layerManager) { // 创建画布事件管理器 this.eventManager = new CanvasEventManager(this.canvas, { toolManager: this.toolManager, animationManager: this.animationManager, thumbnailManager: this.thumbnailManager, editorMode: this.editorMode, activeElementId: activeElementId, layerManager: layerManager, layers: this.layers, }); // 设置动画交互效果 this.animationManager.setupInteractionAnimations(); } setupLongPress(callback) { if (this.eventManager) { this.eventManager.setupLongPress(callback); } } updateSelectedElements(opt, activeElementId) { if (this.eventManager) { this.eventManager.updateSelectedElements(opt); } else { const selected = opt.selected[0]; if (selected) { activeElementId.value = selected.id; } } } clearSelectedElements(activeElementId) { if (this.eventManager) { this.eventManager.clearSelectedElements(); } else if (activeElementId) { activeElementId.value = null; } } // 使用动画管理器的缩放方法 animateZoom(point, targetZoom, options = {}) { this.animationManager.animateZoom(point, targetZoom, options); } // 应用缩放(为兼容性保留) _applyZoom(point, zoom, skipUpdate = false) { this.animationManager._applyZoom(point, zoom, skipUpdate); } // 使用动画管理器的平移方法 animatePan(targetPosition, options = {}) { this.animationManager.animatePan(targetPosition, options); } // 应用平移(为兼容性保留) _applyPan(x, y) { this.animationManager._applyPan(x, y); } // 平移到指定元素 panToElement(elementId) { this.animationManager.panToElement(elementId); } // 重置缩放并居中内容 async resetZoom(animated = true) { // 先重置缩放 await this.animationManager.resetZoom(animated); // // 重置视图变换以确保元素位置正确 // this._resetViewportTransform(); // // 居中所有画布元素,包括背景层和其他元素 // this.centerAllObjects(); // 重新渲染画布使变更生效 this.canvas.renderAll(); } // 设置固定图层可擦除状态 setFixedLayerErasable({ type = "isFixed", flag = false }) { const layer = this.layers.value.find((layer) => layer[type]); if (layer) { // 设置固定图层的可擦除状态 layer.locked = flag; // 更新画布对象的erasable属性 const fabricObject = this.canvas .getObjects() .find((obj) => obj.id === layer.id); if (fabricObject) { fabricObject.erasable = flag; fabricObject.set("erasable", flag); fabricObject.setCoords(); // 更新控制点坐标 this.canvas.renderAll(); // 重新渲染画布 } return; } } setCanvasSize(width, height) { this.width = width; this.height = height; this.canvas.setWidth(width); this.canvas.setHeight(height); // 重置视图变换以确保元素位置正确 this._resetViewportTransform(); // 居中所有画布元素,包括背景层和其他元素 this.centerAllObjects(); // 重新渲染画布使变更生效 this.canvas.renderAll(); } /** * 重置视图变换,使元素回到原始位置 * @private */ _resetViewportTransform(zoom) { // 保存当前缩放值 const currentZoom = zoom ?? this.canvas.getZoom(); // 重置视图变换,但保留缩放级别 this.canvas.setViewportTransform([currentZoom, 0, 0, currentZoom, 0, 0]); } /** * 居中所有画布元素 * 以背景层为参照,计算背景层的偏移量并应用到所有对象上 * 这样可以保持对象间的相对位置关系不变 */ centerAllObjects() { if (!this.canvas) return; // 获取所有可见对象(不是背景元素的对象) const allObjects = this.canvas.getObjects(); if (allObjects.length === 0) return; const visibleObjects = allObjects.filter( (obj) => obj.visible !== false && !obj.excludeFromExport ); // 如果没有可见对象,直接返回 if (visibleObjects.length === 0) return; // 获取背景对象 const backgroundObject = visibleObjects.find((obj) => obj.isBackground); this.canvas?.clipPath?.set?.({ left: this.width / 2, top: this.height / 2, originX: "center", originY: "center", }); this.canvas?.clipPath?.setCoords?.(); // 如果只有背景层或没有背景层,使用原有逻辑 if (!backgroundObject) { console.warn("未找到背景层,使用默认居中逻辑"); // 如果只有一个对象且可能是背景,直接居中 if (visibleObjects.length === 1) { const obj = visibleObjects[0]; obj.set({ left: this.width / 2, top: this.height / 2, originX: "center", originY: "center", }); obj.setCoords(); this.canvas.renderAll(); } return; } // 记录背景层居中前的位置 const backgroundOldLeft = backgroundObject.left; const backgroundOldTop = backgroundObject.top; // 计算画布中心点 const canvasCenterX = this.width / 2; const canvasCenterY = this.height / 2; // 设置背景层居中 backgroundObject.set({ left: canvasCenterX, top: canvasCenterY, originX: "center", originY: "center", }); // 计算背景层的偏移量 const deltaX = backgroundObject.left - backgroundOldLeft; const deltaY = backgroundObject.top - backgroundOldTop; // 将相同的偏移量应用到所有其他对象上 const otherObjects = visibleObjects.filter( (obj) => obj !== backgroundObject ); otherObjects.forEach((obj) => { obj.set({ left: obj.left + deltaX, top: obj.top + deltaY, }); obj.setCoords(); // 更新对象的控制点坐标 }); // 如果有背景层,更新蒙层位置 if (backgroundObject && CanvasConfig.isCropBackground) { this.updateMaskPosition(backgroundObject); } // 重新渲染画布 this.canvas.renderAll(); } /** * 计算多个对象的总边界框 * @private * @param {Array} objects 要计算边界的对象数组 * @return {Object} 边界信息,包含left、top、width、height */ _calculateObjectsBounds(objects) { if (!objects || objects.length === 0) return null; let minX = Infinity; let minY = Infinity; let maxX = -Infinity; let maxY = -Infinity; objects.forEach((obj) => { const bound = obj.getBoundingRect(); minX = Math.min(minX, bound.left); minY = Math.min(minY, bound.top); maxX = Math.max(maxX, bound.left + bound.width); maxY = Math.max(maxY, bound.top + bound.height); }); return { left: minX, top: minY, width: maxX - minX, height: maxY - minY, }; } setCanvasColor(color) { this.backgroundColor = color; // this.canvas.setBackgroundColor( // color, // this.canvas.renderAll.bind(this.canvas) // ); this.thumbnailManager?.generateLayerThumbnail?.( this.layers?.value.find((layer) => layer.isBackground)?.id ); } /** * 居中背景层 * @param {Object} backgroundLayerObject 背景层对象 * @param {Number} canvasWidth 画布宽度 * @param {Number} canvasHeight 画布高度 */ centerBackgroundLayer(canvasWidth, canvasHeight) { const backgroundLayerObject = this.getBackgroundLayer(); if (!backgroundLayerObject) return false; // const bgWidth = backgroundLayerObject.width * backgroundLayerObject.scaleX; // const bgHeight = // backgroundLayerObject.height * backgroundLayerObject.scaleY; // 计算居中位置 const left = canvasWidth / 2; const top = canvasHeight / 2; backgroundLayerObject.set({ left: left, top: top, originX: "center", originY: "center", }); !CanvasConfig.isCropBackground && this.canvas.renderAll(); // 如果不需要裁剪背景层以外的内容,则渲染画布 // 如果需要裁剪背景层以外的内容,则更新蒙层位置 // 创建或更新蒙层 CanvasConfig.isCropBackground && !this.enabledRedGreenMode && this.createOrUpdateMask(backgroundLayerObject); return true; } /** * 创建或更新蒙层,用于裁剪不可见区域 * @param {Object} backgroundLayerObject 背景层对象 */ createOrUpdateMask(backgroundLayerObject) { if (!backgroundLayerObject) return; const bgWidth = backgroundLayerObject.width * backgroundLayerObject.scaleX; const bgHeight = backgroundLayerObject.height * backgroundLayerObject.scaleY; const left = backgroundLayerObject.left; const top = backgroundLayerObject.top; // 如果已经存在蒙层,则更新它 if (this.maskLayer) { this.canvas.remove(this.maskLayer); } // 创建蒙层 - 使用透明矩形作为裁剪区域 this.maskLayer = new fabric.Rect({ id: "canvasMaskLayer", width: bgWidth, height: bgHeight, left: left, top: top, fill: "transparent", stroke: "transparent", strokeWidth: 1, strokeDashArray: [5, 5], selectable: false, evented: false, hoverCursor: "default", originX: "center", originY: "center", }); // 将蒙层添加到画布 this.canvas.add(this.maskLayer); // 设置蒙层为最顶层 this.maskLayer.bringToFront(); this.canvas.clipPath = new fabric.Rect({ width: bgWidth, height: bgHeight, left: left, top: top, originX: backgroundLayerObject.originX || "left", originY: backgroundLayerObject.originY || "top", absolutePositioned: true, }); } getBackgroundLayer() { if (!this.canvas) return null; const backgroundLayer = this.canvas.getObjects().find((obj) => { return obj.isBackground; }); if (backgroundLayer) return backgroundLayer; // 如果没有找到背景层,则根据图层ID查找 const backgroundLayerId = this.layers.value.find((layer) => { return layer.isBackground; })?.id; const backgroundLayerByBgLayer = this.canvas.getObjects().find((obj) => { return obj.isBackground || obj.id === backgroundLayerId; }); if (!backgroundLayerByBgLayer) { console.warn( "CanvasManager.js = >getBackgroundLayer 方法没有找到背景层" ); } return backgroundLayerByBgLayer; } /** * 更新蒙层位置 * @param {Object} backgroundLayerObject 背景层对象 */ updateMaskPosition(backgroundLayerObject) { if (!backgroundLayerObject || !this.maskLayer || !this.canvas.clipPath) return; const left = backgroundLayerObject.left; const top = backgroundLayerObject.top; this.maskLayer.set({ left: left, top: top, width: backgroundLayerObject.width * backgroundLayerObject.scaleX, height: backgroundLayerObject.height * backgroundLayerObject.scaleY, originX: backgroundLayerObject.originX || "left", originY: backgroundLayerObject.originY || "top", }); this.canvas.clipPath.set({ left: left, top: top, width: backgroundLayerObject.width * backgroundLayerObject.scaleX, height: backgroundLayerObject.height * backgroundLayerObject.scaleY, }); this.canvas.renderAll(); } /** * 更新指定图层的缩略图 * @param {String} layerId 图层ID */ updateLayerThumbnail(layerId) { this.thumbnailManager?.generateLayerThumbnail?.(layerId); } /** * 更新所有图层和元素的缩略图 */ updateAllThumbnails() { // 为所有元素生成缩略图 this.thumbnailManager?.generateAllLayerThumbnails?.(this.layers.value); } /** * * 更改固定图层的图片 * @param {String} imageUrl 新的图片URL * @param {Object} options 选项 * @param {String} options.targetLayerType 目标图层类型(background/fixed) * @param {Boolean} options.undoable 是否可撤销,默认不可撤销 * @return {Object} 执行结果 * */ async changeFixedImage(imageUrl, options = {}) { if (!this.layerManager) { console.error("图层管理器未设置,无法更改固定图层图片"); return; } const command = new ChangeFixedImageCommand({ canvas: this.canvas, layerManager: this.layerManager, imageUrl: imageUrl, targetLayerType: options.targetLayerType || "fixed", // background/fixed canvasWidth: this.canvasWidth, canvasHeight: this.canvasHeight, ...options, }); command.undoable = options.undoable !== undefined ? options.undoable : false; // 默认不可撤销 undoable = true 为可撤销 return ( (await command?.execute?.()) || { success: false, layerId: null, imageUrl: null, } ); } /** * 导出图片 * @param {Object} options 导出选项 * @param {Boolean} options.isContainBg 是否包含背景图层 * @param {Boolean} options.isContainFixed 是否包含固定图层 * @param {String} options.layerId 导出具体图层ID * @param {Array} options.layerIdArray 导出多个图层ID数组 * @param {String} options.expPicType 导出图片类型 (png/jpg/svg) * @param {Boolean} options.restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1 * @returns {String} 导出的图片数据URL */ exportImage(options = {}) { if (!this.exportManager) { console.error("导出管理器未初始化,请确保已设置图层管理器"); throw new Error("导出管理器未初始化"); } try { // 自动设置红绿图模式相关参数 const enhancedOptions = { ...options, // 如果没有明确指定,则根据当前模式自动设置 restoreOpacityInRedGreen: options.restoreOpacityInRedGreen !== undefined ? options.restoreOpacityInRedGreen : true, // 默认在红绿图模式下恢复透明度 }; // 如果在红绿图模式下且没有指定具体的图层,自动包含所有普通图层 if ( this.enabledRedGreenMode && !options.layerId && (!options.layerIdArray || options.layerIdArray.length === 0) ) { console.log("检测到红绿图模式,自动包含所有普通图层进行导出"); // 获取所有非背景、非固定的普通图层ID const normalLayerIds = this.layers?.value ?.filter( (layer) => !layer.isBackground && !layer.isFixed && layer.visible ) ?.map((layer) => layer.id) || []; if (normalLayerIds.length > 0) { enhancedOptions.layerIdArray = normalLayerIds; console.log("红绿图模式导出图层:", normalLayerIds); } } return this.exportManager.exportImage(enhancedOptions); } catch (error) { console.error("CanvasManager导出图片失败:", error); throw error; } } dispose() { // 释放导出管理器资源 if (this.exportManager) { this.exportManager = null; } // 释放事件管理器资源 if (this.eventManager) { this.eventManager.dispose(); this.eventManager = null; } // 释放动画管理器资源 if (this.animationManager) { this.animationManager.dispose(); this.animationManager = null; } // 释放缩略图管理器资源 if (this.thumbnailManager) { this.thumbnailManager.dispose(); this.thumbnailManager = null; } if (this.canvas) { this.canvas.dispose(); } } getJSON() { // // 简化图层数据,在loadJSON时要根据id恢复引用 // const simplifyLayers = (layers) => { // return layers.map((layer) => { // if (layer?.children?.length) { // layer.children = layer.children.map((child) => { // return { // id: child.id, // type: child.type, // layerId: child.layerId, // layerName: child.layerName, // isBackground: child.isBackground, // isLocked: child.isLocked, // isVisible: child.isVisible, // isFixed: child.isFixed, // parentId: child.parentId, // fabricObject: child.fabricObject // ? { // id: child.fabricObject.id, // type: child.fabricObject.type, // layerId: child.fabricObject.layerId, // layerName: child.fabricObject.layerName, // } // : {}, // fabricObjects: // child.fabricObjects?.map((obj) => ({ // id: obj.id, // type: obj.type, // layerId: obj.layerId, // layerName: obj.layerName, // })) || [], // }; // }); // } // return { // id: layer.id, // type: layer.type, // layerId: layer.layerId, // layerName: layer.layerName, // isBackground: layer.isBackground, // isLocked: layer.isLocked, // isVisible: layer.isVisible, // isFixed: layer.isFixed, // parentId: layer.parentId, // fabricObject: child.fabricObject // ? { // id: child.fabricObject.id, // type: child.fabricObject.type, // layerId: child.fabricObject.layerId, // layerName: child.fabricObject.layerName, // } // : {}, // fabricObjects: // child.fabricObjects?.map((obj) => ({ // id: obj.id, // type: obj.type, // layerId: obj.layerId, // layerName: obj.layerName, // })) || [], // children: layer.children, // }; // }); // }; try { const simplifyLayersData = simplifyLayers( JSON.parse(JSON.stringify(this.layers.value)) ); console.log("获取画布JSON数据...", simplifyLayersData); return JSON.stringify({ canvas: this.canvas.toJSON([ "id", "type", "layerId", "layerName", "isBackground", "isLocked", "isVisible", "isFixed", "parentId", "eraser", "eraserable", "erasable", ]), layers: JSON.stringify(simplifyLayersData), // 简化图层数据 // layers: JSON.stringify(JSON.parse(JSON.stringify(this.layers.value))), // 全数据 version: "1.0", // 添加版本信息 timestamp: new Date().toISOString(), // 添加时间戳 canvasWidth: this.canvasWidth.value, canvasHeight: this.canvasHeight.value, canvasColor: this.canvasColor.value, activeLayerId: this.layerManager?.activeLayerId?.value, }); } catch (error) { console.error("获取画布JSON失败:", error); throw new Error("获取画布JSON失败"); } } loadJSON(json, calllBack) { console.log("加载画布JSON数据:", json); // 确保传入的json是字符串格式 if (typeof json === "object") { json = JSON.stringify(json); } else if (typeof json !== "string") { throw new Error("loadJSON方法需要传入字符串或对象格式的JSON数据"); } // 解析JSON字符串 try { const parsedJson = JSON.parse(json); return new Promise(async (resolve, reject) => { const tempLayers = JSON.parse(parsedJson?.layers) || []; const canvasData = parsedJson?.canvas; if (!tempLayers) { reject(new Error("JSON数据中缺少layers字段")); return; } if (!canvasData) { reject(new Error("JSON数据中缺少canvas字段")); return; } this.layers.value = tempLayers; // this.canvasWidth.value = parsedJson.canvasWidth || this.width; // this.canvasHeight.value = parsedJson.canvasHeight || this.height; // this.canvasColor.value = parsedJson.canvasColor || this.backgroundColor; console.log("是否检测到红绿图模式内容:", this.enabledRedGreenMode); // 重置视图变换以确保元素位置正确 this._resetViewportTransform(1); let canvasClipPath = null; // 克隆当前裁剪路径 if (this.canvas?.clipPath) { canvasClipPath = this.canvas?.clipPath; } // 清除当前画布内容 this.canvas.clear(); console.log("清除当前画布内容", canvasData); delete canvasData.clipPath; // 删除当前裁剪路径 // 加载画布数据 this.canvas.loadFromJSON(canvasData, async () => { await optimizeCanvasRendering(this.canvas, async () => { // 清空重做栈 this.commandManager?.clear?.(); this.backgroundColor = parsedJson.backgroundColor || "#ffffff"; if (canvasClipPath) { // canvasClipPath.set({ // absolutePositioned: true, // }); this.canvas.clipPath = canvasClipPath; // await new Promise((resolve) => { // debugger; // fabric.util.enlivenObjects([canvasClipPath], (clipPaths) => { // if (clipPaths && clipPaths.length > 0) { // resolve(clipPaths[0]); // } else { // resolve(null); // } // }); // }); // debugger; } try { // 重置画布数据 this.setCanvasSize(this.canvas.width, this.canvas.height); // 重新构建对象关系 restoreObjectLayerAssociations( this.layers.value, this.canvas.getObjects() ); // 验证图层关联关系 - 稳定后可以注释 const isValidate = validateLayerAssociations( this.layers.value, this.canvas.getObjects() ); console.log("图层关联验证结果:", isValidate); this.layerManager.activeLayerId.value = this.layers.value[0]?.id || parsedJson?.activeLayerId || null; // // 如果检测到红绿图模式内容,进行缩放调整 // if (this.enabledRedGreenMode) { // this._rescaleRedGreenModeContent(); // } // 重载代码后支持回调中操作一些内容 await calllBack?.(); // 确保所有对象的交互性正确设置 await this.layerManager?.updateLayersObjectsInteractivity?.( false ); console.log(this.layerManager.layers.value); // 更新所有缩略图 setTimeout(() => { this.updateAllThumbnails(); }, 500); console.log("画布JSON数据加载完成"); resolve(); } catch (error) { console.error("恢复图层数据失败:", error); reject(new Error("恢复图层数据失败: " + error.message)); } }); }); }); } catch (error) { console.error("解析JSON失败:", error); throw new Error("解析JSON失败,请检查输入格式: " + error.message); } } /** * 缩放红绿图模式内容以适应当前画布大小 * 确保衣服底图和红绿图永远在画布内可见 * @private */ _rescaleRedGreenModeContent() { if (!this.canvas) return; console.log("正在重新缩放红绿图内容..."); try { // 获取固定图层和普通图层 const fixedLayerObject = this._getFixedLayerObject(); const normalLayerObjects = this._getNormalLayerObjects(); if (!fixedLayerObject) { console.warn("找不到固定图层对象,无法进行红绿图内容缩放"); return; } // 计算边距(画布两侧各留出一定空间) const margin = 50; const maxWidth = this.canvas.width - margin * 2; const maxHeight = this.canvas.height - margin * 2; // 计算原始尺寸 const originalWidth = fixedLayerObject.width * fixedLayerObject.scaleX; const originalHeight = fixedLayerObject.height * fixedLayerObject.scaleY; // 计算需要的缩放比例,确保图像完全适应画布 const scaleX = maxWidth / originalWidth; const scaleY = maxHeight / originalHeight; const scale = Math.min(scaleX, scaleY); console.log( `计算的缩放比例: ${scale},原始尺寸: ${originalWidth}x${originalHeight},目标尺寸: ${maxWidth}x${maxHeight}` ); // 如果缩放比例接近1,不进行缩放 if (Math.abs(scale - 1) < 0.05) { console.log("缩放比例接近1,不进行缩放,仅居中内容"); this.centerAllObjects(); return; } // 缩放固定图层(衣服底图) this._rescaleObject(fixedLayerObject, scale); // 缩放所有普通图层对象(红绿图和其他内容) normalLayerObjects.forEach((obj) => { // 红绿图对象应与底图保持完全一致的位置和大小 if (this._isLikelyRedGreenImage(obj, fixedLayerObject)) { // 完全匹配底图的位置和大小 obj.set({ scaleX: fixedLayerObject.scaleX, scaleY: fixedLayerObject.scaleY, left: fixedLayerObject.left, top: fixedLayerObject.top, originX: fixedLayerObject.originX || "center", originY: fixedLayerObject.originY || "center", }); } else { // 其他普通对象进行等比例缩放 this._rescaleObject(obj, scale); } }); // 重新居中所有内容 this.centerAllObjects(); // 更新所有对象的坐标系统 this.canvas.getObjects().forEach((obj) => { obj.setCoords(); }); // 渲染画布 this.canvas.renderAll(); console.log("红绿图内容缩放完成"); } catch (error) { console.error("缩放红绿图内容时出错:", error); } } /** * 缩放单个对象 * @param {Object} obj fabric对象 * @param {Number} scale 缩放比例 * @private */ _rescaleObject(obj, scale) { if (!obj) return; // 保存原始中心点 const center = obj.getCenterPoint(); // 应用新的缩放 obj.set({ scaleX: obj.scaleX * scale, scaleY: obj.scaleY * scale, }); // 重新定位到原中心点 obj.setPositionByOrigin(center, "center", "center"); obj.setCoords(); } /** * 获取固定图层对象(衣服底图) * @returns {Object|null} 固定图层对象或null * @private */ _getFixedLayerObject() { if (!this.layers || !this.layers.value) return null; // 查找固定图层 const fixedLayer = this.layers.value.find((layer) => layer.isFixed); if (!fixedLayer) return null; // 返回图层中的fabric对象 return fixedLayer.fabricObject || null; } /** * 获取所有普通图层对象(包括红绿图) * @returns {Array} 普通图层对象数组 * @private */ _getNormalLayerObjects() { if (!this.layers || !this.layers.value) return []; // 查找所有非背景、非固定的普通图层 const normalLayers = this.layers.value.filter( (layer) => !layer.isBackground && !layer.isFixed ); // 收集所有普通图层中的对象 const objects = []; normalLayers.forEach((layer) => { // 如果有单个对象属性 if (layer.fabricObject) { objects.push(layer.fabricObject); } // 如果有对象数组 if (Array.isArray(layer.fabricObjects)) { layer.fabricObjects.forEach((obj) => { if (obj) objects.push(obj); }); } }); return objects; } /** * 判断对象是否可能是红绿图 * 通过比较与衣服底图的大小、位置来判断 * @param {Object} obj 要检查的对象 * @param {Object} fixedLayerObject 固定图层对象(衣服底图) * @returns {Boolean} 是否可能是红绿图 * @private */ _isLikelyRedGreenImage(obj, fixedLayerObject) { if (!obj || !fixedLayerObject) return false; // 检查对象是否为图像 if (obj.type !== "image") return false; // 比较尺寸(允许5%的误差) const sizeMatch = Math.abs( obj.width * obj.scaleX - fixedLayerObject.width * fixedLayerObject.scaleX ) < fixedLayerObject.width * fixedLayerObject.scaleX * 0.05 && Math.abs( obj.height * obj.scaleY - fixedLayerObject.height * fixedLayerObject.scaleY ) < fixedLayerObject.height * fixedLayerObject.scaleY * 0.05; // 比较位置(允许一定的偏差) const positionMatch = Math.abs(obj.left - fixedLayerObject.left) < 50 && Math.abs(obj.top - fixedLayerObject.top) < 50; return sizeMatch && positionMatch; } }