合并画布
This commit is contained in:
@@ -66,11 +66,13 @@ export class CanvasManager {
|
||||
// 初始化缩略图管理器
|
||||
this.thumbnailManager = new ThumbnailManager(this.canvas, {
|
||||
// 可以根据需求自定义选项
|
||||
layerThumbSize: { width: 32, height: 32 },
|
||||
elementThumbSize: { width: 32, height: 24 },
|
||||
// layerThumbSize: { width: 32, height: 32 },
|
||||
// elementThumbSize: { width: 32, height: 24 },
|
||||
layers: this.layers,
|
||||
});
|
||||
|
||||
this.canvas.thumbnailManager = this.thumbnailManager; // 将缩略图管理器绑定到画布
|
||||
|
||||
// 设置画布辅助线
|
||||
initAligningGuidelines(this.canvas);
|
||||
|
||||
@@ -110,6 +112,8 @@ export class CanvasManager {
|
||||
activeLayer,
|
||||
});
|
||||
|
||||
this.thumbnailManager?.generateLayerThumbnail(activeLayer.id);
|
||||
|
||||
// 返回true表示不要自动添加到画布,因为我们已经通过图层管理器处理了
|
||||
return true;
|
||||
} else {
|
||||
@@ -147,6 +151,10 @@ export class CanvasManager {
|
||||
// 更新交互性
|
||||
command &&
|
||||
(await this.layerManager?.updateLayersObjectsInteractivity?.());
|
||||
|
||||
this.thumbnailManager?.generateLayerThumbnail(
|
||||
this.layerManager?.activeLayerId?.value
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -340,9 +348,9 @@ export class CanvasManager {
|
||||
* 重置视图变换,使元素回到原始位置
|
||||
* @private
|
||||
*/
|
||||
_resetViewportTransform() {
|
||||
_resetViewportTransform(zoom) {
|
||||
// 保存当前缩放值
|
||||
const currentZoom = this.canvas.getZoom();
|
||||
const currentZoom = zoom ?? this.canvas.getZoom();
|
||||
|
||||
// 重置视图变换,但保留缩放级别
|
||||
this.canvas.setViewportTransform([currentZoom, 0, 0, currentZoom, 0, 0]);
|
||||
@@ -370,6 +378,14 @@ export class CanvasManager {
|
||||
// 获取背景对象
|
||||
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("未找到背景层,使用默认居中逻辑");
|
||||
@@ -462,9 +478,12 @@ export class CanvasManager {
|
||||
|
||||
setCanvasColor(color) {
|
||||
this.backgroundColor = color;
|
||||
this.canvas.setBackgroundColor(
|
||||
color,
|
||||
this.canvas.renderAll.bind(this.canvas)
|
||||
// this.canvas.setBackgroundColor(
|
||||
// color,
|
||||
// this.canvas.renderAll.bind(this.canvas)
|
||||
// );
|
||||
this.thumbnailManager?.generateLayerThumbnail?.(
|
||||
this.layers?.value.find((layer) => layer.isBackground)?.id
|
||||
);
|
||||
}
|
||||
|
||||
@@ -615,80 +634,15 @@ export class CanvasManager {
|
||||
* @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
|
||||
);
|
||||
}
|
||||
this.thumbnailManager?.generateLayerThumbnail?.(layerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有图层和元素的缩略图
|
||||
*/
|
||||
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
|
||||
);
|
||||
}
|
||||
});
|
||||
this.thumbnailManager?.generateAllLayerThumbnails?.(this.layers.value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -710,6 +664,7 @@ export class CanvasManager {
|
||||
layerManager: this.layerManager,
|
||||
imageUrl: imageUrl,
|
||||
targetLayerType: options.targetLayerType || "fixed", // background/fixed
|
||||
options: options,
|
||||
});
|
||||
|
||||
command.undoable =
|
||||
@@ -812,110 +767,72 @@ export class CanvasManager {
|
||||
|
||||
getJSON() {
|
||||
// // 简化图层数据,在loadJSON时要根据id恢复引用
|
||||
// let tempLayers = this.layers ? this.layers.value : [];
|
||||
// // 创建对象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
|
||||
// )}`;
|
||||
// }
|
||||
|
||||
// const simplifyLayers = (layers) => {
|
||||
// return layers.map((layer) => {
|
||||
// if (layer?.children?.length) {
|
||||
// layer.children = layer.children.map((child) => {
|
||||
// return {
|
||||
// id: item.id,
|
||||
// type: item.type || "object", // 保存类型信息用于调试
|
||||
// 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,
|
||||
// })) || [],
|
||||
// };
|
||||
// })
|
||||
// .filter((item) => item !== null);
|
||||
// } else {
|
||||
// newLayer.fabricObjects = [];
|
||||
// }
|
||||
|
||||
// if (layer.clippingMask) {
|
||||
// layer.clippingMask = {
|
||||
// id: layer.clippingMask.id,
|
||||
// };
|
||||
// }
|
||||
|
||||
// // 处理单个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",
|
||||
// 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,
|
||||
// };
|
||||
// } 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 {
|
||||
console.log(
|
||||
"获取画布JSON数据...",
|
||||
simplifyLayers(JSON.parse(JSON.stringify(this.layers.value)))
|
||||
const simplifyLayersData = simplifyLayers(
|
||||
JSON.parse(JSON.stringify(this.layers.value))
|
||||
);
|
||||
console.log("获取画布JSON数据...", simplifyLayersData);
|
||||
return JSON.stringify({
|
||||
canvas: this.canvas.toJSON([
|
||||
"id",
|
||||
@@ -931,15 +848,14 @@ export class CanvasManager {
|
||||
"eraserable",
|
||||
"erasable",
|
||||
]),
|
||||
layers: JSON.stringify(
|
||||
simplifyLayers(JSON.parse(JSON.stringify(this.layers.value)))
|
||||
), // 简化图层数据
|
||||
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.canvas.activeLayerId.value,
|
||||
activeLayerId: this.layerManager?.activeLayerId?.value,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("获取画布JSON失败:", error);
|
||||
@@ -960,7 +876,7 @@ export class CanvasManager {
|
||||
try {
|
||||
const parsedJson = JSON.parse(json);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const tempLayers = JSON.parse(parsedJson?.layers) || [];
|
||||
const canvasData = parsedJson?.canvas;
|
||||
|
||||
@@ -983,19 +899,43 @@ export class CanvasManager {
|
||||
console.log("是否检测到红绿图模式内容:", this.enabledRedGreenMode);
|
||||
|
||||
// 重置视图变换以确保元素位置正确
|
||||
this._resetViewportTransform();
|
||||
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,
|
||||
@@ -1010,8 +950,8 @@ export class CanvasManager {
|
||||
|
||||
console.log("图层关联验证结果:", isValidate);
|
||||
|
||||
this.canvas.activeLayerId.value =
|
||||
parsedJson?.activeLayerId || this.layers.value[0]?.id || null;
|
||||
this.layerManager.activeLayerId.value =
|
||||
this.layers.value[0]?.id || parsedJson?.activeLayerId || null;
|
||||
|
||||
// // 如果检测到红绿图模式内容,进行缩放调整
|
||||
// if (this.enabledRedGreenMode) {
|
||||
@@ -1026,12 +966,11 @@ export class CanvasManager {
|
||||
false
|
||||
);
|
||||
console.log(this.layerManager.layers.value);
|
||||
debugger;
|
||||
|
||||
// 更新所有缩略图
|
||||
setTimeout(() => {
|
||||
this.updateAllThumbnails();
|
||||
}, 100);
|
||||
}, 500);
|
||||
|
||||
console.log("画布JSON数据加载完成");
|
||||
resolve();
|
||||
|
||||
Reference in New Issue
Block a user