Frage

I'm trying to draw a line from the edges of the two circles in HTML5 canvas. So, I know the coordinates of the centers of two circles and their radius.

  1. Circles drawn randomly.
  2. Line should move from the edge of one circle to the other.

Please help!

P.S. Sorry for my english :)

UPDATE:

I'm trying this, but how to know angle?

from_line_x = circle1.x + circle1.radius * Math.cos(Math.PI * angle);
from_line_y = circle1.y + cirlce1.radius * Math.sin(Math.PI * angle);
to_line_x = circle2.x - circle2.radius * Math.cos(Math.PI * angle);
to_line_y = circle2.y - circle2.radius * Math.sin(Math.PI * angle);

UPDATE2:

I think I found how to find the angle. But as a circle drawn randomly, the line is drawn is not always true. How then should look algorithm?

Sorry for my english again.

War es hilfreich?

Lösung

Here's a solution that will achieve what you've asked for.

I've declared 3 'classes' to make things clearer to read. First, I define a generic shape class. Next, I define a basic circle class. Finally, I define a vec2 class. You could easily extend this as I have done, and add other shapes that inherit from the shape class - i.e square triangle, etc.

I create 10 circles at random positions and radii. I then draw a line between each circle and the one following it. I didn't bother with the 'wrap-around' case, so I draw 10 circles and 9 lines (I dont draw from circle 9 to circle 0)

I've used some of the code Tamura left, hence the familiar dimensions and id of the canvas.

<!doctype html>
<html>
<head>
<script>
function byId(e){return document.getElementById(e)}
window.addEventListener('load', onDocLoaded, false);

var shapeList = [];

function onDocLoaded()
{
    var i, n=10;
    var canvas = byId('myCanvas');

    for (i=0; i<n; i++)
    {
        shapeList[i] = new circle_t(Math.random()*578, Math.random()*400, Math.random()*30 + 20);
        shapeList[i].draw(canvas);
    }

    for (i=0; i<n-1; i++)
        draw_line2(shapeList[i].origX, shapeList[i].origY, shapeList[i].radius, shapeList[i+1].origX, shapeList[i+1].origY, shapeList[i+1].radius);
}   

var shape_t = function(x,y)
{
    this.origX = (x==undefined ? 0 : x);
    this.origY = (y==undefined ? 0 : y);
}
shape_t.prototype =
{
    origX:0, origY:0, typeString:'shape',
    setPos: function(x,y){this.x=x;this.y=y;},
    setType: function(typeString){this.typeString = typeString;},
    toString: function(){return this.typeString + " - " + this.origX + "," + this.origY;},
    draw: function(canElem){},
};

function circle_t(x,y,radius)
{
    this.origX = (x==undefined ? 0 : x);
    this.origY = (y==undefined ? 0 : y);
    this.radius = (radius==undefined ? 10 : radius);
    this.setType("circle");
}
circle_t.prototype = new shape_t();
circle_t.prototype.constructor = circle_t;
circle_t.prototype.draw = function(canElem, color)
{
    var ctx = canElem.getContext('2d');
    var col = 'black';
    if (color != undefined)
        col = color;
    drawCircle(this.origX, this.origY, this.radius, ctx, col);
}

circle_t.prototype.setRadius = function(radius)
{
    if (radius != undefined)
        this.radius = radius;
}

function drawCircle(x, y, radius, ctx, col)
{
    ctx.save();
    if (col == undefined)
        col = 'black';
    ctx.strokeStyle = col;
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.arc(x,y,radius,(Math.PI/180)*0, (Math.PI/180)*360, false);
    ctx.stroke();
    ctx.closePath();
    ctx.restore();
}

// define a vec2 class to make vector maths easier (simpler to read)
function vec2(x,y)
{
    this.length = function()
    {
        return Math.sqrt((this.x * this.x) + (this.y*this.y));
    }
    this.normalize = function()
    {
        var scale = this.length();
        this.x /= scale;
        this.y /= scale;
    }
    this.x = x;
    this.y = y;
}

function draw_line2(center1_x, center1_y, radius1, center2_x, center2_y, radius2)
{
    var betweenVec = new vec2(center2_x - center1_x, center2_y - center1_y);
    betweenVec.normalize();

    var p1x = center1_x + (radius1 * betweenVec.x);
    var p1y = center1_y + (radius1 * betweenVec.y);

    var p2x = center2_x - (radius2 * betweenVec.x);
    var p2y = center2_y - (radius2 * betweenVec.y);

    var canvas = document.getElementById('myCanvas');
    var context = canvas.getContext('2d');
    context.beginPath();
        context.moveTo(p1x,p1y);
        context.lineTo(p2x,p2y);
    context.stroke();
}
</script>
</head>
<body>
    <canvas id="myCanvas" width="578" height="400"></canvas>
</body>
</html>

See here for a live demo: http://jsfiddle.net/YYjYL/

Andere Tipps

3 steps solutions :
- build all your random circle coordinates (x,y,r).
- draw all lines in between their center as you see fit.
- draw all circles.

(!)

code is very easy :

http://jsbin.com/qutahatu/1/edit?js,output

enter image description here

var circles = [];

function createCircles(cnt) {
  circles = [];
  for (var i=0; i<cnt; i++) {
    var x = 5+ Math.random() *300;
    var y = 5+ Math.random() *300;
    var r = 20  + Math.random() *6;    
    circles.push({x:x,y:y,r:r});
  }
}

function drawLines() {
  var cnt= circles.length;
   ctx.strokeStyle = '#000';
  ctx.lineWidth = 2;
  ctx.beginPath();
  ctx.moveTo(circles[0].x, circles[0].y);
  for (var i=1; i<cnt; i++) {
     ctx.lineTo(circles[i].x, circles[i].y);
  }
  ctx.stroke(); 
}

function drawCircles() {
  var cnt= circles.length;
   ctx.fillStyle = '#4A8';
  for (var i=0; i<cnt; i++) {
     ctx.beginPath();
     ctx.arc(circles[i].x, circles[i].y, circles[i].r, 0, 6.282);
     ctx.fill();
  }
}

createCircles(4);
drawLines();
drawCircles();

Here is the JSFIDDLE link: http://jsfiddle.net/WfF3v/1/. Is that what you want?

Below is the JS code:

function draw_circle(center_x, center_y){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = center_x;
var centerY = center_y;
var radius = 70;

context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
}

function draw_line(center1_x, center1_y, center2_x, center2_y) {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');

context.beginPath();
context.moveTo(center1_x, center1_y);
context.lineTo(center2_x, center2_y);
context.stroke();
}

draw_circle(100,100);
draw_circle(300,200);
draw_line(100,100,300,200);

Had the same problem so I made these functions based on sketch. connectingPts takes the two circle's coordinates {x: x, y: y, r: radius} and returns a 2 element array of the coordinates of the line segment connecting the two circles from their edges.

function connectingPts(t1, t2) {
    let p1, p2;

    if (t1.x < t2.x) {
        p1 = { ...t1 };
        p2 = { ...t2 };
    } else {
        p1 = { ...t2 };
        p2 = { ...t1 };
    }

    let dx = Math.abs(p1.x - p2.x);
    let dy = Math.abs(p1.y - p2.y);

    let alpha = radToDeg(Math.atan(dy / dx));
    let beta = 90 - alpha;

    return [
        rotatePt(
            { ...p1, x: p1.x + p1.r },
            p1,
            (p2.y < p1.y ? 360 : alpha * 2) - alpha,
        ),
        rotatePt(
            { ...p2, x: p2.x + p2.r },
            p2,
            (p2.y > p1.y ? 270 - 2 * beta : 90) + beta,
        ),
    ];
}

function rotatePt(p, o, deg) {
    let res = { ...p };

    let _x = res.x - o.x;
    let _y = res.y - o.y;

    res.x = _x * Math.cos(degToRad(deg)) - _y * Math.sin(degToRad(deg));
    res.y = _x * Math.sin(degToRad(deg)) + _y * Math.cos(degToRad(deg));

    res.x += o.x;
    res.y += o.y;

    return res;
}

function degToRad(deg) {
    return (deg * Math.PI) / 180;
}

function radToDeg(rad) {
    return (rad * 180) / Math.PI;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top