Files
aida_front/src/component/Canvas/CanvasEditor/managers/CanvasManager.js

1187 lines
35 KiB
JavaScript
Raw Normal View History

2025-06-09 10:25:54 +08:00
//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 {
ChangeFixedImageCommand,
AddImageToLayerCommand,
} from "../commands/ObjectLayerCommands";
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.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.redGreenModeManager = new RedGreenModeManager({
canvas: this.canvas,
layerManager: null, // 稍后设置
toolManager: null, // 稍后设置
commandManager: null, // 稍后设置
});
// 设置画布辅助线
initAligningGuidelines(this.canvas);
// 设置画布中心线
initCenteringGuidelines(this.canvas);
// 初始化画布事件监听器
this._initCanvasEvents();
}
/**
* 初始化画布事件监听器
* 设置鼠标事件键盘事件等
* @private
*/
_initCanvasEvents() {
// 添加笔刷图像转换处理回调
this.canvas.onBrushImageConverted = (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)}`,
});
// 执行高保真合并操作
this.eventManager?.mergeLayerObjectsForPerformance?.({
fabricImage,
activeLayer,
});
// 返回false表示不要自动添加到画布因为我们已经通过图层管理器处理了
return false;
} else {
console.warn("没有活动图层,使用默认行为添加图像");
}
}
// 返回true表示使用默认行为直接添加到画布
return true;
};
}
/**
* 设置编辑器模式
* @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;
}
}
/**
* 设置命令管理器
* @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();
}
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() {
// 保存当前缩放值
const currentZoom = 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 ||
(visibleObjects.length === 1 && visibleObjects[0].isBackground)
) {
// 尝试居中背景层
this.centerBackgroundLayer(this.width, this.height);
return;
}
// 单独处理背景层
const backgroundObject = visibleObjects.find((obj) => obj.isBackground);
const contentObjects = backgroundObject
? visibleObjects.filter((obj) => obj !== backgroundObject)
: visibleObjects;
// 如果只有背景层,居中背景层
if (contentObjects.length === 0 && backgroundObject) {
this.centerBackgroundLayer(this.width, this.height);
return;
}
// 计算内容对象的边界
const bounds = this._calculateObjectsBounds(contentObjects);
// 计算所有对象的中心点
const objectsCenterX = bounds.left + bounds.width / 2;
const objectsCenterY = bounds.top + bounds.height / 2;
// 计算画布中心点
const canvasCenterX = this.width / 2;
const canvasCenterY = this.height / 2;
// 计算需要移动的距离
const deltaX = canvasCenterX - objectsCenterX;
const deltaY = canvasCenterY - objectsCenterY;
// 移动所有对象,包括背景层
visibleObjects.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} 边界信息包含lefttopwidthheight
*/
_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)
);
}
/**
* 居中背景层
* @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.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({
width: bgWidth,
height: bgHeight,
left: left,
top: top,
fill: "transparent",
stroke: "#cccccc",
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: 0,
top: 0,
originX: backgroundLayerObject.originX || "left",
originY: backgroundLayerObject.originY || "top",
absolutePositioned: true,
});
// 设置蒙层位置
this.canvas.clipPath.set({
left: left,
top: top,
});
this.canvas.renderAll();
}
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) {
if (!this.thumbnailManager || !layerId || !this.layers) return;
const layer = this.layers.value.find((l) => l.id === layerId);
if (layer) {
this.thumbnailManager.generateLayerThumbnail(layer);
}
}
/**
* 更新指定元素图层的缩略图
* @param {String} elementId 元素ID
* @param {Object} fabricObject fabric对象
*/
updateElementThumbnail(elementId, fabricObject) {
if (this.eventManager) {
this.eventManager.updateElementThumbnail(elementId, fabricObject);
} else if (
this.thumbnailManager &&
elementId &&
fabricObject &&
this.layers
) {
// 查找对应的图层(现在元素就是图层)
const layer = this.layers.value.find(
(l) =>
l.id === elementId ||
(l.fabricObject && l.fabricObject.id === elementId)
);
if (layer) {
// 生成图层缩略图
this.thumbnailManager.generateLayerThumbnail(layer);
}
// 同时也维护元素缩略图,以保持向后兼容性
this.thumbnailManager.generateElementThumbnail(
{ id: elementId, type: fabricObject.type },
fabricObject
);
}
}
/**
* 更新所有图层和元素的缩略图
*/
updateAllThumbnails() {
if (!this.thumbnailManager || !this.layers) return;
this.thumbnailManager.generateAllLayerThumbnails(this.layers.value);
// 为所有元素生成缩略图
this.layers.value.forEach((layer) => {
// 如果是分组图层,处理子图层
if (isGroupLayer(layer) && layer.children) {
layer.children.forEach((childLayerId) => {
const childLayer = this.layers.value.find(
(l) => l.id === childLayerId
);
if (childLayer && childLayer.fabricObject) {
this.thumbnailManager.generateElementThumbnail(
{ id: childLayer.id, type: childLayer.fabricObject.type },
childLayer.fabricObject
);
}
});
}
// 如果是元素图层,则直接生成缩略图
else if (layer.isElementLayer && layer.fabricObject) {
this.thumbnailManager.generateElementThumbnail(
{ id: layer.id, type: layer.fabricObject.type },
layer.fabricObject
);
}
});
}
/**
* 导出图片
* @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)
* @returns {String} 导出的图片数据URL
*/
exportImage(options = {}) {
if (!this.exportManager) {
console.error("导出管理器未初始化,请确保已设置图层管理器");
throw new Error("导出管理器未初始化");
}
try {
return this.exportManager.exportImage(options);
} 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恢复引用
let tempLayers = this.layers ? this.layers.value : [];
// 为所有fabric对象生成ID如果没有的话
const canvasObjects = this.canvas.getObjects();
canvasObjects.forEach((obj) => {
if (!obj.id) {
obj.id = `obj_${Date.now()}_${Math.floor(Math.random() * 10000)}`;
}
});
// 创建对象ID映射表用于快速查找
const objectIdMap = new Map();
canvasObjects.forEach((obj) => {
if (obj.id) {
objectIdMap.set(obj, obj.id);
}
});
tempLayers = tempLayers.map((layer) => {
const newLayer = { ...layer };
// 处理fabricObjects数组
if (Array.isArray(layer.fabricObjects)) {
newLayer.fabricObjects = layer.fabricObjects
.map((item) => {
if (!item) return null;
// 确保对象有ID
if (!item.id) {
item.id = `obj_${Date.now()}_${Math.floor(
Math.random() * 10000
)}`;
}
return {
id: item.id,
type: item.type || "object", // 保存类型信息用于调试
};
})
.filter((item) => item !== null);
} else {
newLayer.fabricObjects = [];
}
// 处理单个fabricObject
if (layer.fabricObject) {
if (!layer.fabricObject.id) {
layer.fabricObject.id = `obj_${Date.now()}_${Math.floor(
Math.random() * 10000
)}`;
}
newLayer.fabricObject = {
id: layer.fabricObject.id,
type: layer.fabricObject.type || "object",
};
} else {
newLayer.fabricObject = null;
}
// 处理子图层
if (Array.isArray(layer.children)) {
newLayer.children = layer.children.map((cItem) => {
const newChild = { ...cItem };
// 处理子图层的fabricObjects
if (Array.isArray(cItem.fabricObjects)) {
newChild.fabricObjects = cItem.fabricObjects
.map((item) => {
if (!item) return null;
if (!item.id) {
item.id = `obj_${Date.now()}_${Math.floor(
Math.random() * 10000
)}`;
}
return {
id: item.id,
type: item.type || "object",
};
})
.filter((item) => item !== null);
} else {
newChild.fabricObjects = [];
}
// 处理子图层的fabricObject
if (cItem.fabricObject) {
if (!cItem.fabricObject.id) {
cItem.fabricObject.id = `obj_${Date.now()}_${Math.floor(
Math.random() * 10000
)}`;
}
newChild.fabricObject = {
id: cItem.fabricObject.id,
type: cItem.fabricObject.type || "object",
};
} else {
newChild.fabricObject = null;
}
return newChild;
});
} else {
newLayer.children = [];
}
return newLayer;
});
try {
return JSON.stringify({
canvas: this.canvas.toJSON([
"id",
"layerId",
"layerName",
"isBackground",
"isFixed",
"parentId",
"excludeFromExport",
]),
layers: tempLayers,
version: "1.0", // 添加版本信息
timestamp: new Date().toISOString(), // 添加时间戳
canvasWidth: this.canvasWidth.value,
canvasHeight: this.canvasHeight.value,
canvasColor: this.canvasColor.value,
activeLayerId: this.canvas.activeLayerId.value,
});
} catch (error) {
console.error("获取画布JSON失败:", error);
throw new Error("获取画布JSON失败");
}
}
loadJSON(json) {
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((resolve, reject) => {
const tempLayers = parsedJson?.layers || [];
const canvasData = parsedJson?.canvas;
if (!tempLayers) {
reject(new Error("JSON数据中缺少layers字段"));
return;
}
if (!canvasData) {
reject(new Error("JSON数据中缺少canvas字段"));
return;
}
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();
// 清除当前画布内容
this.canvas.clear();
// 加载画布数据
this.canvas.loadFromJSON(canvasData, () => {
this.backgroundColor = parsedJson.backgroundColor || "#ffffff";
try {
// 重置画布数据
this.setCanvasSize(this.canvas.width, this.canvas.height);
// 创建对象ID映射表用于快速查找
const objectIdMap = new Map();
const canvasObjects = this.canvas.getObjects();
canvasObjects.forEach((obj) => {
if (obj.id) {
objectIdMap.set(obj.id, obj);
}
});
// 辅助函数根据ID查找对象
const findObjectById = (id) => {
if (!id) return null;
return objectIdMap.get(id) || null;
};
// 恢复图层数据
this.layers.value = tempLayers.map((layer) => {
const restoredLayer = { ...layer };
// 恢复fabricObjects数组
if (Array.isArray(layer.fabricObjects)) {
restoredLayer.fabricObjects = layer.fabricObjects
.map((item) => {
if (!item || !item.id) return null;
return findObjectById(item.id);
})
.filter((obj) => obj !== null);
} else {
restoredLayer.fabricObjects = [];
}
// 恢复单个fabricObject
if (layer.fabricObject && layer.fabricObject.id) {
restoredLayer.fabricObject = findObjectById(
layer.fabricObject.id
);
} else {
restoredLayer.fabricObject = null;
}
// 恢复子图层
if (Array.isArray(layer.children)) {
restoredLayer.children = layer.children.map((cItem) => {
const restoredChild = { ...cItem };
// 恢复子图层的fabricObjects
if (Array.isArray(cItem.fabricObjects)) {
restoredChild.fabricObjects = cItem.fabricObjects
.map((item) => {
if (!item || !item.id) return null;
return findObjectById(item.id);
})
.filter((obj) => obj !== null);
} else {
restoredChild.fabricObjects = [];
}
// 恢复子图层的fabricObject
if (cItem.fabricObject && cItem.fabricObject.id) {
restoredChild.fabricObject = findObjectById(
cItem.fabricObject.id
);
} else {
restoredChild.fabricObject = null;
}
return restoredChild;
});
} else {
restoredLayer.children = [];
}
return restoredLayer;
});
this.canvas.activeLayerId.value =
parsedJson?.activeLayerId || this.layers.value[0]?.id || null;
// 如果检测到红绿图模式内容,进行缩放调整
if (this.enabledRedGreenMode) {
this._rescaleRedGreenModeContent();
}
// 更新所有缩略图
setTimeout(() => {
this.updateAllThumbnails();
}, 100);
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;
}
}