Procházet zdrojové kódy

feat(pictureEditor): 限制文本框仅支持左右缩放

- 为 Textbox 添加缩放事件监听,将 scaleX 映射为 width 变更
- 禁止 Textbox 纵向缩放,保持字体高度不变
- 锁定 Textbox 旋转功能
- 仅显示左右控制点,隐藏角点和旋转控件
- 在选中、创建选择和更新选择时应用文本框控制规则
- 添加错误处理避免影响其他交互功能
panqiuyao před 12 hodinami
rodič
revize
23e45e6004

+ 67 - 0
frontend/src/views/components/PictureEditor/mixin/actions/index.js

@@ -158,6 +158,73 @@ export default  {
       // 添加键盘事件监听,用于移动选中的对象
       this.initKeyboardNavigation()
 
+      // 对 Textbox 限制为仅左右缩放(垂直不缩放),并把缩放的 scaleX 映射为 width 变更
+      this.fcanvas.on('object:scaling', (opt) => {
+        try {
+          const target = opt.target
+          if (!target) return
+          // 只处理 Textbox(多行文本)
+          if (target.type === 'textbox' || target instanceof fabric.Textbox) {
+            const sx = target.scaleX || 1
+            const sy = target.scaleY || 1
+            const needUpdate = Math.abs(sx - 1) > 1e-6 || Math.abs(sy - 1) > 1e-6
+            if (!needUpdate) return
+
+            // 横向缩放:把 scaleX 应用到 width 上
+            if (Math.abs(sx - 1) > 1e-6) {
+              const newWidth = Math.max(10, target.width * sx)
+              target.scaleX = 1
+              target.set({ width: newWidth })
+            }
+
+            // 纵向缩放:禁止生效,直接复位 scaleY,不改变字体或高度
+            if (Math.abs(sy - 1) > 1e-6) {
+              target.scaleY = 1
+            }
+
+            target.setCoords()
+            // 触发渲染(必要时)
+            if (this.fcanvas && this.fcanvas.requestRenderAll) this.fcanvas.requestRenderAll()
+          }
+        } catch (e) {
+          // 忽略处理错误,避免影响其他交互
+          console.warn('[marketingEdit] object:scaling handler error', e)
+        }
+      })
+
+      // 当选中对象时,为 Textbox 应用仅左右缩放的控件展示与锁定
+      const applyTextboxControls = (obj) => {
+        try {
+          if (!obj) return
+          if (obj.type === 'textbox' || obj instanceof fabric.Textbox) {
+            obj.lockScalingY = true
+            obj.lockRotation = true
+            // 只保留左右中控点(ml/mr),隐藏角点与旋转
+            obj.setControlsVisibility({
+              tl: false, tr: false, bl: false, br: false,
+              mt: false, mb: false,
+              ml: true, mr: true, mtr: false
+            })
+            obj.setCoords()
+          }
+        } catch (e) {
+          console.warn('[marketingEdit] applyTextboxControls error', e)
+        }
+      }
+
+      this.fcanvas.on('object:selected', (e) => {
+        const obj = e.target
+        applyTextboxControls(obj)
+      })
+      this.fcanvas.on('selection:created', (e) => {
+        const items = e.selected || []
+        items.forEach(it => applyTextboxControls(it))
+      })
+      this.fcanvas.on('selection:updated', (e) => {
+        const items = e.selected || []
+        items.forEach(it => applyTextboxControls(it))
+      })
+
       //设置默认笔画
       setTimeout(() => {
         this.fcanvas.freeDrawingBrush.width = this.drawWidth