'use strict'
function rangeFrom1ToN(N) {
return Array(N).fill(0).map((x, index) => index).slice(1);
}
function expandRange(Range, precision) {
return Range.map(x => rangeFrom1ToN(precision).map((y, index) => x + 1/precision * index))
.reduce((acc, val) => acc.concat(val));
}
function formatForSvg(points) {
return points.map(x => x.toString()).reduce((acc, val) => {return acc + ' ' + val})
}
function derivative(curve, index){
if (index === 0) {
return 0;
}
const point1 = curve[index - 1];
const point2 = curve[index];
return (point2[1] - point1[1]) / (point2[0] - point1[0]);
}
function squiggleAroundCurve(x, y, curve, index) {
const len = lenCurve(curve, index);
const h = Math.sin(len);
const b = Math.sin(Math.atan2(1, derivative(curve, index))) * h;
const a = Math.cos(Math.atan2(1, derivative(curve, index))) * h;
x -= a;
y += b;
return [x, y];
}
function pow2(x) {
return Math.pow(x,2);
}
function dist(point1, point2) {
return Math.sqrt(pow2(point2[0] - point1[0]) + pow2(point2[1] - point1[1]))
}
function lenCurve(rasterizedCurve, index) {
const curve = rasterizedCurve.slice(0, index);
return curve.reduce((sum, point, index) => {
let len = 0;
if (index > 0) {
len = dist(point, curve[index - 1]);
}
return sum + len;
}, 0);
}
const Curve = expandRange(rangeFrom1ToN(90),50).map(x => [x, (Math.log(x) * 15)]);
const SquiggledCurve = Curve.map((point, index) => squiggleAroundCurve(point[0], point[1], Curve, index))
function zoom(curve, w) {
return curve.map(point => [point[0] * w, point[1] * w]);
}
function getNode(n, v) {
n = document.createElementNS("http://www.w3.org/2000/svg", n);
for (var p in v)
n.setAttributeNS(null, p.replace(/[A-Z]/g, function(m, p, o, s) { return "-" + m.toLowerCase(); }), v[p]);
return n
}
var svg = getNode("svg");
setTimeout(function() {
document.body.appendChild(svg);
const r = getNode('polyline', { points:formatForSvg(zoom(SquiggledCurve, 10)), fill:'none', stroke:'black'});
const c = getNode('polyline', { points:formatForSvg(zoom(Curve, 10)), fill:'none', stroke:'black'});
svg.appendChild(r);
svg.appendChild(c);
}, 1000);
svg {
width: 1100px;
height: 900px;
}