function SVGPathInterpolator (path, eps, maxIter) {
const safeIter = maxIter || 100;
const epsilon = eps || 0.00001;
const pathString = path || "M0,0L1,1";
const area = svg`
<svg>
<path d='${pathString}' />
</svg>`
const svgpath = area.querySelector('path');
svgpath.setAttribute('d', pathString);
const totalLength = svgpath.getTotalLength();
const minPoint = svgpath.getPointAtLength(0);
const maxPoint = svgpath.getPointAtLength(totalLength);
let reverse = maxPoint.x < minPoint.x;
const range = reverse ? [maxPoint, minPoint] : [minPoint, maxPoint];
reverse = reverse ? -1 : 1;
return function interpolator (x) {
const targetX = x === 0 ? 0 : x || minPoint.x;
if ( targetX < range[0].x ) return range[0];
if ( targetX > range[1].x ) return range[1];
const estimatedLength = estimateLength(totalLength / 2, 0, totalLength);
return estimatedLength ? svgpath.getPointAtLength(estimatedLength) : false;
function estimateLength (l, mn, mx) {
let delta = svgpath.getPointAtLength(l).x - targetX;
let next_delta = 0;
let iter = 0;
while (Math.abs(delta) > epsilon) {
if (iter++ > safeIter) return false;
if (reverse * delta < 0) { mn = l; l = (l + mx) / 2; }
else { mx = l; l = (mn + l) / 2; }
next_delta = svgpath.getPointAtLength(l).x - targetX;
delta = next_delta;
}
return l;
}
}
}