如何在 HTML canvas 元素之外绘制?

How to draw outside of an HTML canvas element?

我有一个 HTML canvas 元素并实现了一个画笔来捕获 mousedownmousemovemouseup 事件 canvas 元素。这一切都适用于在 canvas 上绘图。但是,我不认为我喜欢如果您的鼠标离开 canvas 中间笔画就无法继续绘图的方式。它有点像切断它。这对这个人来说是非常无情的,在我看来也不是很人性化。

如果您打开 Microsoft Paint 并开始使用画笔或椭圆或其他工具绘图,只要您在 canvas 内开始,您可以将鼠标拖动到屏幕上的任意位置并重新输入 canvas无论哪里。它还可以轻松地在角落绘制四分之一圆,因为您可以将椭圆工具拖出屏幕。我希望这是有道理的。

无论如何,我想知道是否有一种方法可以使用 HTML5 canvas 来实现它,或者我将如何实现这种事情。用户永远不必实际看到那里绘制的任何东西;它主要只是一个可用性功能。

编辑:很多这些解决方案的一个问题是如何处理坐标。目前我的canvas在屏幕中间,canvas的左上角是(0, 0),右下角是(500, 500)。还要考虑坐标的平移工作

Edit2:我发现显然你可以画出 canvas 边界就好了。例如,您可以提供负宽度、高度和坐标,canvas 元素会很好地处理它。所以基本上解决方案可能涉及只捕获文档的 mousemovemouseup 并只翻译 xy 以从 canvas 的左上角开始角落.

重新输入 canvas 时,您可以通过以下方式继续绘图:

  • 创建一个全局变量并在鼠标按下时将该变量设置为 true
  • 为 mouseup 添加一个全局事件,这样您就可以捕捉到有人在外面这样做 canvas,如果是,设置全局变量为false,canvas元素的mouseup当然也需要设置相同的变量
  • 在 mousemove 上,在绘制之前检查全局变量是否为真

要绘制 "outside" canvas,就像角落中的四分之一圆一样,我会将所有事件作为全局处理程序移动到文档级别,并在单击时捕获 canvas 元素并传递其客户端坐标以与文档坐标一起计算。

这是一个非常粗略的初稿,说明如何在 window 而不是 canvas 上监听鼠标事件以便能够连续绘制:

var logger = document.getElementById("logger"),
  mState = document.getElementById("mState"),
  mX = document.getElementById("mX"),
  mY = document.getElementById("mY"),
  cX = document.getElementById("cX"),
  cY = document.getElementById("cY"),
  c = document.getElementById("canvas"),
  ctx = c.getContext("2d");

var mouse = {
  x: 0,
  y: 0,
  state: ""
};

function printCanvasLocation() {
  var b = c.getBoundingClientRect();
  cX.innerHTML = b.top;
  cY.innerHTML = b.left;
}

function setState(mouseE, state) {
  mouse.x = mouseE.clientX;
  mouse.y = mouseE.clientY;

  mX.innerHTML = mouseE.clientX;
  mY.innerHTML = mouseE.clientY;
  if (state) {
    mState.innerHTML = state;
    mouse.state = state;
  }
}

window.addEventListener("mousedown", function(mouseE) {
  setState(mouseE, "down");
});

window.addEventListener("mouseup", function(mouseE) {
  setState(mouseE, "up");
});

window.addEventListener("mousemove", function(mouseE) {
  var offset = c.getBoundingClientRect();

  var fix = {
    x1: (mouse.x - offset.left),
    y1: (mouse.y - offset.top),
    x2: (mouseE.clientX - offset.left),
    y2: (mouseE.clientY - offset.top)
  };

  if (mouse.state === "down") {
    ctx.moveTo(fix.x1, fix.y1);
    ctx.lineTo(fix.x2, fix.y2);
    ctx.strokeStyle = "#000";
    ctx.stroke();
  }
  setState(mouseE);
});

window.addEventListener("resize", function() {
  printCanvasLocation();
});

printCanvasLocation();
            .center {

              text-align: center;

            }

            canvas {

              background-color: lightblue;

            }
<main>
  <div class="center">
    <canvas id="canvas" width="128" height="128">If you can see me, you should update your browser</canvas>
  </div>
  <div id="logger" role="log">
    <span>State: </span><span id="mState">Unknown</span>
    <span>X: </span><span id="mX">Unknown</span>
    <span>Y: </span><span id="mY">Unknown</span>
    <span>Canvas X: </span><span id="cX">Unknown</span>
    <span>Canvas Y: </span><span id="cY">Unknown</span>
  </div>
</main>

一种解决方案是按字面意思使 canvas 成为 window 的大小,并随其缩放。 canvas 可以大部分透明。

我相信还有一种方法可以使鼠标事件等先通过 canvas,然后再传递到后面的元素,如果需要的话。 (参见:"js events bubbling and capturing"。)

但是这样你就可以拥有绝对的控制权,可以在任何地方画任何东西。