curveRadialNatural = {
return function(complete) {
function Natural(context) {
this._context = context;
}
Natural.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x = [];
this._y = [];
},
lineEnd: function() {
var x = this._x,
y = this._y,
n = x.length;
if (n) {
this._line
? this._context.lineTo(x[0], y[0])
: this._context.moveTo(x[0], y[0]);
if (n === 2) {
this._context.lineTo(x[1], y[1]);
} else {
var px = controlPoints(x),
py = controlPoints(y);
for (
var i0 = 0, i1 = 1;
i1 < (this.complete ? n : n - 1); // TBD: apply only on the last element of data!
++i0, ++i1
) {
this._context.bezierCurveTo(
px[0][i0],
py[0][i0],
px[1][i0],
py[1][i0],
x[i1],
y[i1]
);
}
}
}
if (this._line || (this._line !== 0 && n === 1))
this._context.closePath();
this._line = 1 - this._line;
this._x = this._y = null;
},
point: function(x, y) {
// if the new point has a a wide angle with the previous one, insert intermediates
x = +x;
y = +y;
const l = this._x.length;
if (l > 0) {
const px = this._x[l - 1],
py = this._y[l - 1],
norm = Math.sqrt(x ** 2 + y ** 2),
pnorm = Math.sqrt(px ** 2 + py ** 2),
N = norm * pnorm,
angle = N ? Math.acos((x * px + y * py) / N) : 0;
if (Math.abs(angle) > 1) {
var a = Math.atan2(py, px),
b = Math.atan2(y, x);
if (a < b - Math.PI) a += 2 * Math.PI;
if (b < a - Math.PI) b += 2 * Math.PI;
for (var t = 0.34; t < 1; t += 0.333) {
const n = pnorm * Math.pow(norm / pnorm, t),
alpha = a * (1 - t) + b * t;
this._x.push(n * Math.cos(alpha));
this._y.push(n * Math.sin(alpha));
}
}
}
this._x.push(x);
this._y.push(y);
}
};
// See https://www.particleincell.com/2012/bezier-splines/ for derivation.
function controlPoints(x) {
var i,
n = x.length - 1,
m,
a = new Array(n),
b = new Array(n),
r = new Array(n);
(a[0] = 0), (b[0] = 2), (r[0] = x[0] + 2 * x[1]);
for (i = 1; i < n - 1; ++i)
(a[i] = 1), (b[i] = 4), (r[i] = 4 * x[i] + 2 * x[i + 1]);
(a[n - 1] = 2), (b[n - 1] = 7), (r[n - 1] = 8 * x[n - 1] + x[n]);
for (i = 1; i < n; ++i)
(m = a[i] / b[i - 1]), (b[i] -= m), (r[i] -= m * r[i - 1]);
a[n - 1] = r[n - 1] / b[n - 1];
for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
b[n - 1] = (x[n] + a[n - 1]) / 2;
for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
return [a, b];
}
return function(context) {
return new Natural(context);
};
};
}