From 8442412a3413490b7cafba73194e6277d6ff0ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BF=97=E9=B9=8F?= <2916022834@qq.com> Date: Mon, 10 Nov 2025 16:19:05 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E7=94=BB=E5=B8=83=E9=80=89=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E6=93=8D=E4=BD=9C=E9=9D=A2=E6=9D=BF=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/SelectMenuPanel.vue | 115 +++++++++++------- src/views/HomeView/history.vue | 2 +- 2 files changed, 72 insertions(+), 45 deletions(-) diff --git a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue index e5396c59..1a6a76cf 100644 --- a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue +++ b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue @@ -22,7 +22,7 @@ v-for="v in activeObjects" :key="v.id" > -
图层1
+
{{ v.layer?.name }}
W @@ -53,7 +53,7 @@
@@ -158,6 +158,9 @@ const getActiveObject = (e) => { console.log("==========切换激活对象", e); activeObjects.value = e.selected.map((v) => v); + activeObjects.value.forEach((v) => { + v.layer = props.layerManager.getLayerById(v.layerId); + }); if (activeObjects.value.length === 0) { close(); } else { @@ -166,46 +169,11 @@ }; const lastSelectLayerId = inject("lastSelectLayerId"); const layers = inject("layers"); - const changeAngle = (activeObj) => { - // console.log("=====================", e.target.value); - // const finalState = TransformCommand.captureTransformState(activeObj); - // const { xPrime, yPrime } = compute( - // activeObj.left, - // activeObj.top, - // activeObj.width, - // activeObj.height, - // activeObj.angle - // ); - // finalState.left = xPrime; - // finalState.top = yPrime; - // const transformCmd = new TransformCommand({ - // canvas: props.canvas, - // objectId: activeObj.id, - // initialState: null, - // finalState, - // objectType: activeObj.type, - // name: `变换 ${activeObj.type || "对象"}`, - // layerManager: props.layerManager, - // layers: layers, - // lastSelectLayerId: lastSelectLayerId, - // }); - // props.layerManager.commandManager.execute(transformCmd, { - // name: "对象修改", - // }); - }; - - const flipObject = (activeObj, type) => { - const initialState = TransformCommand.captureTransformState(activeObj); - const finalState = { ...initialState }; - if (type === "h") { - finalState.flipX = !finalState.flipX; - } else if (type === "v") { - finalState.flipY = !finalState.flipY; - } + const transformObject = (activeObj, initialState, finalState) => { const transformCmd = new TransformCommand({ canvas: props.canvas, objectId: activeObj.id, - initialState: initialState, + initialState, finalState, objectType: activeObj.type, name: `变换 ${activeObj.type || "对象"}`, @@ -217,13 +185,72 @@ name: "对象修改", }); }; - const clickflipHorizontal = (obj) => { - console.log("水平翻转"); - flipObject(obj, "h"); + + /** + * 根据左上角坐标计算旋转后的新坐标 + * @param {number} W - 宽度 + * @param {number} H - 高度 + * @param {number} currentX - 当前左上角x坐标 + * @param {number} currentY - 当前左上角y坐标 + * @param {number} currentAngleDeg - 当前角度(度) + * @param {number} newAngleDeg - 新角度(度) + * @returns {Object} 旋转后的左上角坐标 {x, y} + */ + function calculateRotatedTopLeftDeg( + W, + H, + currentX, + currentY, + currentAngleDeg, + newAngleDeg + ) { + const currentAngle = (currentAngleDeg * Math.PI) / 180; + const newAngle = (newAngleDeg * Math.PI) / 180; + // 1. 用当前角度计算中心点位置 + const cosCurrent = Math.cos(currentAngle); + const sinCurrent = Math.sin(currentAngle); + const Cx = currentX + (W / 2) * cosCurrent - (H / 2) * sinCurrent; + const Cy = currentY + (W / 2) * sinCurrent + (H / 2) * cosCurrent; + + // 2. 用新角度计算旋转后的左上角位置 + const cosNew = Math.cos(newAngle); + const sinNew = Math.sin(newAngle); + const newX = Cx + (-W / 2) * cosNew - (-H / 2) * sinNew; + const newY = Cy + (-W / 2) * sinNew + (-H / 2) * cosNew; + + return { x: newX, y: newY }; + } + // 改变角度 + const changeAngle = (e, obj) => { + const initialState = TransformCommand.captureTransformState(obj); + const finalState = { ...initialState }; + const angle = e.target.value; + const { x, y } = calculateRotatedTopLeftDeg( + obj.width, + obj.height, + obj.left, + obj.top, + obj.angle, + angle + ); + finalState.left = x; + finalState.top = y; + finalState.angle = angle; + transformObject(obj, initialState, finalState); }; + // 水平翻转 + const clickflipHorizontal = (obj) => { + const initialState = TransformCommand.captureTransformState(obj); + const finalState = { ...initialState }; + finalState.flipX = !finalState.flipX; + transformObject(obj, initialState, finalState); + }; + // 垂直翻转 const clickflipVertical = (obj) => { - console.log("垂直翻转"); - flipObject(obj, "v"); + const initialState = TransformCommand.captureTransformState(obj); + const finalState = { ...initialState }; + finalState.flipY = !finalState.flipY; + transformObject(obj, initialState, finalState); }; const updateActiveObjects = (arrs, keys) => { diff --git a/src/views/HomeView/history.vue b/src/views/HomeView/history.vue index 4b30f338..38a4b3f5 100644 --- a/src/views/HomeView/history.vue +++ b/src/views/HomeView/history.vue @@ -771,7 +771,7 @@ export default defineComponent({ padding: 0 1rem; .operate_item { - font-size: 1.4rem; + // font-size: 1.4rem; font-family: Roboto; font-weight: 400; color: #007ee5; From 804040d9fd6f9034ea49d57788af193b5066e412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BF=97=E9=B9=8F?= <2916022834@qq.com> Date: Mon, 10 Nov 2025 16:59:28 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9B=BE=E5=B1=82?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E6=BF=80=E6=B4=BB=E5=AF=B9=E8=B1=A1=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Canvas/CanvasEditor/components/SelectMenuPanel.vue | 5 +++-- src/component/Canvas/CanvasEditor/managers/LayerManager.js | 4 ++++ src/lang/cn.ts | 2 ++ src/lang/en.ts | 2 ++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue index 1a6a76cf..c83ce2fc 100644 --- a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue +++ b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue @@ -58,11 +58,11 @@
-

水平翻转

+

{{ t('Canvas.flipHorizontal') }}

-

垂直翻转

+

{{ t('Canvas.flipVertical') }}

@@ -271,6 +271,7 @@ } else { arrs.push(e.target); } + console.log(e.target); updateActiveObjects(arrs, ["angle"]); }; diff --git a/src/component/Canvas/CanvasEditor/managers/LayerManager.js b/src/component/Canvas/CanvasEditor/managers/LayerManager.js index c2fe3941..e70a6b70 100644 --- a/src/component/Canvas/CanvasEditor/managers/LayerManager.js +++ b/src/component/Canvas/CanvasEditor/managers/LayerManager.js @@ -1219,6 +1219,10 @@ export class LayerManager { } // 切换到选择模式 this?.toolManager?.setTool(OperationType.SELECT); + if(objects.length === 1) { + this.canvas.setActiveObject(objects[0]); + return objects[0]; + } // 创建一个新的活动选择组 const activeSelection = new fabric.ActiveSelection(objects, { canvas: this.canvas, diff --git a/src/lang/cn.ts b/src/lang/cn.ts index 8cc1cddc..71224767 100644 --- a/src/lang/cn.ts +++ b/src/lang/cn.ts @@ -1217,6 +1217,8 @@ export default { Rough: '粗糙', Smooth: '平滑', basic: '基础', + flipHorizontal: '水平翻转', + flipVertical: '垂直翻转', //长毛笔 FurSettings: '长毛笔设置', FurLength: '毛发长度', diff --git a/src/lang/en.ts b/src/lang/en.ts index 013326c6..054b3b13 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -1252,6 +1252,8 @@ export default { Rough: 'Rough', Smooth: 'Smooth', basic: 'Basic', + flipHorizontal: 'Horizontal Flip', + flipVertical: 'Vertical Flip', //长毛笔 FurSettings: 'FurSettings', FurLength: 'Fur Length', From 4365b810dbf8810fb48dbd90f0c1d28490a5c2d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BF=97=E9=B9=8F?= <2916022834@qq.com> Date: Mon, 10 Nov 2025 17:07:05 +0800 Subject: [PATCH 3/4] fix --- .../Canvas/CanvasEditor/components/SelectMenuPanel.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue index c83ce2fc..917d0816 100644 --- a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue +++ b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue @@ -226,8 +226,8 @@ const finalState = { ...initialState }; const angle = e.target.value; const { x, y } = calculateRotatedTopLeftDeg( - obj.width, - obj.height, + obj.width * obj.scaleX, + obj.height * obj.scaleY, obj.left, obj.top, obj.angle, From 5f3c4b5ac9a0bce96c7a94106e89c87879b9f334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BF=97=E9=B9=8F?= <2916022834@qq.com> Date: Tue, 11 Nov 2025 10:13:59 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E7=94=BB=E5=B8=83=E5=8F=8C=E5=87=BB?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=86=85=E9=83=A8=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CanvasEditor/commands/LayerCommands.js | 2 +- .../components/SelectMenuPanel.vue | 42 ++++++++++++------- .../Canvas/ExistsImageList/index.vue | 11 +++-- src/component/common/SelectImages.vue | 15 +++++-- 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/component/Canvas/CanvasEditor/commands/LayerCommands.js b/src/component/Canvas/CanvasEditor/commands/LayerCommands.js index 66880184..0380638e 100644 --- a/src/component/Canvas/CanvasEditor/commands/LayerCommands.js +++ b/src/component/Canvas/CanvasEditor/commands/LayerCommands.js @@ -2595,7 +2595,7 @@ export class CreateImageLayerCommand extends Command { // 生成图层名称 const fileName = - this.layerName || `图片 ${new Date().toLocaleTimeString()}`; + this.layerName || `${new Date().toLocaleString()}`; this.fabricImage.set({ id: this.imageId, diff --git a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue index 917d0816..d02015c8 100644 --- a/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue +++ b/src/component/Canvas/CanvasEditor/components/SelectMenuPanel.vue @@ -58,11 +58,15 @@
-

{{ t('Canvas.flipHorizontal') }}

+

+ {{ t("Canvas.flipHorizontal") }} +

-

{{ t('Canvas.flipVertical') }}

+

+ {{ t("Canvas.flipVertical") }} +

@@ -225,16 +229,22 @@ const initialState = TransformCommand.captureTransformState(obj); const finalState = { ...initialState }; const angle = e.target.value; - const { x, y } = calculateRotatedTopLeftDeg( - obj.width * obj.scaleX, - obj.height * obj.scaleY, - obj.left, - obj.top, - obj.angle, - angle - ); - finalState.left = x; - finalState.top = y; + if (obj.originX === "left" && obj.originY === "top") { + const width = obj.width * obj.scaleX; + const height = obj.height * obj.scaleY; + const left = obj.left; + const top = obj.top; + const { x, y } = calculateRotatedTopLeftDeg( + width, + height, + left, + top, + obj.angle, + angle + ); + finalState.left = x; + finalState.top = y; + } finalState.angle = angle; transformObject(obj, initialState, finalState); }; @@ -257,7 +267,12 @@ arrs.forEach((v) => { activeObjects.value.forEach((item) => { if (item.id === v.id) { - keys.forEach((key) => (item[key] = v[key])); + keys.forEach((k) => { + item[k] = + typeof v[k] === "number" + ? Number(v[k].toFixed(3)) + : v[k]; + }); } }); activeObjects.value = [...activeObjects.value]; @@ -271,7 +286,6 @@ } else { arrs.push(e.target); } - console.log(e.target); updateActiveObjects(arrs, ["angle"]); }; diff --git a/src/component/Canvas/ExistsImageList/index.vue b/src/component/Canvas/ExistsImageList/index.vue index d1aaab6c..2f18de34 100644 --- a/src/component/Canvas/ExistsImageList/index.vue +++ b/src/component/Canvas/ExistsImageList/index.vue @@ -44,16 +44,17 @@ :key="index" class="image-item" @click="handleImageClick(item)" + @dblclick="handleImageDoubleClick(item)" >
- {{ item.name || "未命名" }} + {{ item.name }}
-

加载中...

@@ -279,6 +279,14 @@ const handleImageClick = item => { } } +// 处理图片双击 +const handleImageDoubleClick = item => { + selectList.value = [item.url] + confirm() +} + + + // 处理分类切换 const handleChangeCategory = category => { // console.log('handleChangeCategory',category) @@ -307,6 +315,7 @@ const confirm = () => { emitData = selectList.value } emits('select', emitData) + selectList.value = [] showPanel.value = false }