最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to draw outside of an HTML canvas element? - Stack Overflow

programmeradmin1浏览0评论

I have an HTML canvas element and have implemented a brush that captures the mousedown, mousemove, and mouseup events of the canvas element. This all works fine for drawing on the canvas. However, I don't think I like how you can't continue a drawing if your mouse leaves the canvas mid stroke. It kind of just cuts it off. It's very unforgiving to the person and not very user-friendly in my opinion.

If you open up Microsoft Paint and begin drawing with the brush or ellipse or something, as long as you start within the canvas, you can drag your mouse anywhere on your screen and re-enter the canvas wherever. It also makes it easy, for example, to draw quarter-circles in corners because you can drag the ellipse tool off-screen. I hope this makes sense.

Anyways, I was wondering if there was a way to implement this with the HTML5 canvas or how I would go about implementing this sort of thing. The user would never have to actually seen anything drawn over there; it's mostly just going to be a feature for usability.

Edit: A problem with a lot of these solutions is how to handle coordinates. Currently my canvas is in the middle of the screen and the top left of the canvas is (0, 0) and the bottom right is (500, 500). The translation work of the coordinates has to be considered as well.

Edit2: I found out that apparently you can draw off the canvas bounds just fine. For example, you can supply negative widths, heights, and coordinates and the canvas element will handle it just fine. So basically the solution will likely involve just capturing the document's mousemove and mouseup and just translating the x and y to start at the canvas's top left corner.

I have an HTML canvas element and have implemented a brush that captures the mousedown, mousemove, and mouseup events of the canvas element. This all works fine for drawing on the canvas. However, I don't think I like how you can't continue a drawing if your mouse leaves the canvas mid stroke. It kind of just cuts it off. It's very unforgiving to the person and not very user-friendly in my opinion.

If you open up Microsoft Paint and begin drawing with the brush or ellipse or something, as long as you start within the canvas, you can drag your mouse anywhere on your screen and re-enter the canvas wherever. It also makes it easy, for example, to draw quarter-circles in corners because you can drag the ellipse tool off-screen. I hope this makes sense.

Anyways, I was wondering if there was a way to implement this with the HTML5 canvas or how I would go about implementing this sort of thing. The user would never have to actually seen anything drawn over there; it's mostly just going to be a feature for usability.

Edit: A problem with a lot of these solutions is how to handle coordinates. Currently my canvas is in the middle of the screen and the top left of the canvas is (0, 0) and the bottom right is (500, 500). The translation work of the coordinates has to be considered as well.

Edit2: I found out that apparently you can draw off the canvas bounds just fine. For example, you can supply negative widths, heights, and coordinates and the canvas element will handle it just fine. So basically the solution will likely involve just capturing the document's mousemove and mouseup and just translating the x and y to start at the canvas's top left corner.

Share Improve this question edited Sep 22, 2015 at 16:48 Lawrence Douglas asked Sep 22, 2015 at 16:00 Lawrence DouglasLawrence Douglas 7471 gold badge7 silver badges16 bronze badges 5
  • 3 Could you capture the mouse events on the window itself and then delegate to the canvas? – zero298 Commented Sep 22, 2015 at 16:02
  • Perhaps try posting an example of what you have currently. It's easier to help if we don't first have to recreate our own 'broken' example. – duncanhall Commented Sep 22, 2015 at 16:03
  • 1 Maybe you could also make the canvas element in full width and height of the window and the drawing area somewhat smaller within the canvas? – Aidas Bendoraitis Commented Sep 22, 2015 at 16:08
  • @AidasBendoraitis: That's a pretty good idea too. Let me try that real quick. – Lawrence Douglas Commented Sep 22, 2015 at 16:09
  • @zero298: Could you show how to do that? – Lawrence Douglas Commented Sep 22, 2015 at 16:18
Add a ment  | 

3 Answers 3

Reset to default 2

Here is one way you can keep drawing when reenter the canvas:

  • Create a global variable and set that one to true on mousedown
  • Add a global event for mouseup so you can catch if someone do that outside the canvas, and if so, set global variable to false, and the canvas element's mouseup need of course also to set the same variable
  • On mousemove, check for global variable to be true before draw

To draw "outside" the canvas, like quarter-circles in a corner, I would move all events to the document level as global handler and catch the canvas element on click and pass its client coordinates to be puted with the document coordinates.

Here is an extremely rough first draft of how you can listen for mouse events on the window rather than the canvas to be able to draw continuously:

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>

One solution would be to literally make the canvas the size of the window, and scale its size with it. The canvas can be mostly transparent.

I'm sure there's also a way to make mouse events and such go through the canvas first but then pass through to the elements behind, if that's desired. (See: "js events bubbling and capturing".)

But then you would have absolute control and be able to draw anything anywhere.

发布评论

评论列表(0)

  1. 暂无评论