Published
Edited
Dec 12, 2021
Importers
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = [[1,1], [4, 1], [5, 3], [6, 3], [7,3], [10,10]]
Insert cell
line = d3.line().curve(d3.curveBasis).defined( d => d[0] !== 6 )
Insert cell
pathString = line(data)
Insert cell
targetPoint = SVGPathInterpolator(pathString, 0.01)(slider)
Insert cell
d3 = require("d3-shape@3")
Insert cell
Insert cell
Insert cell
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; // check for 0 and null/undefined
if ( targetX < range[0].x ) return range[0]; // clamp
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;
//console.log(delta, targetX, epsilon);
while (Math.abs(delta) > epsilon) {
if (iter++ > safeIter) return false;
//console.log(iter, Math.abs(delta) > epsilon);
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;
}
//console.log(iter);
return l;
// if (Math.abs(delta) < epsilon) return resultLength
// if (reverse * delta < 0) return estimateLength((totalLength + max)/2, resultLength, max)
// return estimateLength((min + resultLength)/2, min, resultLength)
}
}
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more