窗口大小决定是否触发Mouseout事件

18

我想在经过3D变换的画布上绘图,但是在Chrome浏览器中鼠标移出事件存在一些奇怪的问题。

当我将JSFiddle窗口大小设置为2100像素时,鼠标移出事件按预期工作。

enter image description here

然而,当我将窗口大小设置为1900像素时,鼠标事件大约在红色线条处触发。

enter image description here

这真的很奇怪,因为JSFiddle窗口大小决定了鼠标移出事件是否能够正确触发。

在Firefox和Edge中,直到此处鼠标移出事件都能够被正确触发,但在Chrome中无法正常工作!此外,在滚动位置(例如添加一些<br>并滚动会影响鼠标移出事件位置)、窗口大小(参见上面的图像)或画布宽度(例如将画布宽度设置为200能够正确触发鼠标移出事件)方面我们看到了一些奇怪的行为。

有人能帮我解决这个bug吗?使浏览器能够独立于窗口大小或滚动位置正确地触发mouseout事件?

代码: JSFiddle

演示: YouTube

fiddle中的代码片段:

$(".dynamic-drawing-canvas").on("mouseout", function(e) {
  console.log(e.clientX, e.clientY)
})
#container {
  pointer-events: none;
  margin-left: 400px;
}

.dynamic-drawing-canvas {
  pointer-events: auto;
  background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
  <canvas class="dynamic-drawing-canvas" width="1200" height="300" style="
    transform: matrix3d(1.0303, 0.00317459, 0, 2.13211e-05, -0.68458, -0.165542, 0, -0.00111181, 0, 0, 1, 0, -34.7412, 264.118, 0, 1);
    transform-origin: left top;
"></canvas>
</div>


1
我无法在本地或CodePen上重现此问题。为确保此问题不是JSFiddle平台本身的问题,请您提供一个CodePen链接以演示相同的问题。 - Brandon McConnell
1
这在Firefox上可以运行,但在Chrome/Edge上无法运行。我认为可能是它们处理转换的方式有问题,但还不确定问题出在哪里。 - Alexandre Elshobokshy
1
实际上,我被我的金丝雀浏览器误导了(它的窗口大小与我的稳定版本不同)。问题仍未解决,运行二分查找后,我发现它一直存在(至少从M53开始)。当然,webkit也有同样的bug... - Kaiido
1
是的,@wuiwuiwui,你可以这样做 :) 但不要指望很快修复错误。 - Alexandre Elshobokshy
@Jabbar 是的,同样的行为。 - wuiwuiwui
显示剩余8条评论
1个回答

1

看起来你遇到了canvas容器的问题。

以下是一些注意事项: canvas使用标记中的属性生成宽度为1200px和高度为300px:width="1200" height="300"您可以通过直接或使用JavaScript在<canvas>标签中覆盖这些值。 CSS调整大小存在问题的原因:CSS的作用是将现有的canvas重新调整大小。当典型/大多数HTML组件被调整大小时,浏览器可以很好地处理。不同之处在于<canvas>是像素的集合。当你使用CSS改变像素大小时,这些像素会发生改变(被拉伸或缩小),画布上的图像会呈现出不同的外观。请注意,空白的画布也会被拉伸,因此向其绘制可能会面临挑战,可能无法按预期工作。

在这里,我使用JavaScript调整了你的canvas以适应容器,但这只是一个示例-你的大小会有所不同。

我添加了一些边框,以便你可以看到它的效果-我放置了一些日志来显示它的变化和mouseout何时触发,因为现在它适合容器的大小-使用1.1进行了比例缩放,并将样式移动到CSS中,以便我可以添加注释。

console.clear();
let canvas = document.getElementById("c");

let width = canvas.width;
let height = canvas.height;
console.log("CW:", width, "CH:", height);
let rect = canvas.parentNode.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;

width = canvas.width;
height = canvas.height;
let r = canvas.getBoundingClientRect();
let ctop = r.top;
let cleft = r.left;
console.log("T:", ctop, "L:", cleft, "W:", width, "H:", height);
$(".dynamic-drawing-canvas")
  .on("mouseout", function(e) {
    // console.log(e.clientX, e.clientY);
    console.log("Screen X/Y:", e.screenX, e.screenY, "Client X/Y:", e.clientX, e.clientY);
    console.log("X:", e.screenX - e.clientX);
    console.log("Y:", e.screenY - e.clientY);
  });
#container {
  pointer-events: none;
  position: absolute;
  top: 0;
  left: 0;
  margin-left: 0px;
  width: 90%;
  height: 100%;
  border: solid red 3px;
}

.dynamic-drawing-canvas {
  pointer-events: auto;
  background-color: blue;
  object-fit: none;
  object-position: top left;
  transform-origin: left top;
  /* pulled out of markup, alter for 2.13211e-5 */
  /*
  transform: matrix3d(
  1.0303, 0.00317459, 0, 0.0000213211,
  -0.68458, -0.165542, 0, -0.00111181,
  0, 0, 1, 0,
  -34.7412, 264.118, 0, 1
  ); 
  THEN adjusted the 
      following transformations:
         0, 30, 0, 1.1
        Translates every X point by 0px
        Translates every Y point by 30px
        Translates every Z point by 0
        Scales down by 10%
*/
  transform: matrix3d(1.0303, 0.00317459, 0, 0.0000213211, 0.68458, 0.165542, 0, 0.00111181, 0, 0, 1, 0, 0, 30, 0, 1.1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
  <canvas id="c" class="dynamic-drawing-canvas" width="1200" height="300"></canvas>
</div>


嗨。你隐藏了问题,但并没有解决它 :) 或者将其纳入一些创意CSS中,这实际上是他在答案中寻找的内容,我个人认为。 - Alexandre Elshobokshy
@AlexandreElshobokshy - 这是一个观点问题 - 如果图像超出画布边框/大小,应该发生什么?请注意,在这种情况下,CSS不是答案。我将在答案中添加更多细节以增加清晰度。 - Mark Schultheiss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接