Chart.js Zoom插件:默认滚动失效,需区分XY轴滚动行为
解决Chart.js Zoom插件与页面Y轴滚动冲突问题
我用Chart.js实现了一款柱状图,支持用户滚动查看近两年的月度数据,为此引入Chart.js Zoom插件实现X轴平移功能。但插件会自动给canvas添加touch-action: none样式,导致页面Y轴滚动失效。将该属性改为auto虽恢复了Y轴滚动,却破坏了柱状图的X轴平移功能。现需实现精准区分用户操作:横向拖动时触发X轴平移展示往期数据,纵向滚动时保留页面默认滚动行为。
插件自动添加的Canvas样式
display: block; box-sizing: border-box; height: 300px; width: 343px; touch-action: none; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
当前Chart.js配置(TS)
plugins: { zoom: { pan: { sensitivity: 6, enabled: true, mode: 'x', speed: 0.2, threshold: 8, }, }, }
可行解决方案
1. 动态控制touch-action属性
通过监听canvas的触摸事件,根据用户初始拖动方向动态修改touch-action属性:
- 触摸开始时记录初始触摸坐标
- 触摸移动时计算X、Y方向的偏移量,判断用户主要操作方向
- 横向拖动时设置
touch-action: pan-x,触发插件的X轴平移;纵向滚动时设置touch-action: pan-y,保留页面滚动 - 触摸结束后重置属性,确保后续操作正常触发
示例代码:
const chartCanvas = document.getElementById('your-chart-canvas') as HTMLCanvasElement; let startX = 0; let startY = 0; chartCanvas.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; startY = e.touches[0].clientY; }); chartCanvas.addEventListener('touchmove', (e) => { const deltaX = Math.abs(e.touches[0].clientX - startX); const deltaY = Math.abs(e.touches[0].clientY - startY); if (deltaX > deltaY) { chartCanvas.style.touchAction = 'pan-x'; } else { chartCanvas.style.touchAction = 'pan-y'; } }, { passive: false }); chartCanvas.addEventListener('touchend', () => { chartCanvas.style.touchAction = 'none'; });
2. 调整Zoom插件阈值+修改touch-action
直接设置canvas的touch-action: pan-x pan-y,同时增大插件的threshold值,减少纵向滚动时误触发X轴平移的概率:
- 修改CSS覆盖默认样式:
#your-chart-canvas { touch-action: pan-x pan-y !important; }
- 更新Chart.js配置:
plugins: { zoom: { pan: { sensitivity: 6, enabled: true, mode: 'x', speed: 0.2, threshold: 20, // 增大阈值,仅当横向偏移超过20px时触发平移 }, }, }
3. 自定义Zoom插件触摸逻辑
重写Zoom插件的触摸处理方法,在touchmove事件中判断操作方向:
- 若检测到纵向滚动,不阻止默认事件,让页面正常滚动;若为横向拖动,继续执行插件的平移逻辑
- 此方法需要对Zoom插件源码有一定了解,适合需要高度定制的场景
内容的提问来源于stack exchange,提问作者Sudharsan S
相关产品推荐
相关产品推荐

