8
I need to draw a flow dynamically based on a few user 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 to node 2.
To draw the direction I draw the arrow at the end of the line but I can’t get the arrow to turn just 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 method drawArrow()
in:
canvasContext.translate(ptArrow.x, ptArrow.y);
canvasContext.rotate(angleInDegrees);
I have tried all possible values for rotation and translation but the arrow still does not rotate properly around itself. Can someone help me?
Update
I’ve been watching 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);
Yet I still have the same problem..
Using
canvasContext.translate(-ptArrow.x/20, ptArrow.y/3.5);
andcanvasContext.rotate(angleInDegrees/100);
I managed to get the arrow right for Fiddle’s coordinates, but I played with the coordinates of circle 2 and that was just a trick of mine.– mutlei
@Can Mutley show me in the example that working please? I applied this to my example but the arrow goes out of place and is supposed to be at the end of the line pointing to circle 2. http://jsfiddle.net/msmini5/gbyt2zuq/
– Ninita
Link to jsfiddle http://jsfiddle.net/zfoyf8bg/
– mutlei
@Mutley Because it really really works for the current circles. The problem is that the construction of this flow must be dynamic. If we change the circle coordinates, the solution no longer works. The values you placed for rotation and translation correspond to some logic or were just a result of trial-error?
– Ninita
Trial and error, unfortunately. Changing circle coordinates will not work. D:
– mutlei