0

How can I get all the coordinates of the border of a drawn ellipse? I can draw it by using canvas.

My idea is to get all the coordinates and store them into an array. When clicking on the canvas, I want to check if the point is in the border of the ellipse.

Laurel
  • 5,965
  • 14
  • 31
  • 57
hiepnv
  • 1

1 Answers1

0

Just redefine your path (without drawing it), then use (instead of isPointInPath()):

ctx.isPointInStroke(x, y)

It will even consider the line thickness of the stroke.

The problem with this solution is that these path checks are not supported in IE (ie). For that you need a manual solution. But for browsers which do (you can feature check this), simple use it like this:

Example

var ctx = document.querySelector("canvas").getContext("2d");

function getEllipse(ctx, cx, cy, rx, ry) {   // render an ellipse
  var angleStep = 0.05, angle = angleStep;
  ctx.moveTo(cx + rx, cy);                   // start at angle 0
  while(angle < Math.PI*2) {
    ctx.lineTo(
      cx + rx * Math.cos(angle),             // store these to an array as wanted
      cy + ry * Math.sin(angle)
    );
    angle += angleStep
  }
  ctx.closePath();
}

// draw an ellipse:
getEllipse(ctx, 150, 75, 100, 60);
ctx.lineWidth = 10;
ctx.stroke();

// reuse ellipse path when checking for mouse position
ctx.canvas.onmousemove = function(e) {
  ctx.clearRect(0,0,300,150);
  var rect = this.getBoundingClientRect(),    // get adjusted mouse position
      x = e.clientX - rect.left,
      y = e.clientY - rect.top;
  
  ctx.strokeStyle = ctx.isPointInStroke(x, y) ?  "red" : "black";
  
  ctx.stroke();
};
<canvas></canvas>

Note that context already has an ellipse method, it doesn't have the greatest support yet, but when it does you could instead of storing each point along the ellipse, store the center and radius (it do support rotation as well as start and end angles too). Something to have in mind for later.

Support as of 2018/9

api.CanvasRenderingContext2D.isPointInStroke                                       
On Standard Track                                                                  
https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/isPointInStroke
                                                                                   
DESKTOP >        |Chrome    |Edge      |Firefox   |IE        |Opera     |Safari    
:----------------|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:
isPointInStroke  |    Y     |    -     |    Y     |    -     |    Y     |    Y     
                                                                                   
MOBILE >         |Chrome/A  |Edge/mob  |Firefox/A |Opera/A   |Safari/iOS|Webview/A 
:----------------|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:
isPointInStroke  |    Y     |    Y     |    Y     |    Y     |    Y     |    Y

Data from MDN - "npm i -g mdncomp" (c) epistemex                                   

For these browsers you can use this polyfill.

Other alternatives is to use line-intersection. Iterate your array and check each line segment against a line going from center to mouse. You will get a x/y coordinate if it does, then apply a radius check for thickness (you can optimize by only selecting the closest lines to an angle etc.)

How to do line intersection can be found in this answer (getIntersection).

Community
  • 1
  • 1
  • Upvote for efficiency using `isPointInStroke`! :-) One addition: in production you often want the hit-area to be larger than the displayed lineWidth (so the user has a bigger target to aim at), so you might want to dissociate the drawn lineWidth from the lineWidth used for hit testing. – markE Jun 05 '15 at 19:12
  • Thickness can be set right before checking, updated with solution for IE –  Jun 05 '15 at 19:32
  • 1
    I also thought IE (the weak sister of browsers) had added support for `isPointInStroke`. Even MDN thinks `isPointInStroke` is supported: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInStroke. C'mon Microsoft! – markE Jun 05 '15 at 19:46
  • @K3N, LOL! :-)) That sounds like MS. I could have **sworn** that I've used `isPointInStroke` with IE before so you might be right about them removing it for whatever wacky reason. – markE Jun 05 '15 at 20:43