Chrome-使用 D3 缩放时的特定问题
Chrome-specific issue when using D3 zoom
我正在开发 D3 应用程序,遇到了一个奇怪的缩放问题,该问题出现在 Chrome 而不是 Firefox(这是我唯一测试过我的代码的浏览器)。我已将问题归结为下面的代码片段。
基本上,在某些情况下,当我在 canvas 元素上滚动时(使用鼠标的滚动按钮或笔记本电脑触控板上的两个手指),我定义的缩放处理程序不会被调用。但是,单击并拖动 canvas 以尝试平移它会成功调用缩放处理程序。
问题详情:
只要不调用“单击”事件处理程序,缩放就会按预期工作。一旦调用,滚动缩放将不起作用。它与在单击事件处理程序中调用 ctx.getImageData
有关。
如果我在调用 clearRect
的 canvas 选择末尾省略 .call
,即使您没有触发“点击”事件
除 v5 外,其他版本的 D3 也会出现此问题。我试过 v6 和 v7。
我使用的Chrome版本是92.0.4515.159
我知道有几种方法可以解决这个问题:
- 如果 canvas 元素的不透明度未设置为 0,该问题已解决。
- 也可以调用
window.addEventListener('wheel', () => {})
解决
- 据我所知,另一种解决方案是在 canvas 的父元素上定义缩放行为。
下面的代码在左上角创建了一个 canvas 元素(它不可见,因为它的不透明度为 0)。缩放元素将向控制台打印一条“缩放”消息。单击 canvas 将打印“单击”。您会发现,按原样使用代码,如果您单击该元素然后尝试滚动缩放,则不会打印“缩放”。您还可以 运行 JSFiddle 中的代码:https://jsfiddle.net/yr3jdvhw/37/
我想知道是什么导致了这个问题。正如我提到的,我可以将 canvas 的不透明度设置为非零值来避免该问题。但我真的很想知道根本原因。
<html>
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<canvas class="my-canvas"></canvas>
<script>
const myCanvas = d3.select(".my-canvas")
.style('opacity', 0)
.on('click', function () {
console.log("click")
let ctx = this.getContext('2d')
const pixel = ctx.getImageData(0, 0, 1, 1)
})
.call(d3.zoom().on('zoom', () => {
console.log("zooming")
}))
.call(function (s) {
let ctx = s.node().getContext('2d')
ctx.clearRect(0, 0, s.node().width, s.node().height)
})
</script>
</body>
</html>
这是一个 Chrome 错误,我刚刚打开了一个关于它的 new issue,希望它能尽快得到修复。
根据我的调查,根本问题是它们确实在合成器级别处理轮子事件,并且当您的 canvas 减速时,它不再在合成器中采用正确的路径,因此不再被视为“车轮事件处理程序区域”。
当前调用 getImageData()
会使您的 canvas 减速,它从 GPU 转到 CPU 并停留在那里,这就是调用此方法导致问题的原因。同样,在您执行任何绘图操作之前,canvas 尚未移动到 GPU,因此这里也会重现错误。
请注意,希望在一些版本中 { willReadFrequently }
可以不使用标志,并且目前大多数 canvases 将始终加速。
我正在开发 D3 应用程序,遇到了一个奇怪的缩放问题,该问题出现在 Chrome 而不是 Firefox(这是我唯一测试过我的代码的浏览器)。我已将问题归结为下面的代码片段。
基本上,在某些情况下,当我在 canvas 元素上滚动时(使用鼠标的滚动按钮或笔记本电脑触控板上的两个手指),我定义的缩放处理程序不会被调用。但是,单击并拖动 canvas 以尝试平移它会成功调用缩放处理程序。
问题详情:
只要不调用“单击”事件处理程序,缩放就会按预期工作。一旦调用,滚动缩放将不起作用。它与在单击事件处理程序中调用
ctx.getImageData
有关。如果我在调用
clearRect
的 canvas 选择末尾省略.call
,即使您没有触发“点击”事件除 v5 外,其他版本的 D3 也会出现此问题。我试过 v6 和 v7。
我使用的Chrome版本是92.0.4515.159
我知道有几种方法可以解决这个问题:
- 如果 canvas 元素的不透明度未设置为 0,该问题已解决。
- 也可以调用
window.addEventListener('wheel', () => {})
解决 - 据我所知,另一种解决方案是在 canvas 的父元素上定义缩放行为。
下面的代码在左上角创建了一个 canvas 元素(它不可见,因为它的不透明度为 0)。缩放元素将向控制台打印一条“缩放”消息。单击 canvas 将打印“单击”。您会发现,按原样使用代码,如果您单击该元素然后尝试滚动缩放,则不会打印“缩放”。您还可以 运行 JSFiddle 中的代码:https://jsfiddle.net/yr3jdvhw/37/
我想知道是什么导致了这个问题。正如我提到的,我可以将 canvas 的不透明度设置为非零值来避免该问题。但我真的很想知道根本原因。
<html>
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<canvas class="my-canvas"></canvas>
<script>
const myCanvas = d3.select(".my-canvas")
.style('opacity', 0)
.on('click', function () {
console.log("click")
let ctx = this.getContext('2d')
const pixel = ctx.getImageData(0, 0, 1, 1)
})
.call(d3.zoom().on('zoom', () => {
console.log("zooming")
}))
.call(function (s) {
let ctx = s.node().getContext('2d')
ctx.clearRect(0, 0, s.node().width, s.node().height)
})
</script>
</body>
</html>
这是一个 Chrome 错误,我刚刚打开了一个关于它的 new issue,希望它能尽快得到修复。
根据我的调查,根本问题是它们确实在合成器级别处理轮子事件,并且当您的 canvas 减速时,它不再在合成器中采用正确的路径,因此不再被视为“车轮事件处理程序区域”。
当前调用 getImageData()
会使您的 canvas 减速,它从 GPU 转到 CPU 并停留在那里,这就是调用此方法导致问题的原因。同样,在您执行任何绘图操作之前,canvas 尚未移动到 GPU,因此这里也会重现错误。
请注意,希望在一些版本中 { willReadFrequently }
可以不使用标志,并且目前大多数 canvases 将始终加速。