Rotate an arrow on a canvas

8

I need to draw a stream dynamically based on the user's choices. In this flow I want to draw the chosen hypotheses (blue circles with numbers) and the direction between the choices (lines with arrows). For example: node 1 for node 2.

JSFiddle Example

To draw the direction I draw the arrow at the end of the line but I can not make the arrow just rotate around its center, following the direction of the line.

JS code

$(document).ready(function () {
    drawOnCanvas();
});

function drawOnCanvas() {
    var canvas = document.getElementById('myCanvas');

    if (canvas.getContext) {
        var ctx = canvas.getContext("2d");

        var circle1 = {
            x: 75,
            y: 75,
            r: 15
        };

        var circle2 = {
            x: 225,
            y: 50,
            r: 15
        };

        var arrow = 
            {
                h: 5,
                w: 10
            };

        drawCircle(ctx, circle1, "1");
        drawCircle(ctx, circle2, "2");

        var ptCircle1 = getPointOnCircle(circle1.r, circle1, circle2);
        var ptCircle2 = getPointOnCircle(circle2.r, circle2, circle1);
        var ptArrow = getPointOnCircle(circle2.r + arrow.w, circle2, circle1);

        drawLine(ctx, ptCircle1, ptCircle2);
        drawArrow(ctx, arrow, ptArrow, ptCircle2);
    }
}

function drawArrow(canvasContext, arrow, ptArrow, endPt) {

    var angleInDegrees = getAngleBetweenPoints(ptArrow, endPt);

    canvasContext.beginPath();
    // first save the untranslated/unrotated context
    canvasContext.save();        

    // move the rotation point to the center of the rect    
    canvasContext.translate(ptArrow.x, ptArrow.y);        
    // rotate the rect
    canvasContext.rotate(angleInDegrees);

    canvasContext.moveTo(endPt.x, endPt.y);
    canvasContext.lineTo(endPt.x - arrow.w, endPt.y + arrow.h);
    canvasContext.lineTo(endPt.x - arrow.w, endPt.y - arrow.h);
    canvasContext.closePath();
    canvasContext.fillStyle = "rgb(72,72,72)";
    canvasContext.stroke();
    canvasContext.fill();

    // restore the context to its untranslated/unrotated state
    canvasContext.restore();
}

function drawCircle(canvasContext, circle, text) {
    canvasContext.beginPath(); //começa ou reinicia o desenho de algo       
    canvasContext.fillStyle = "rgb(43,166,203)";
    canvasContext.arc(circle.x, circle.y, circle.r, 0, 2 * Math.PI, false); //cria arcos     
    canvasContext.fill(); //atribui estilos

    drawText(canvasContext, circle, text);
}

function drawText(canvasContext, circle, text) {
    canvasContext.font = '8pt Calibri';
    canvasContext.fillStyle = 'white';
    canvasContext.textAlign = 'center';
    canvasContext.fillText(text, circle.x, circle.y + 3);
}

function drawLine(canvasContext, startPt, endPt) {
    canvasContext.moveTo(startPt.x, startPt.y);
    canvasContext.lineTo(endPt.x, endPt.y);
    canvasContext.stroke();
}

function getPointOnCircle(radius, originPt, endPt) {
    var angleInDegrees = getAngleBetweenPoints(originPt, endPt);


    // Convert from degrees to radians via multiplication by PI/180        
    var x = radius * Math.cos(angleInDegrees * Math.PI / 180) + originPt.x;
    var y = radius * Math.sin(angleInDegrees * Math.PI / 180) + originPt.y;

    return { x: x, y: y };
}

function getAngleBetweenPoints(originPt, endPt) {
    var interPt = { x: endPt.x - originPt.x,
        y: endPt.y - originPt.y
    };

    return Math.atan2(interPt.y, interPt.x) * 180 / Math.PI;
}

I think the problem is in the drawArrow() nas method:

canvasContext.translate(ptArrow.x, ptArrow.y);   

canvasContext.rotate(angleInDegrees);

I have tried all possible values for rotation and translation but the arrow continues to not rotate properly around itself. Can anyone help me?

Update

I've seen and maybe the best way to draw the triangle is JSFiddle Example

canvasContext.moveTo(ptArrow.x, ptArrow.y);
canvasContext.lineTo(ptArrow.x, ptArrow.y - arrow.h);
canvasContext.lineTo(ptArrow.x + arrow.w, ptArrow.y);
canvasContext.lineTo(ptArrow.x + arrow.w, ptArrow.y);
canvasContext.lineTo(ptArrow.x, ptArrow.y + arrow.h);

However I continue with the same problem ..

    
asked by anonymous 16.01.2015 / 11:13

1 answer

6

Problem solved ! After defining the translation point, the coordinates used to draw the arrow should be based on the point 0 which actually becomes the translation point.

       // move the rotation point to the center of the rect    
       canvasContext.translate(ptArrow.x, ptArrow.y);        
       // rotate the rect
       canvasContext.rotate(angleInDegrees*Math.PI/180);

        canvasContext.beginPath();
        canvasContext.moveTo(0,0);
        canvasContext.lineTo( 0, -arrow.h);
        canvasContext.lineTo( arrow.w, 0);
        canvasContext.lineTo( 0, +arrow.h);    
    
16.01.2015 / 13:24