feat(CanvasManager): enhance image layer management and event handling
This commit is contained in:
@@ -35,13 +35,19 @@ import { fabric } from "fabric-with-all";
|
||||
import {
|
||||
uploadImageAndCreateLayer,
|
||||
loadImageUrlToLayer,
|
||||
loadImage,
|
||||
} from "./utils/imageHelper.js";
|
||||
import { next } from "lodash-es";
|
||||
// import MinimapPanel from "./components/MinimapPanel.vue";
|
||||
const KeyboardShortcutHelp = defineAsyncComponent(() =>
|
||||
import("./components/KeyboardShortcutHelp.vue")
|
||||
);
|
||||
|
||||
const emit = defineEmits(["trigger-red-green-mouseup", "changeCanvas"]);
|
||||
const emit = defineEmits([
|
||||
"trigger-red-green-mouseup", // 红绿图模式鼠标抬起事件
|
||||
"changeCanvas", // 画布变更事件
|
||||
"canvasInit", // 画布初始化事件
|
||||
]);
|
||||
|
||||
const props = defineProps({
|
||||
canvasJSON: {
|
||||
@@ -151,6 +157,24 @@ function handleToolSelect(tool) {
|
||||
}); // 命令模式 可撤回操作
|
||||
}
|
||||
|
||||
// 触发组件初始化事件
|
||||
function handleCanvasInit(isLoadJson = false) {
|
||||
emit("canvasInit", {
|
||||
isLoadJson: isLoadJson ?? !!props.canvasJSON, // 是否加载了JSON数据
|
||||
isRedGreenMode: isRedGreenMode.value,
|
||||
layers,
|
||||
activeLayerId,
|
||||
canvasManager,
|
||||
layerManager,
|
||||
commandManager,
|
||||
toolManager,
|
||||
keyboardManager,
|
||||
liquifyManager,
|
||||
selectionManager,
|
||||
redGreenModeManager,
|
||||
});
|
||||
}
|
||||
|
||||
function toggleMinimap(enabled) {
|
||||
// minimapEnabled.value = enabled;
|
||||
// if (minimapManager.value) {
|
||||
@@ -177,6 +201,7 @@ onMounted(async () => {
|
||||
canvasHeight,
|
||||
canvasColor,
|
||||
enabledRedGreenMode: props.enabledRedGreenMode,
|
||||
isFixedErasable: props.isFixedErasable,
|
||||
});
|
||||
canvasManager.canvas.activeLayerId = activeLayerId;
|
||||
canvasManager.canvas.activeElementId = activeElementId;
|
||||
@@ -205,24 +230,6 @@ onMounted(async () => {
|
||||
// 设置缩略图管理器需要访问的图层数据
|
||||
// canvasManager.layers = layers;
|
||||
|
||||
if (props.canvasJSON) {
|
||||
// 如果传入了初始JSON数据,加载到画布上
|
||||
if (typeof props.canvasJSON === "string") {
|
||||
try {
|
||||
canvasManager.loadJSON(props.canvasJSON);
|
||||
} catch (error) {
|
||||
console.error("加载画布JSON失败:", error);
|
||||
// 初始化图层 - 确保创建背景层
|
||||
layerManager.initializeLayers();
|
||||
}
|
||||
} else if (typeof props.canvasJSON === "object") {
|
||||
canvasManager.loadJSON(JSON.stringify(props.canvasJSON));
|
||||
}
|
||||
} else {
|
||||
// 初始化图层 - 确保创建背景层
|
||||
layerManager.initializeLayers();
|
||||
}
|
||||
|
||||
// 创建工具管理器实例
|
||||
toolManager = new ToolManager({
|
||||
canvas: canvasManager.canvas, // fabric.js 画布实例
|
||||
@@ -253,6 +260,9 @@ onMounted(async () => {
|
||||
|
||||
// 绑定快捷键事件
|
||||
keyboardManager.init();
|
||||
// 绑定画布操作事件
|
||||
canvasManager.setupCanvasEvents(activeElementId, layerManager);
|
||||
canvasManager.setupCanvasInitEvent(handleCanvasInit); // 绑定画布初始化事件
|
||||
|
||||
provide("canvasManager", canvasManager); // 提供给子组件使用
|
||||
provide("layerManager", layerManager); // 提供给子组件使用
|
||||
@@ -262,27 +272,12 @@ onMounted(async () => {
|
||||
provide("activeTool", activeTool); // 提供给子组件使用
|
||||
provide("liquifyManager", () => liquifyManager); // 提供液化管理器
|
||||
provide("layers", layers); // 提供图层数据
|
||||
|
||||
// 绑定画布操作事件
|
||||
canvasManager.setupCanvasEvents(activeElementId, layerManager);
|
||||
|
||||
canvasManagerLoaded.value = true;
|
||||
|
||||
// 初始化网格设置
|
||||
// toggleGridVisibility(gridEnabled.value);
|
||||
|
||||
// 初始化小地图
|
||||
// minimapManager.value = new MinimapManager(canvasManager.canvas);
|
||||
|
||||
setTimeout(() => {
|
||||
// 初始状态下生成所有预览图
|
||||
canvasManager.updateAllThumbnails();
|
||||
}, 300);
|
||||
|
||||
// 使用window的resize事件代替ResizeObserver
|
||||
// 只有当窗口大小变化时才更新画布尺寸
|
||||
window.addEventListener("resize", handleWindowResize);
|
||||
|
||||
// 初始化液化管理器
|
||||
liquifyManager = new LiquifyManager({
|
||||
canvas: canvasManager.canvas,
|
||||
@@ -298,6 +293,24 @@ onMounted(async () => {
|
||||
});
|
||||
canvasManager.setSelectionManager(selectionManager);
|
||||
|
||||
if (props.canvasJSON) {
|
||||
// 如果传入了初始JSON数据,加载到画布上
|
||||
if (typeof props.canvasJSON === "string") {
|
||||
try {
|
||||
await canvasManager.loadJSON(props.canvasJSON);
|
||||
} catch (error) {
|
||||
console.error("加载画布JSON失败:", error);
|
||||
// 初始化图层 - 确保创建背景层
|
||||
await layerManager.initializeLayers();
|
||||
}
|
||||
} else if (typeof props.canvasJSON === "object") {
|
||||
await canvasManager.loadJSON(JSON.stringify(props.canvasJSON));
|
||||
}
|
||||
} else {
|
||||
// 初始化图层 - 确保创建背景层
|
||||
await layerManager.initializeLayers();
|
||||
}
|
||||
|
||||
if (
|
||||
props.enabledRedGreenMode &&
|
||||
props.clothingImageUrl &&
|
||||
@@ -340,18 +353,14 @@ onMounted(async () => {
|
||||
// 初始设置
|
||||
handleWindowResize(); // 设置画布大小
|
||||
} else if (!isRedGreenMode.value && props.clothingImageUrl) {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
canvasManager?.changeFixedImage?.(props.clothingImageUrl, {
|
||||
undoable: false, // 不可撤销操作
|
||||
...(props?.clothingImageOpts || {}),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("更换底图失败:", error);
|
||||
}
|
||||
}, 92); // 延迟 确保更新底图完成
|
||||
});
|
||||
try {
|
||||
await canvasManager?.changeFixedImage?.(props.clothingImageUrl, {
|
||||
undoable: false, // 不可撤销操作
|
||||
...(props?.clothingImageOpts || {}),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("更换底图失败:", error);
|
||||
}
|
||||
|
||||
canvasManager?.centerBackgroundLayer?.(
|
||||
canvasManager.canvas.width,
|
||||
@@ -369,6 +378,24 @@ onMounted(async () => {
|
||||
// type: "isBackground",
|
||||
// flag: !props.isBackgroundErasable, // 设置操作类型为可擦除
|
||||
// });
|
||||
|
||||
canvasManagerLoaded.value = true;
|
||||
|
||||
// 触发组件初始化事件
|
||||
nextTick(() => {
|
||||
// 确保所有依赖都已加载完成
|
||||
handleCanvasInit();
|
||||
requestAnimationFrame(() => {
|
||||
setTimeout(() => {
|
||||
// 初始状态下生成所有预览图
|
||||
canvasManager.updateAllThumbnails();
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
|
||||
// 使用window的resize事件代替ResizeObserver
|
||||
// 只有当窗口大小变化时才更新画布尺寸
|
||||
window.addEventListener("resize", handleWindowResize);
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
@@ -707,18 +734,38 @@ defineExpose({
|
||||
},
|
||||
// (更换底图,不可撤销,不可操作)
|
||||
changeFixedImage: (url, opts) => {
|
||||
return canvasManager?.changeFixedImage?.(url, opts);
|
||||
return canvasManager?.changeFixedImage?.(url, {
|
||||
...(props?.clothingImageOpts || {}),
|
||||
...opts,
|
||||
});
|
||||
},
|
||||
//图片url或者base64
|
||||
addImageToLayer: async (url) => {
|
||||
addImageToLayer: async (
|
||||
url,
|
||||
{ layerId, undoable } = { layerId: null, undoable: true } // 可选参数 layerId 指定图层 将内容添加到指定图层 undoable 是否可撤销 false不可撤销 默认可撤销
|
||||
) => {
|
||||
if (!url) return Promise.reject(new Error("图片URL不能为空"));
|
||||
|
||||
return await loadImageUrlToLayer({
|
||||
imageUrl: url,
|
||||
layerManager,
|
||||
canvas: canvasManager.canvas,
|
||||
toolManager,
|
||||
});
|
||||
if (layerId) {
|
||||
const fabricImage = await loadImage(url);
|
||||
// 如果指定了图层ID,确保图层存在
|
||||
return await canvasManager?.addImageToLayer?.(url, {
|
||||
targetLayerId: layerId,
|
||||
fabricImage,
|
||||
undoable, // 是否可撤销操作
|
||||
});
|
||||
}
|
||||
|
||||
// 未指定图层ID,默认添加到新的图层
|
||||
return await loadImageUrlToLayer(
|
||||
{
|
||||
imageUrl: url,
|
||||
layerManager,
|
||||
canvas: canvasManager.canvas,
|
||||
toolManager,
|
||||
},
|
||||
{ undoable }
|
||||
);
|
||||
},
|
||||
// 导出图片
|
||||
exportImage: ({
|
||||
|
||||
Reference in New Issue
Block a user