Akxe - 1 year ago 98

Javascript Question

So I have an imaginary circle divided into multiple parts (I use 8 for simplicity, but in the end, I would like to divide it to 16 or 32 parts).

Then I have N number of quadratic bezier curves, that is between 2 nearest segments. It may rest upon the circle or further from the center, but not nearer than the circle.

I know how to find, what in witch line I should look for intersection in, but I do not know how to split it into two parts... I know, that if I looked for intersection of the line and curve I should get the point that the previous curve should end and the next should start, and that by derivation I may be able to get the vector, but I do not know how to do it.

Example image where I have only 8 parts for easier problem solving.

The point is, to make "progress" bar using bezier curves. Side note: The curves will change every frame, as they are part of music visualization.

**If there is a better way to spit color a curve, I am all for it!**

Answer

The algo for getting the length is still not working, it seems I forgot to calculate the last path, if someone wants to point me to the solution that would be very nice since I don't have time right now. (Otherwise, I'll try to find it in the weekend...)

Since you don't need support for older IE (<=11), one easy way is to use the `setLineDash()`

method.

This will allow you to only draw your path once, and to only have to get the full length of your path.

To do so, I use a js implementation of this algo made by tunght13488. There may be better implementations of it.

```
var ctx = c.getContext('2d');
var percent = 90;
var length = 0;
// all our quadraticCurves points
var curves = [
[146, 146, 134, 118, 184, 103],
[217, 91, 269, 81, 271, 107],
[263, 155, 381, 158, 323, 173],
[279, 182, 314, 225, 281, 223],
[246, 219, 247, 274, 207, 236],
[177, 245, 133, 248, 137, 211],
[123, 238, 10, 145, 130, 150]
];
// get the full length of our spline
curves.forEach(function(c) {
length += quadraticBezierLength.apply(null, c);
});
// that's still not it...
length += quadraticBezierLength.apply(null,curves[curves.length-1]);
var anim = function() {
var offset = (percent / 100) * length;
ctx.clearRect(0, 0, c.width, c.height);
ctx.beginPath();
ctx.moveTo(133, 150);
// draw our splines
curves.forEach(function(c) {
ctx.bezierCurveTo.apply(ctx, c);
})
ctx.closePath();
// the non completed part
ctx.strokeStyle = "gray";
// this will make the part from 0 to offset non drawn
ctx.setLineDash([0, offset, length]);
ctx.stroke();
// the completed part
ctx.setLineDash([offset, length]);
ctx.strokeStyle = "blue";
ctx.stroke();
percent = (percent + .25) % 100;
requestAnimationFrame(anim);
}
// modified from https://gist.github.com/tunght13488/6744e77c242cc7a94859
function Point(x, y) {
this.x = x;
this.y = y;
}
function quadraticBezierLength(p0x, p0y, p1x, p1y, p2x, p2y) {
var a = new Point(
p0x - 2 * p1x + p2x,
p0y - 2 * p1y + p2y
);
var b = new Point(
2 * p1x - 2 * p0x,
2 * p1y - 2 * p0y
);
var A = 4 * (a.x * a.x + a.y * a.y);
var B = 4 * (a.x * b.x + a.y * b.y);
var C = b.x * b.x + b.y * b.y;
var Sabc = 2 * Math.sqrt(A + B + C);
var A_2 = Math.sqrt(A);
var A_32 = 2 * A * A_2;
var C_2 = 2 * Math.sqrt(C);
var BA = B / A_2;
return (A_32 * Sabc + A_2 * B * (Sabc - C_2) + (4 * C * A - B * B) * Math.log((2 * A_2 + BA + Sabc) / (BA + C_2))) / (4 * A_32);
};
anim();
```

`<canvas width="500" height="500" id="c"></canvas>`

Source (Stackoverflow)