JSFiddle - React, Tailwind, and code Playground
by msmini5
HTML
<canvas id="canvas" width=300 height=300></canvas>
CSS
body {
background-color: ivory;
}
#canvas {
border:1px solid red;
}
JavaScript
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var bez1 = {
sx: 50,
sy: 150,
cx1: 125,
cy1: 75,
cx2: 100,
cy2: 225,
ex: 200,
ey: 130
};
drawCurvedArrow(bez1);
function drawCurvedArrow(bez) {
// calculate the ending angle of the curve
var pointNearEnd = getCubicBezierXYatT({
x: bez.sx,
y: bez.sy
}, {
x: bez.cx1,
y: bez.cy1
}, {
x: bez.cx2,
y: bez.cy2
}, {
x: bez.ex,
y: bez.ey
}, 0.99);
var dx = bez.ex - pointNearEnd.x;
var dy = bez.ey - pointNearEnd.y;
var endingAngle = Math.atan2(dy, dx);
// draw the arrow shaft
ctx.moveTo(bez.sx, bez.sy);
ctx.bezierCurveTo(bez.cx1, bez.cy1, bez.cx2, bez.cy2, bez.ex, bez.ey);
ctx.lineWidth = 5;
ctx.stroke();
// draw the arrow head
var size = ctx.lineWidth;
ctx.beginPath();
ctx.save();
ctx.translate(bez.ex, bez.ey);
ctx.rotate(endingAngle);
ctx.moveTo(0, 0);
ctx.lineTo(0, -size * 2);
ctx.lineTo(size * 3, 0);
ctx.lineTo(0, size * 2);
ctx.lineTo(0, 0);
ctx.closePath();
ctx.fill();
ctx.restore();
}
// helper functions
function getCubicBezierXYatT(startPt, controlPt1, controlPt2, endPt, T) {
var x = CubicN(T, startPt.x, controlPt1.x, controlPt2.x, endPt.x);
var y = CubicN(T, startPt.y, controlPt1.y, controlPt2.y, endPt.y);
return ({
x: x,
y: y
});
}
// cubic helper formula at T distance
function CubicN(T, a, b, c, d) {
var t2 = T * T;
var t3 = t2 * T;
return a + (-a * 3 + T * (3 * a - a * T)) * T + (3 * b + T * (-6 * b + b * 3 * T)) * T + (c * 3 - c * 3 * T) * t2 + d * t3;
}