fix: 优化细节
This commit is contained in:
@@ -72,7 +72,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
||||
originY: clippingMaskFabricObject.originY || "center",
|
||||
scaleX: clippingMaskFabricObject.scaleX || 1,
|
||||
scaleY: clippingMaskFabricObject.scaleY || 1,
|
||||
// type: "fill",
|
||||
});
|
||||
// this.newFill.clipPath = clippingMaskFabricObject;
|
||||
// this.newFill.dirty = true;
|
||||
@@ -92,7 +91,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
|
||||
evented: false,
|
||||
originX: "center",
|
||||
originY: "center",
|
||||
// type: "fill",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,10 @@ export class FillLayerBackgroundCommand extends Command {
|
||||
let clippingMaskFabricObject = null;
|
||||
if (layer.clippingMask) {
|
||||
// 反序列化 clippingMask
|
||||
clippingMaskFabricObject = await restoreFabricObject(layer.clippingMask, this.canvas);
|
||||
clippingMaskFabricObject = await restoreFabricObject(
|
||||
layer.clippingMask,
|
||||
this.canvas
|
||||
);
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
|
||||
clippingMaskFabricObject.set({
|
||||
@@ -75,7 +78,6 @@ export class FillLayerBackgroundCommand extends Command {
|
||||
originY: clippingMaskFabricObject.originY || "center",
|
||||
scaleX: clippingMaskFabricObject.scaleX || 1,
|
||||
scaleY: clippingMaskFabricObject.scaleY || 1,
|
||||
type: "fill",
|
||||
});
|
||||
|
||||
this.newFill.clipPath = clippingMaskFabricObject; // 设置填充的遮罩
|
||||
@@ -96,7 +98,6 @@ export class FillLayerBackgroundCommand extends Command {
|
||||
evented: false,
|
||||
originX: "center",
|
||||
originY: "center",
|
||||
type: "fill",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -104,11 +105,15 @@ export class FillLayerBackgroundCommand extends Command {
|
||||
// 判断fabricObjects是否是组,是组则添加填充到最前面,否则创建组
|
||||
if (layer.fabricObjects && layer.fabricObjects.length > 0) {
|
||||
let insertIndex =
|
||||
this.canvas.getObjects()?.findIndex((obj) => obj.id === layer.fabricObjects?.[0]?.id) || 0;
|
||||
this.canvas
|
||||
.getObjects()
|
||||
?.findIndex((obj) => obj.id === layer.fabricObjects?.[0]?.id) || 0;
|
||||
if (this.oldFill) {
|
||||
// 如果有旧填充,先获取旧的索引再移除旧填充
|
||||
insertIndex =
|
||||
this.canvas.getObjects()?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
|
||||
this.canvas
|
||||
.getObjects()
|
||||
?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
|
||||
removeCanvasObjectByObject(this.canvas, this.oldFill);
|
||||
}
|
||||
insertIndex = insertIndex == -1 ? 0 : insertIndex;
|
||||
@@ -122,13 +127,17 @@ export class FillLayerBackgroundCommand extends Command {
|
||||
.getObjects()
|
||||
.findIndex(
|
||||
(obj) =>
|
||||
obj.id === this.originalfabricObjects[this.originalfabricObjects.length - 1]?.id
|
||||
obj.id ===
|
||||
this.originalfabricObjects[this.originalfabricObjects.length - 1]
|
||||
?.id
|
||||
) || 0;
|
||||
|
||||
if (this.oldFill) {
|
||||
// 如果有旧填充,先获取旧的索引再移除旧填充
|
||||
insertIndex =
|
||||
this.canvas.getObjects()?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
|
||||
this.canvas
|
||||
.getObjects()
|
||||
?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
|
||||
removeCanvasObjectByObject(this.canvas, this.oldFill);
|
||||
}
|
||||
insertIndex = insertIndex == -1 ? 0 : insertIndex;
|
||||
@@ -142,7 +151,9 @@ export class FillLayerBackgroundCommand extends Command {
|
||||
if (!this.isRetimeUpdate) {
|
||||
layer.fill = this.newFill.toObject(["id", "layerId"]);
|
||||
layer.fillColor = this.fillColor;
|
||||
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layer.id);
|
||||
this.canvasManager.thumbnailManager?.generateLayerThumbnail(
|
||||
this.layer.id
|
||||
);
|
||||
|
||||
// 重新排序
|
||||
// 使用LayerSort工具重新排列画布对象(如果可用)
|
||||
@@ -187,7 +198,10 @@ export class FillLayerBackgroundCommand extends Command {
|
||||
.map((obj) => {
|
||||
return findObjectById(this.canvas.value, obj.id)?.object || obj;
|
||||
});
|
||||
} else if (this.layer.fabricObjects && this.layer.fabricObjects.length > 0) {
|
||||
} 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;
|
||||
@@ -204,11 +218,17 @@ export class FillLayerBackgroundCommand extends Command {
|
||||
minTop = Infinity,
|
||||
maxRight = -Infinity,
|
||||
maxBottom = -Infinity;
|
||||
console.log("计算当前所有对象的边界信息:===>", this.originalfabricObjects.length);
|
||||
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 });
|
||||
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);
|
||||
|
||||
@@ -224,7 +224,7 @@ export class AddObjectToLayerCommand extends Command {
|
||||
isLocked: layer.locked || false, // 是否锁定
|
||||
isVisible: layer.visible !== false, // 是否可见
|
||||
eraser: layer.eraser || false, // 是否为橡皮擦
|
||||
type: this.fabricObject.type || "object", // 对象类型
|
||||
// type: this.fabricObject.type || "object", // 对象类型
|
||||
selectable: true, // 设置对象可选择
|
||||
evented: true, // 设置对象可事件
|
||||
});
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { Command } from "./Command";
|
||||
import { fabric } from "fabric-with-all";
|
||||
import { LayerType, OperationType, createLayer, findLayerRecursively } from "../utils/layerHelper";
|
||||
import {
|
||||
LayerType,
|
||||
OperationType,
|
||||
createLayer,
|
||||
findLayerRecursively,
|
||||
} from "../utils/layerHelper";
|
||||
import {
|
||||
generateId,
|
||||
optimizeCanvasRendering,
|
||||
@@ -34,7 +39,10 @@ export class RasterizeLayerCommand extends Command {
|
||||
this.layerManager = options.layerManager;
|
||||
|
||||
// 查找目标图层
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
this.layer = layer;
|
||||
this.parentLayer = parent;
|
||||
this.isGroupLayer = this.layer?.children && this.layer.children.length > 0;
|
||||
@@ -94,7 +102,9 @@ export class RasterizeLayerCommand extends Command {
|
||||
|
||||
console.log(`✅ 图层 ${this.layer.name} 组合完成`);
|
||||
|
||||
this.canvas?.thumbnailManager?.generateLayerThumbnail?.(this.rasterizedLayerId);
|
||||
this.canvas?.thumbnailManager?.generateLayerThumbnail?.(
|
||||
this.rasterizedLayerId
|
||||
);
|
||||
return this.rasterizedLayerId;
|
||||
} catch (error) {
|
||||
console.error("组合图层失败:", error);
|
||||
@@ -330,7 +340,7 @@ export class RasterizeLayerCommand extends Command {
|
||||
// 更新图像对象的图层关联
|
||||
rasterizedImage.set({
|
||||
id: this.resterizedId,
|
||||
type: "image",
|
||||
// type: "image",
|
||||
layerId: this.rasterizedLayerId,
|
||||
layerName: this.rasterizedLayer.name,
|
||||
});
|
||||
@@ -352,7 +362,10 @@ export class RasterizeLayerCommand extends Command {
|
||||
*/
|
||||
_replaceLayerInStructure() {
|
||||
// 1.当前如果是子图层,则插入到子图层的位置
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
|
||||
let insertIndex = 0;
|
||||
// 说明是子图层
|
||||
@@ -373,7 +386,11 @@ export class RasterizeLayerCommand extends Command {
|
||||
if (insertIndex !== -1) {
|
||||
if (parent) {
|
||||
const pIndex = this.layers.value.findIndex((l) => l.id === parent.id);
|
||||
this.layers.value[pIndex].children?.splice?.(insertIndex, 1, this.rasterizedLayer);
|
||||
this.layers.value[pIndex].children?.splice?.(
|
||||
insertIndex,
|
||||
1,
|
||||
this.rasterizedLayer
|
||||
);
|
||||
} else {
|
||||
this.layers.value.splice(insertIndex, 1, this.rasterizedLayer);
|
||||
}
|
||||
@@ -391,9 +408,14 @@ export class RasterizeLayerCommand extends Command {
|
||||
async _getMaskObject() {
|
||||
// 如果图层有clippingMask,获取对应的fabric对象
|
||||
if (this.layer?.clippingMask) {
|
||||
const { object: maskObject } = findObjectById(this.canvas, this.layer.clippingMask.id);
|
||||
const { object: maskObject } = findObjectById(
|
||||
this.canvas,
|
||||
this.layer.clippingMask.id
|
||||
);
|
||||
if (maskObject) {
|
||||
console.log(`📎 找到遮罩对象: ${maskObject.id}, 类型: ${maskObject.type}`);
|
||||
console.log(
|
||||
`📎 找到遮罩对象: ${maskObject.id}, 类型: ${maskObject.type}`
|
||||
);
|
||||
return maskObject;
|
||||
}
|
||||
return await restoreFabricObject(this.layer.clippingMask);
|
||||
@@ -439,7 +461,10 @@ export class ExportLayerToImageCommand extends Command {
|
||||
this.layerManager = options.layerManager;
|
||||
|
||||
// 查找目标图层
|
||||
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
|
||||
const { layer, parent } = findLayerRecursively(
|
||||
this.layers.value,
|
||||
this.layerId
|
||||
);
|
||||
this.layer = layer;
|
||||
this.parentLayer = parent;
|
||||
this.isGroupLayer = this.layer?.children && this.layer.children.length > 0;
|
||||
@@ -475,7 +500,10 @@ export class ExportLayerToImageCommand extends Command {
|
||||
let clippingMaskFabricObject = null;
|
||||
if (this.layer?.clippingMask) {
|
||||
// 重新创建遮罩对象
|
||||
clippingMaskFabricObject = await restoreFabricObject(this.layer?.clippingMask, this.canvas);
|
||||
clippingMaskFabricObject = await restoreFabricObject(
|
||||
this.layer?.clippingMask,
|
||||
this.canvas
|
||||
);
|
||||
|
||||
clippingMaskFabricObject.clipPath = null;
|
||||
clippingMaskFabricObject.set({
|
||||
|
||||
@@ -310,7 +310,11 @@ async function prepareForLiquify(targetObj) {
|
||||
}
|
||||
|
||||
// 获取图层信息
|
||||
const layerId = targetObj.layerId || props.canvas.activeLayerId?.value;
|
||||
const layerId =
|
||||
targetObj.layerId ||
|
||||
canvasManager?.layerManager?.activeLayerId?.value ||
|
||||
canvasManager.activeLayerId?.value ||
|
||||
props.canvas.activeLayerId?.value;
|
||||
targetLayerId.value = layerId;
|
||||
|
||||
try {
|
||||
@@ -374,7 +378,10 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
// 创建状态管理器
|
||||
stateManager.value = new LiquifyStateManager(props.canvas, realtimeUpdater.value);
|
||||
stateManager.value = new LiquifyStateManager(
|
||||
props.canvas,
|
||||
realtimeUpdater.value
|
||||
);
|
||||
}
|
||||
|
||||
// 监听画布事件
|
||||
@@ -443,7 +450,12 @@ function showPanel(event) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("显示液化面板,目标对象:", targetObj.type, "图层ID:", targetLayerIdValue);
|
||||
console.log(
|
||||
"显示液化面板,目标对象:",
|
||||
targetObj.type,
|
||||
"图层ID:",
|
||||
targetLayerIdValue
|
||||
);
|
||||
|
||||
// 更新面板状态,但保持当前模式不变
|
||||
// 只有在首次显示面板或面板已关闭时才重置模式
|
||||
@@ -513,8 +525,8 @@ function showPanel(event) {
|
||||
const status = props.liquifyManager.getStatus
|
||||
? props.liquifyManager.getStatus()
|
||||
: props.liquifyManager.enhancedManager
|
||||
? props.liquifyManager.enhancedManager.getStatus()
|
||||
: {};
|
||||
? props.liquifyManager.enhancedManager.getStatus()
|
||||
: {};
|
||||
|
||||
webglAvailable.value = status.isWebGLAvailable || false;
|
||||
|
||||
@@ -545,8 +557,8 @@ function showPanel(event) {
|
||||
const status = props.liquifyManager.getStatus
|
||||
? props.liquifyManager.getStatus()
|
||||
: props.liquifyManager.enhancedManager
|
||||
? props.liquifyManager.enhancedManager.getStatus()
|
||||
: {};
|
||||
? props.liquifyManager.enhancedManager.getStatus()
|
||||
: {};
|
||||
|
||||
webglAvailable.value = status.isWebGLAvailable || false;
|
||||
|
||||
@@ -605,7 +617,11 @@ function setTargetObject(obj) {
|
||||
|
||||
// 确保对象有唯一ID
|
||||
if (!obj.id && !obj.objectId && !obj.uid) {
|
||||
obj.id = "liquify_target_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
|
||||
obj.id =
|
||||
"liquify_target_" +
|
||||
Date.now() +
|
||||
"_" +
|
||||
Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
|
||||
targetObject.value = obj;
|
||||
@@ -673,7 +689,9 @@ function updateParam(paramName, value) {
|
||||
`set${paramName.charAt(0).toUpperCase() + paramName.slice(1)}`
|
||||
] === "function"
|
||||
) {
|
||||
props.liquifyManager[`set${paramName.charAt(0).toUpperCase() + paramName.slice(1)}`](value);
|
||||
props.liquifyManager[
|
||||
`set${paramName.charAt(0).toUpperCase() + paramName.slice(1)}`
|
||||
](value);
|
||||
} else {
|
||||
console.warn(`❌ 液化管理器不支持设置参数: ${paramName}`);
|
||||
}
|
||||
@@ -756,9 +774,19 @@ async function getCurrentImageData(targetObject) {
|
||||
tempCtx.drawImage(element, 0, 0, tempCanvas.width, tempCanvas.height);
|
||||
|
||||
// 获取ImageData
|
||||
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
const imageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
|
||||
console.log("✅ 成功获取当前图像状态,尺寸:", imageData.width, "x", imageData.height);
|
||||
console.log(
|
||||
"✅ 成功获取当前图像状态,尺寸:",
|
||||
imageData.width,
|
||||
"x",
|
||||
imageData.height
|
||||
);
|
||||
return imageData;
|
||||
} catch (error) {
|
||||
console.warn("获取当前图像数据失败:", error);
|
||||
@@ -837,7 +865,9 @@ async function handleMouseDown(event) {
|
||||
const imageCoords = _convertFabricCoordsToImageCoords(pointer.x, pointer.y);
|
||||
if (imageCoords) {
|
||||
props.liquifyManager.startLiquifyOperation(imageCoords.x, imageCoords.y);
|
||||
console.log(`开始液化操作,图像坐标: (${imageCoords.x}, ${imageCoords.y})`);
|
||||
console.log(
|
||||
`开始液化操作,图像坐标: (${imageCoords.x}, ${imageCoords.y})`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -933,15 +963,27 @@ async function handleMouseUp() {
|
||||
// 尝试从实时更新器获取当前图像数据
|
||||
if (realtimeUpdater.value) {
|
||||
try {
|
||||
const currentImageElement = realtimeUpdater.value.getTargetObject()?._element;
|
||||
const currentImageElement =
|
||||
realtimeUpdater.value.getTargetObject()?._element;
|
||||
if (currentImageElement) {
|
||||
// 从当前图像元素创建ImageData
|
||||
const tempCanvas = document.createElement("canvas");
|
||||
tempCanvas.width = initialImageData.value.width;
|
||||
tempCanvas.height = initialImageData.value.height;
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
tempCtx.drawImage(currentImageElement, 0, 0, tempCanvas.width, tempCanvas.height);
|
||||
finalImageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
tempCtx.drawImage(
|
||||
currentImageElement,
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
finalImageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
|
||||
console.log(
|
||||
"✅ 从实时更新器获取最终图像数据成功,尺寸:",
|
||||
@@ -962,8 +1004,19 @@ async function handleMouseUp() {
|
||||
tempCanvas.width = initialImageData.value.width;
|
||||
tempCanvas.height = initialImageData.value.height;
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
tempCtx.drawImage(currentTarget._element, 0, 0, tempCanvas.width, tempCanvas.height);
|
||||
finalImageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
tempCtx.drawImage(
|
||||
currentTarget._element,
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
finalImageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
|
||||
console.log(
|
||||
"✅ 从目标对象获取最终图像数据成功,尺寸:",
|
||||
@@ -1048,7 +1101,14 @@ async function applyLiquifyAtPoint(x, y) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("原始坐标:", x, y, "转换后图像坐标:", imageCoords.x, imageCoords.y);
|
||||
console.log(
|
||||
"原始坐标:",
|
||||
x,
|
||||
y,
|
||||
"转换后图像坐标:",
|
||||
imageCoords.x,
|
||||
imageCoords.y
|
||||
);
|
||||
|
||||
// 获取当前参数
|
||||
const params = {
|
||||
@@ -1113,7 +1173,8 @@ async function applyLiquifyAtPoint(x, y) {
|
||||
targetObject.value = updatedObject;
|
||||
// 如果对象有新的ID,也要更新ID
|
||||
if (updatedObject.id || updatedObject.objectId || updatedObject.uid) {
|
||||
targetObjectId.value = updatedObject.id || updatedObject.objectId || updatedObject.uid;
|
||||
targetObjectId.value =
|
||||
updatedObject.id || updatedObject.objectId || updatedObject.uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1127,7 +1188,8 @@ async function applyLiquifyAtPoint(x, y) {
|
||||
if (avgOperationTime.value === 0) {
|
||||
avgOperationTime.value = operationTime;
|
||||
} else {
|
||||
avgOperationTime.value = 0.7 * avgOperationTime.value + 0.3 * operationTime;
|
||||
avgOperationTime.value =
|
||||
0.7 * avgOperationTime.value + 0.3 * operationTime;
|
||||
}
|
||||
|
||||
// 将性能指标传递给状态管理器
|
||||
@@ -1267,7 +1329,9 @@ async function _replaceTargetWithNewImage(dataURL) {
|
||||
if (layer.type === "background" || layer.isBackground) {
|
||||
layer.fabricObject = img;
|
||||
} else if (layer.fabricObjects) {
|
||||
const objIndex = layer.fabricObjects.findIndex((obj) => obj.id === img.id);
|
||||
const objIndex = layer.fabricObjects.findIndex(
|
||||
(obj) => obj.id === img.id
|
||||
);
|
||||
if (objIndex !== -1) {
|
||||
layer.fabricObjects[objIndex] = img;
|
||||
}
|
||||
@@ -1304,7 +1368,10 @@ function _convertFabricCoordsToImageCoords(fabricX, fabricY) {
|
||||
const matrix = fabric.util.invertTransform(transform);
|
||||
|
||||
// 应用逆变换,将画布坐标转换为对象本地坐标
|
||||
const localPoint = fabric.util.transformPoint(new fabric.Point(fabricX, fabricY), matrix);
|
||||
const localPoint = fabric.util.transformPoint(
|
||||
new fabric.Point(fabricX, fabricY),
|
||||
matrix
|
||||
);
|
||||
|
||||
// 获取图像的原始尺寸(未缩放前)
|
||||
const imageWidth = originalImageData.value.width;
|
||||
@@ -1340,7 +1407,12 @@ function _convertFabricCoordsToImageCoords(fabricX, fabricY) {
|
||||
);
|
||||
|
||||
// 检查坐标是否在图像范围内
|
||||
if (imageX < 0 || imageX >= imageWidth || imageY < 0 || imageY >= imageHeight) {
|
||||
if (
|
||||
imageX < 0 ||
|
||||
imageX >= imageWidth ||
|
||||
imageY < 0 ||
|
||||
imageY >= imageHeight
|
||||
) {
|
||||
console.warn(
|
||||
`坐标超出图像范围: (${imageX}, ${imageY}), 图像尺寸: ${imageWidth}x${imageHeight}`
|
||||
);
|
||||
@@ -1539,9 +1611,7 @@ function stopPressTimer() {
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition:
|
||||
opacity 0.3s,
|
||||
transform 0.3s;
|
||||
transition: opacity 0.3s, transform 0.3s;
|
||||
}
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
|
||||
@@ -218,6 +218,7 @@ onMounted(async () => {
|
||||
isFixedErasable: props.isFixedErasable,
|
||||
});
|
||||
canvasManager.canvas.activeLayerId = activeLayerId;
|
||||
canvasManager.activeLayerId = activeLayerId;
|
||||
canvasManager.canvas.activeElementId = activeElementId;
|
||||
|
||||
// 创建命令管理器
|
||||
@@ -1207,8 +1208,8 @@ defineExpose({
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
padding: .5rem 1rem;
|
||||
border-radius: .4rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.4rem;
|
||||
font-size: 1.4rem;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
color: #666;
|
||||
@@ -1220,8 +1221,8 @@ defineExpose({
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
padding: .5rem 1rem;
|
||||
border-radius: .4rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.4rem;
|
||||
font-size: 1.2rem;
|
||||
color: #666;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
@@ -1230,11 +1231,11 @@ defineExpose({
|
||||
.reset-zoom {
|
||||
margin-left: 1rem;
|
||||
cursor: pointer;
|
||||
padding: .2rem .5rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
font-size: 1.2rem;
|
||||
border: 1px solid #ddd;
|
||||
background: #f8f8f8;
|
||||
border-radius: .3rem;
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
@@ -1247,7 +1248,7 @@ defineExpose({
|
||||
|
||||
.share-btn,
|
||||
.export-btn {
|
||||
padding: .8rem 2rem;
|
||||
padding: 0.8rem 2rem;
|
||||
border: none;
|
||||
border-radius: 2rem;
|
||||
background-color: #000;
|
||||
@@ -1310,7 +1311,7 @@ button:hover {
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
background-color: #fff;
|
||||
border-radius: .8rem;
|
||||
border-radius: 0.8rem;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
@@ -1337,11 +1338,11 @@ button:hover {
|
||||
right: 1rem;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 1rem;
|
||||
border-radius: .4rem;
|
||||
border-radius: 0.4rem;
|
||||
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .8rem;
|
||||
gap: 0.8rem;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
@@ -1353,7 +1354,7 @@ button:hover {
|
||||
background: #fff;
|
||||
width: 35rem;
|
||||
max-height: 85vh;
|
||||
box-shadow: 0 .4rem 2rem rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
|
||||
box-shadow: 0 0.4rem 2rem rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
|
||||
backdrop-filter: blur(2px); /* 添加模糊效果 */
|
||||
-webkit-backdrop-filter: blur(2px);
|
||||
background-color: rgba(255, 255, 255, 0.95); /* 改为白色背景 */
|
||||
@@ -1363,8 +1364,8 @@ button:hover {
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.9rem;
|
||||
right: .6rem;
|
||||
top: -0.9rem;
|
||||
right: 0.6rem;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 1rem solid transparent;
|
||||
@@ -1388,7 +1389,7 @@ button:hover {
|
||||
|
||||
.layer-item,
|
||||
.element-item {
|
||||
padding: 1.2rem .8rem;
|
||||
padding: 1.2rem 0.8rem;
|
||||
}
|
||||
|
||||
.element-action-btn,
|
||||
|
||||
@@ -903,7 +903,10 @@ export class LayerManager {
|
||||
* @returns {Object|null} 图层对象或null
|
||||
*/
|
||||
getLayerById(layerId) {
|
||||
const { layer } = findLayerRecursively(this.layers.value, layerId);
|
||||
const { layer } = findLayerRecursively(
|
||||
this.layers?.value ?? this.layers,
|
||||
layerId
|
||||
);
|
||||
return layer;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { BrushManager } from "./brushes/brushManager";
|
||||
import { BrushIndicator } from "./BrushIndicator";
|
||||
import { ToolCommand } from "../commands/ToolCommands";
|
||||
import { CreateTextCommand } from "../commands/TextCommands";
|
||||
import { OperationType } from "../utils/layerHelper";
|
||||
import { findLayerRecursively, OperationType } from "../utils/layerHelper";
|
||||
import CanvasConfig from "../config/canvasConfig";
|
||||
import { fabric } from "fabric-with-all";
|
||||
import { InitLiquifyToolCommand } from "../commands/LiquifyCommands";
|
||||
@@ -349,6 +349,11 @@ export class ToolManager {
|
||||
// 保存先前的工具
|
||||
this.previousTool = this.activeTool.value;
|
||||
|
||||
// 取消画布的选中状态
|
||||
this.canvas?.discardActiveObject();
|
||||
this.canvasManager?.layerManager?.updateLayersObjectsInteractivity?.();
|
||||
this.canvas?.renderAll();
|
||||
|
||||
// 如果切换到非画笔工具,禁用笔刷指示器
|
||||
if (!this._shouldShowBrushIndicator(toolId)) {
|
||||
this._disableBrushIndicator();
|
||||
@@ -665,7 +670,11 @@ export class ToolManager {
|
||||
panelDetail.layerStatus = checkResult;
|
||||
|
||||
// 获取图层对象
|
||||
const layer = this.layerManager.getLayerById(activeLayerId);
|
||||
// const layer = this.layerManager.getLayerById(activeLayerId);
|
||||
const { layer } = findLayerRecursively(
|
||||
this.layerManager.layers?.value ?? this.layerManager.layers,
|
||||
activeLayerId
|
||||
);
|
||||
|
||||
// 检查图层是否为空
|
||||
if (!checkResult.isEmpty) {
|
||||
@@ -844,7 +853,12 @@ export class ToolManager {
|
||||
*/
|
||||
async _startLiquify(layerId) {
|
||||
// 获取图层信息
|
||||
const layer = this.layerManager.getLayerById(layerId);
|
||||
|
||||
// const layer = this.layerManager.getLayerById(layerId);
|
||||
const { layer } = findLayerRecursively(
|
||||
this.layerManager.layers?.value ?? this.layerManager.layers,
|
||||
layerId
|
||||
);
|
||||
if (!layer) {
|
||||
Modal.error({
|
||||
title: "图层错误",
|
||||
@@ -1122,7 +1136,11 @@ export class ToolManager {
|
||||
target.type === "textbox")
|
||||
) {
|
||||
// 获取对应的图层
|
||||
const layer = this.layerManager.getLayerById(target.layerId);
|
||||
// const layer = this.layerManager.getLayerById(target.layerId);
|
||||
const { layer } = findLayerRecursively(
|
||||
this.layerManager.layers?.value ?? this.layerManager.layers,
|
||||
target.layerId
|
||||
);
|
||||
if (layer) {
|
||||
// 显示文本编辑面板
|
||||
this.showTextEditor(target, layer);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { LiquifyWebGLManager } from "./LiquifyWebGLManager";
|
||||
import { LiquifyCPUManager } from "./LiquifyCPUManager";
|
||||
import { findInChildLayers, LayerType } from "../../utils/layerHelper";
|
||||
import { findLayerRecursively, LayerType } from "../../utils/layerHelper";
|
||||
|
||||
export class EnhancedLiquifyManager {
|
||||
/**
|
||||
@@ -140,7 +140,10 @@ export class EnhancedLiquifyManager {
|
||||
// 处理传入的是图层ID的情况
|
||||
if (typeof target === "string") {
|
||||
targetLayerId = target;
|
||||
const layer = this.layerManager.getLayerById(targetLayerId);
|
||||
const { layer } = findLayerRecursively(
|
||||
this.layerManager.layers?.value ?? this.layerManager.layers,
|
||||
targetLayerId
|
||||
);
|
||||
|
||||
// 检查图层是否存在和是否有对象
|
||||
let hasObjects = false;
|
||||
@@ -160,7 +163,7 @@ export class EnhancedLiquifyManager {
|
||||
} else if (typeof target === "object") {
|
||||
// 传入的是对象
|
||||
targetObject = target;
|
||||
const { layer } = findInChildLayers(
|
||||
const { layer } = findLayerRecursively(
|
||||
this.layerManager.layers?.value ?? this.layerManager.layers,
|
||||
targetObject.layerId
|
||||
);
|
||||
@@ -216,7 +219,9 @@ export class EnhancedLiquifyManager {
|
||||
// 计算图像大小
|
||||
const pixelCount = imageData.width * imageData.height;
|
||||
|
||||
console.log(`液化选择渲染器: 图像大小=${pixelCount}像素, WebGL可用=${this.isWebGLAvailable}`);
|
||||
console.log(
|
||||
`液化选择渲染器: 图像大小=${pixelCount}像素, WebGL可用=${this.isWebGLAvailable}`
|
||||
);
|
||||
|
||||
// 默认使用CPU渲染器
|
||||
this.activeRenderer = this.cpuRenderer;
|
||||
@@ -247,7 +252,11 @@ export class EnhancedLiquifyManager {
|
||||
this.activeRenderer = this.webglRenderer;
|
||||
this.renderMode = "webgl";
|
||||
} else {
|
||||
console.log(`液化功能: 使用CPU渲染模式${!this.isWebGLAvailable ? " (WebGL不可用)" : ""}`);
|
||||
console.log(
|
||||
`液化功能: 使用CPU渲染模式${
|
||||
!this.isWebGLAvailable ? " (WebGL不可用)" : ""
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,11 +321,16 @@ export class EnhancedLiquifyManager {
|
||||
this.params[param] = value;
|
||||
|
||||
// 同步更新当前渲染器 - 关键修复:确保参数正确传递
|
||||
if (this.activeRenderer && typeof this.activeRenderer.setParam === "function") {
|
||||
if (
|
||||
this.activeRenderer &&
|
||||
typeof this.activeRenderer.setParam === "function"
|
||||
) {
|
||||
console.log(`EnhancedLiquifyManager 设置参数: ${param}=${value}`);
|
||||
this.activeRenderer.setParam(param, value);
|
||||
} else {
|
||||
console.warn(`EnhancedLiquifyManager: 无法设置参数 ${param},渲染器未就绪`);
|
||||
console.warn(
|
||||
`EnhancedLiquifyManager: 无法设置参数 ${param},渲染器未就绪`
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -371,17 +385,25 @@ export class EnhancedLiquifyManager {
|
||||
* @param {Number} y 初始Y坐标
|
||||
*/
|
||||
startLiquifyOperation(x, y) {
|
||||
if (this.activeRenderer && typeof this.activeRenderer.startDeformation === "function") {
|
||||
if (
|
||||
this.activeRenderer &&
|
||||
typeof this.activeRenderer.startDeformation === "function"
|
||||
) {
|
||||
this.activeRenderer.startDeformation(x, y);
|
||||
}
|
||||
console.log(`开始液化操作,渲染模式=${this.renderMode}, 初始点: (${x}, ${y})`);
|
||||
console.log(
|
||||
`开始液化操作,渲染模式=${this.renderMode}, 初始点: (${x}, ${y})`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束液化操作
|
||||
*/
|
||||
endLiquifyOperation() {
|
||||
if (this.activeRenderer && typeof this.activeRenderer.endDeformation === "function") {
|
||||
if (
|
||||
this.activeRenderer &&
|
||||
typeof this.activeRenderer.endDeformation === "function"
|
||||
) {
|
||||
this.activeRenderer.endDeformation();
|
||||
}
|
||||
console.log(`结束液化操作,渲染模式=${this.renderMode}`);
|
||||
@@ -424,7 +446,9 @@ export class EnhancedLiquifyManager {
|
||||
|
||||
// 坐标边界检查
|
||||
if (x < 0 || x >= imageWidth || y < 0 || y >= imageHeight) {
|
||||
console.warn(`液化坐标超出图像范围: (${x}, ${y}), 图像尺寸: ${imageWidth}x${imageHeight}`);
|
||||
console.warn(
|
||||
`液化坐标超出图像范围: (${x}, ${y}), 图像尺寸: ${imageWidth}x${imageHeight}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -489,7 +513,9 @@ export class EnhancedLiquifyManager {
|
||||
console.log(
|
||||
`液化性能数据: 模式=${this.renderMode}, 平均耗时=${avgTime.toFixed(
|
||||
2
|
||||
)}ms, 图像尺寸=${this.originalImageData?.width}x${this.originalImageData?.height}`
|
||||
)}ms, 图像尺寸=${this.originalImageData?.width}x${
|
||||
this.originalImageData?.height
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -542,7 +568,11 @@ export class EnhancedLiquifyManager {
|
||||
}
|
||||
|
||||
// 获取图层
|
||||
const layer = this.layerManager.getLayerById(layerId);
|
||||
// const layer = this.layerManager.getLayerById(layerId);
|
||||
const { layer } = findLayerRecursively(
|
||||
this.layerManager.layers?.value ?? this.layerManager.layers,
|
||||
layerId
|
||||
);
|
||||
if (!layer) {
|
||||
return {
|
||||
valid: false,
|
||||
@@ -581,7 +611,8 @@ export class EnhancedLiquifyManager {
|
||||
const singleObject = objectsToCheck.length === 1;
|
||||
const isImage =
|
||||
singleObject &&
|
||||
(objectsToCheck[0].type === "image" || objectsToCheck[0].type === "rasterized-layer");
|
||||
(objectsToCheck[0].type === "image" ||
|
||||
objectsToCheck[0].type === "rasterized-layer");
|
||||
|
||||
// 检查是否为组
|
||||
const isGroup =
|
||||
@@ -631,14 +662,19 @@ export class EnhancedLiquifyManager {
|
||||
tempCanvas.height = fabricObject.height;
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
|
||||
console.log(`创建临时Canvas,尺寸: ${tempCanvas.width}x${tempCanvas.height}`);
|
||||
console.log(
|
||||
`创建临时Canvas,尺寸: ${tempCanvas.width}x${tempCanvas.height}`
|
||||
);
|
||||
|
||||
// 处理不同的图像源
|
||||
if (fabricObject._element) {
|
||||
console.log("使用 _element 绘制图像");
|
||||
|
||||
// 检查_element是否有效
|
||||
if (!fabricObject._element.complete && fabricObject._element.tagName === "IMG") {
|
||||
if (
|
||||
!fabricObject._element.complete &&
|
||||
fabricObject._element.tagName === "IMG"
|
||||
) {
|
||||
console.log("图像未加载完成,等待加载...");
|
||||
fabricObject._element.onload = () => {
|
||||
try {
|
||||
@@ -649,7 +685,12 @@ export class EnhancedLiquifyManager {
|
||||
fabricObject.width,
|
||||
fabricObject.height
|
||||
);
|
||||
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
const imageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
console.log("✅ 图像加载完成后获取数据成功");
|
||||
resolve(imageData);
|
||||
} catch (error) {
|
||||
@@ -664,8 +705,17 @@ export class EnhancedLiquifyManager {
|
||||
}
|
||||
|
||||
// 直接绘制已加载的图像
|
||||
tempCtx.drawImage(fabricObject._element, 0, 0, fabricObject.width, fabricObject.height);
|
||||
} else if (fabricObject.getSrc && typeof fabricObject.getSrc === "function") {
|
||||
tempCtx.drawImage(
|
||||
fabricObject._element,
|
||||
0,
|
||||
0,
|
||||
fabricObject.width,
|
||||
fabricObject.height
|
||||
);
|
||||
} else if (
|
||||
fabricObject.getSrc &&
|
||||
typeof fabricObject.getSrc === "function"
|
||||
) {
|
||||
console.log("使用 getSrc() 方法获取图像源");
|
||||
|
||||
// 通过URL创建图像
|
||||
@@ -674,11 +724,24 @@ export class EnhancedLiquifyManager {
|
||||
|
||||
img.onload = () => {
|
||||
try {
|
||||
console.log(`图像加载成功,原始尺寸: ${img.naturalWidth}x${img.naturalHeight}`);
|
||||
console.log(
|
||||
`图像加载成功,原始尺寸: ${img.naturalWidth}x${img.naturalHeight}`
|
||||
);
|
||||
|
||||
tempCtx.drawImage(img, 0, 0, fabricObject.width, fabricObject.height);
|
||||
tempCtx.drawImage(
|
||||
img,
|
||||
0,
|
||||
0,
|
||||
fabricObject.width,
|
||||
fabricObject.height
|
||||
);
|
||||
|
||||
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
const imageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
|
||||
console.log("✅ 通过URL获取图像数据成功");
|
||||
resolve(imageData);
|
||||
@@ -706,9 +769,20 @@ export class EnhancedLiquifyManager {
|
||||
|
||||
img.onload = () => {
|
||||
try {
|
||||
tempCtx.drawImage(img, 0, 0, fabricObject.width, fabricObject.height);
|
||||
tempCtx.drawImage(
|
||||
img,
|
||||
0,
|
||||
0,
|
||||
fabricObject.width,
|
||||
fabricObject.height
|
||||
);
|
||||
|
||||
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
const imageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
|
||||
console.log("✅ 通过src属性获取图像数据成功");
|
||||
resolve(imageData);
|
||||
@@ -728,13 +802,20 @@ export class EnhancedLiquifyManager {
|
||||
return;
|
||||
} else {
|
||||
console.error("无法找到有效的图像源");
|
||||
reject(new Error("图像对象缺少有效的图像源(_element, getSrc, 或 src)"));
|
||||
reject(
|
||||
new Error("图像对象缺少有效的图像源(_element, getSrc, 或 src)")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果走到这里,说明使用了_element直接绘制
|
||||
try {
|
||||
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
const imageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
|
||||
console.log(
|
||||
`✅ 获取图像数据成功: 对象尺寸=${fabricObject.width}x${fabricObject.height}, ` +
|
||||
|
||||
@@ -95,7 +95,8 @@ export const BlendMode = {
|
||||
export function isGroupLayer(layer) {
|
||||
if (!layer) return false;
|
||||
return (
|
||||
layer.type === LayerType.GROUP || (Array.isArray(layer.children) && layer.children.length > 0)
|
||||
layer.type === LayerType.GROUP ||
|
||||
(Array.isArray(layer.children) && layer.children.length > 0)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -106,7 +107,11 @@ export function isGroupLayer(layer) {
|
||||
* @param {Object} options 其他选项
|
||||
* @returns {Object} 创建的图层对象
|
||||
*/
|
||||
export function createLayerFromFabricObject(fabricObject, layerType = "bitmap", options = {}) {
|
||||
export function createLayerFromFabricObject(
|
||||
fabricObject,
|
||||
layerType = "bitmap",
|
||||
options = {}
|
||||
) {
|
||||
if (!fabricObject) return null;
|
||||
|
||||
// 确定图层类型
|
||||
@@ -132,7 +137,9 @@ export function createLayerFromFabricObject(fabricObject, layerType = "bitmap",
|
||||
type: type,
|
||||
name:
|
||||
options.name ||
|
||||
`${fabricObject.type.charAt(0).toUpperCase() + fabricObject.type.slice(1)} 图层`,
|
||||
`${
|
||||
fabricObject.type.charAt(0).toUpperCase() + fabricObject.type.slice(1)
|
||||
} 图层`,
|
||||
parentId: options.parentId || null,
|
||||
});
|
||||
|
||||
@@ -159,7 +166,9 @@ export function createLayerFromFabricObject(fabricObject, layerType = "bitmap",
|
||||
*/
|
||||
export function createLayer(options = {}) {
|
||||
const id =
|
||||
options.id || generateId("layer_") || `layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
options.id ||
|
||||
generateId("layer_") ||
|
||||
`layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
return {
|
||||
id: id,
|
||||
// 图层基本属性
|
||||
@@ -199,7 +208,8 @@ export function createLayer(options = {}) {
|
||||
* @returns {Object} 背景图层对象
|
||||
*/
|
||||
export function createBackgroundLayer(options = {}) {
|
||||
const id = options.id || `bg_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
const id =
|
||||
options.id || `bg_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
return {
|
||||
id: id,
|
||||
// 图层基本属性
|
||||
@@ -390,7 +400,9 @@ export function createSmartObjectLayer(options = {}) {
|
||||
* @returns {Object} 固定图层对象
|
||||
*/
|
||||
export function createFixedLayer(options = {}) {
|
||||
const id = options.id || `fixed_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
const id =
|
||||
options.id ||
|
||||
`fixed_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
||||
return {
|
||||
id: id,
|
||||
// 图层基本属性
|
||||
@@ -433,7 +445,9 @@ export function cloneLayer(layer) {
|
||||
// 复制 fabric 对象 (如果存在)
|
||||
if (Array.isArray(layer.fabricObjects)) {
|
||||
clonedLayer.fabricObjects = layer.fabricObjects.map((obj) => {
|
||||
return obj && typeof obj.clone === "function" ? obj.clone() : JSON.parse(JSON.stringify(obj));
|
||||
return obj && typeof obj.clone === "function"
|
||||
? obj.clone()
|
||||
: JSON.parse(JSON.stringify(obj));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user