G6 icon indicating copy to clipboard operation
G6 copied to clipboard

[Bug]: 电脑触控板双指操作时,zoom-canvas 和 drag-canvas 手势同时触发了

Open xiaweiss opened this issue 7 months ago • 8 comments

Describe the bug / 问题描述

复现方式是双指朝同一个方向移动:

  1. 移动触发了 drag-canvas 视图移动
  2. 两个手指间的距离会有变化,触发了 zoom-canvas 缩放

Reproduction link / 复现链接

https://g6.antv.antgroup.com/examples/behavior/canvas/#optimize

Steps to Reproduce the Bug or Issue / 重现步骤

No response

Version / 版本

Please select / 请选择

OS / 操作系统

  • [x] macOS
  • [ ] Windows
  • [ ] Linux
  • [ ] Others / 其他

Browser / 浏览器

  • [x] Chrome
  • [ ] Edge
  • [ ] Firefox
  • [ ] Safari (Limited support / 有限支持)
  • [ ] IE (Nonsupport / 不支持)
  • [ ] Others / 其他

xiaweiss avatar May 12 '25 07:05 xiaweiss

这个能力目前还不支持

yvonneyx avatar May 12 '25 08:05 yvonneyx

好的,谢谢。这个问题在 mac 上比较容易复现,触控板、鼠标都是可以双指操作的。

我暂时把缩放禁用了,只保留了平移。

xiaweiss avatar May 12 '25 08:05 xiaweiss

看了下 sketch、蓝湖的交互表现,zoom-canvas 和 drag-canvas 预期是互斥的,就是触发了一种时,另一种不触发

xiaweiss avatar May 12 '25 08:05 xiaweiss

@yvonneyx 看起来是个 bug,双指拉开的手势,预期是不触发 drag-canvas 事件

xiaweiss avatar May 12 '25 08:05 xiaweiss

问了下 AI,在 macOS 触控板中,JavaScript 可通过监听 wheel 事件并结合事件对象的属性判断用户是滚动还是缩放,具体实现如下:

核心判断逻辑

  1. 监听 wheel 事件
document.addEventListener('wheel', function(e) {
  // 判断逻辑
}, { passive: false });
  1. 通过 ctrlKeymetaKey 属性区分
  • 缩放操作:触控板双指捏合会触发 wheel 事件,且 e.ctrlKey === true(即使未按下物理 Control 键)。
  • 滚动操作:双指上下滑动触发 wheel 事件,e.ctrlKey === false,且 deltaY 或 deltaX 有值。
  1. 示例代码
document.addEventListener('wheel', function(e) {
  if (e.ctrlKey || e.metaKey) {
    // 缩放行为(双指捏合)
    e.preventDefault(); // 可选:阻止默认缩放
    console.log('缩放:', e.deltaY);
  } else {
    // 滚动行为(双指滑动)
    console.log('滚动:', e.deltaY);
  }
}, { passive: false });

xiaweiss avatar May 12 '25 08:05 xiaweiss

问了下 AI,在 macOS 触控板中,JavaScript 可通过监听 wheel 事件并结合事件对象的属性判断用户是滚动还是缩放,具体实现如下:

核心判断逻辑

  1. 监听 wheel 事件

document.addEventListener('wheel', function(e) { // 判断逻辑 }, { passive: false }); 2. 通过 ctrlKeymetaKey 属性区分

  • 缩放操作:触控板双指捏合会触发 wheel 事件,且 e.ctrlKey === true(即使未按下物理 Control 键)。
  • 滚动操作:双指上下滑动触发 wheel 事件,e.ctrlKey === false,且 deltaY 或 deltaX 有值。
  1. 示例代码

document.addEventListener('wheel', function(e) { if (e.ctrlKey || e.metaKey) { // 缩放行为(双指捏合) e.preventDefault(); // 可选:阻止默认缩放 console.log('缩放:', e.deltaY); } else { // 滚动行为(双指滑动) console.log('滚动:', e.deltaY); } }, { passive: false });

赞,可以在 G6 中验证下,这个需求确实还挺常见的

yvonneyx avatar May 12 '25 09:05 yvonneyx

目前我在配置项里设置了 enable,解决了,不确定源码里怎么调整

behaviors: [
    {
      type: 'scroll-canvas',
      enable: (event: any) => {
        if (isPC()) {
          // 缩放
          if (event.ctrlKey || event.metaKey) return false
          // 滚动
          return true

        } else {
          return true
        }
      }
    },
    {
      type: 'zoom-canvas',
      enable: (event: any) => {
        if (isPC()) {
          // 缩放
          if (event.ctrlKey || event.metaKey) return true
          // 滚动
          return false

        } else {
          return true
        }
      }
    },
    {
      type: 'drag-canvas',
      enable: (event: any) => {
        // 阻止双指,防止来回闪烁
        if (event.nativeEvent.touches?.length > 1) return false
        if ('targetType' in event) return event.targetType === 'canvas'
        return true
      }
    },
    {
      type: 'drag-element',
      enable: (event: any) => {
        // 阻止双指,防止来回闪烁
        if (event.nativeEvent.touches?.length > 1) return false
        return ['node', 'combo'].includes(event.targetType)
      }
    },
    // 仅电脑端开启 hover 样式
    {
      type: 'hover-activate',
      enable: (event: any) => isPC() && event.targetType === 'node',
      state: 'active',
      degree: 1,
    }
]

判断 PC 电脑端的辅助函数:

const isWechatDevTools = () => {
  return navigator.userAgent.toLowerCase().includes('webdebugger')
}

const isPC = () => {
  const ua = navigator.userAgent

  return Boolean(
    !isWechatDevTools() &&
    !ua.match(/mobile/ig) &&
    (ua.match(/mac/ig) || ua.match(/windows/ig))
  )
}

xiaweiss avatar May 13 '25 08:05 xiaweiss

目前我在配置项里设置了 enable,解决了,不确定源码里怎么调整

behaviors: [ { type: 'scroll-canvas', enable: (event: any) => { if (isPC()) { // 缩放 if (event.ctrlKey || event.metaKey) return false // 滚动 return true

    } else {
      return true
    }
  }
},
{
  type: 'zoom-canvas',
  enable: (event: any) => {
    if (isPC()) {
      // 缩放
      if (event.ctrlKey || event.metaKey) return true
      // 滚动
      return false

    } else {
      return true
    }
  }
},
{
  type: 'drag-canvas',
  enable: (event: any) => {
    // 阻止双指,防止来回闪烁
    if (event.nativeEvent.touches?.length > 1) return false
    if ('targetType' in event) return event.targetType === 'canvas'
    return true
  }
},
{
  type: 'drag-element',
  enable: (event: any) => {
    // 阻止双指,防止来回闪烁
    if (event.nativeEvent.touches?.length > 1) return false
    return ['node', 'combo'].includes(event.targetType)
  }
},
// 仅电脑端开启 hover 样式
{
  type: 'hover-activate',
  enable: (event: any) => isPC() && event.targetType === 'node',
  state: 'active',
  degree: 1,
}

] 判断 PC 电脑端的辅助函数:

const isWechatDevTools = () => { return navigator.userAgent.toLowerCase().includes('webdebugger') }

const isPC = () => { const ua = navigator.userAgent

return Boolean( !isWechatDevTools() && !ua.match(/mobile/ig) && (ua.match(/mac/ig) || ua.match(/windows/ig)) ) }

ok,学习一下,后面我提个 PR 支持

yvonneyx avatar May 13 '25 08:05 yvonneyx