feat: 裁剪组裁剪跟随选择组移动

This commit is contained in:
bighuixiang
2025-07-14 01:00:23 +08:00
parent 96e13cb22a
commit 24e9ba8ae5
80 changed files with 2052 additions and 4292 deletions

View File

@@ -374,10 +374,7 @@ onMounted(() => {
});
// 创建状态管理器
stateManager.value = new LiquifyStateManager(
props.canvas,
realtimeUpdater.value
);
stateManager.value = new LiquifyStateManager(props.canvas, realtimeUpdater.value);
}
// 监听画布事件
@@ -446,12 +443,7 @@ function showPanel(event) {
return;
}
console.log(
"显示液化面板,目标对象:",
targetObj.type,
"图层ID:",
targetLayerIdValue
);
console.log("显示液化面板,目标对象:", targetObj.type, "图层ID:", targetLayerIdValue);
// 更新面板状态,但保持当前模式不变
// 只有在首次显示面板或面板已关闭时才重置模式
@@ -521,8 +513,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;
@@ -553,8 +545,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;
@@ -613,11 +605,7 @@ 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;
@@ -685,9 +673,7 @@ 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}`);
}
@@ -770,19 +756,9 @@ 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);
@@ -861,9 +837,7 @@ 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})`);
}
}
@@ -959,27 +933,15 @@ 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(
"✅ 从实时更新器获取最终图像数据成功,尺寸:",
@@ -1000,19 +962,8 @@ 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(
"✅ 从目标对象获取最终图像数据成功,尺寸:",
@@ -1097,14 +1048,7 @@ async function applyLiquifyAtPoint(x, y) {
return;
}
console.log(
"原始坐标:",
x,
y,
"转换后图像坐标:",
imageCoords.x,
imageCoords.y
);
console.log("原始坐标:", x, y, "转换后图像坐标:", imageCoords.x, imageCoords.y);
// 获取当前参数
const params = {
@@ -1169,8 +1113,7 @@ 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;
}
}
}
@@ -1184,8 +1127,7 @@ 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;
}
// 将性能指标传递给状态管理器
@@ -1265,7 +1207,7 @@ async function _updateImageOnCanvas(imageData) {
}
} else {
// 拖拽结束后进行完整的对象替换
await _replaceTargetObjectWithNewImage(dataURL);
// await _replaceTargetObjectWithNewImage(dataURL);
}
} catch (error) {
console.error("更新画布图像时出错:", error);
@@ -1325,9 +1267,7 @@ 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;
}
@@ -1364,10 +1304,7 @@ 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;
@@ -1403,12 +1340,7 @@ 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}`
);
@@ -1607,7 +1539,9 @@ 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 {