Extend Line based on slope to the end of canvas/dr

2019-05-30 16:15发布

I am trying to extend a line (from to points(X,Y)) to the end of the drawing area. so far i found a couple of instructions on how to calculate the extension end point.

however i don't really get it done it works in one direction and breaks as soon as you reach over the middle point.

see attached code sample (the real product i am working on is in swift, but as it is not a programming language related issue, i ported it to javascript)

on the right side it seems to work, black line is the one the user selects, red one is the extension to the edge of canvas, going to the left side produces garbage.

var canvas = document.getElementById("myCanvas");
var endPoint = {
  x: 200,
  y: 200
};

function draw() {
  //Demo only in final product user also can select the startpoint
  startPoint = {
    x: 150,
    y: 150
  }
  screenMax = {
    x: canvas.height,
    y: canvas.width
  }

  var ctx = canvas.getContext("2d");
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.beginPath();
  ctx.moveTo(startPoint.x, startPoint.y);
  ctx.lineTo(endPoint.x, endPoint.y);
  ctx.strokeStyle = "#000000";
  ctx.stroke();

  //Extend line to end of canvas according to slope
  var slope = 1.0
  var extendedPoint = {
    x: 0,
    y: 0
  }
  if (endPoint.x != startPoint.x) {
    slope = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x);
    extendedPoint = {
      x: screenMax.x,
      y: slope * (screenMax.x - endPoint.x) + endPoint.y
    }

  } else {
    slope = 0
    extendedPoint.x = endPoint.x;
    extendedPoint.y = screenMax.y;
  }
  console.log(endPoint);

  //Draw the Extension
  ctx.beginPath();
  ctx.moveTo(endPoint.x, endPoint.y);
  ctx.lineTo(extendedPoint.x, extendedPoint.y);
  ctx.strokeStyle = "#FF0000";
  ctx.stroke();




}
//initial draw
draw();

//handle Mouse dOwn
canvas.onmousedown = function(e) {
  handleMouseDown(e);
}



// handle the mousedown event
//Set new endpoint
function handleMouseDown(e) {
  mouseX = parseInt(e.clientX);
  mouseY = parseInt(e.clientY);
  endPoint = {
    x: mouseX,
    y: mouseY
  }
  draw();
}
<!DOCTYPE html>
<html>

<body>

  <canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;">
      Your browser does not support the HTML5 canvas tag.</canvas>


</body>

</html>

2条回答
萌系小妹纸
2楼-- · 2019-05-30 16:53

This function may help, takes the line x1,y1 to x2,y2 and extends it to the border defined by left,top,right,bottom returning the intercept point as {x:?,y:?}

function toBorder(x1, y1, x2, y2, left, top, right, bottom){
    var dx, dy, py, vx, vy;
    vx = x2 - x1;
    vy = y2 - y1;
    dx = vx < 0 ? left : right;
    dy = py = vy < 0 ? top : bottom;
    if(vx === 0){
        dx = x1;
    }else if(vy === 0){
        dy = y1;
    }else{
        dy = y1 + (vy / vx) * (dx - x1);
        if(dy < top || dy > bottom){
            dx = x1 + (vx / vy) * (py - y1);
            dy = py;
        }
    }
    return {x : dx, y : dy}
}
查看更多
叼着烟拽天下
3楼-- · 2019-05-30 17:00

Slope approach is not universal - it cannot work with vertical lines (x0=x1).

I'd use parametric representation of ray (line)

 x0 = startPoint.x 
 x1 = endPoint.x
 y0 = startPoint.y 
 y1 = endPoint.y

dx = x1 - x0
dy = y1 - y0
x = x0 + dx * t
y = y0 + dy * t

Now check what border will be intersected first (with smaller t value)

//prerequisites: potential border positions
if dx > 0 then
   bx = width
else
   bx = 0

if dy > 0 then
   by = height
else
   bx = 0

//first check for horizontal/vertical lines 
if dx = 0 then
    return ix = x0,  iy = by

if dy = 0 then
    return iy = y0,  ix = bx


//in general case find parameters of intersection with horizontal and vertical edge
tx = (bx - x0) / dx
ty = (by - y0) / dy

//and get intersection for smaller parameter value
if tx <= ty then
   ix = bx
   iy = y0 + tx * dy
else
   iy = by
   ix = x0 + ty * dx

return ix, iy
查看更多
登录 后发表回答