Skip to main content
added 8 characters in body
Source Link
Ninita
  • 123
  • 1
  • 6
Source Link
Ninita
  • 123
  • 1
  • 6

Rotate arrow on canvas

I need to draw a flow dynamically based on some user choices. In that flow I want to draw the choices (blue circles with number) and the directions of that choices (line and arrow). For example: node 1 to node 2.

JSFiddle

To draw the direction I draw a arrow in the end of the line but I can't make the arrow rotate around itself.

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 drawArrow() method in the lines

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

canvasContext.rotate(angleInDegrees);

I already tried every possible values for the rotation and the translation but arrow still don't rotate properly around itself. Can anyone help me?