Published
Edited
Mar 23, 2022
Importers
19 stars
Insert cell
Insert cell
chart = {
const node = svg`<svg viewBox="0 0 ${width} ${height}">
<path fill="none" stroke="#000" stroke-width="1" d="${line}" />
<line fill="none" stroke="#ccc" stroke-width="2" y1="0" y2="${height}" />
${data.map(d => svg`<circle r=2.5 cx=${d[0]} cy=${d[1]}>`)}
<circle id="intersection" fill="red" r="5" />
</svg>`;

const solver = solve(d3.select(node).select('path').node());

return d3
.select(node)
.on("mousemove", move)
.call(move)
.node();

function move() {
const x = d3.event ? d3.mouse(node)[0] : width / 3;

d3.select(node)
.select("line")
.attr("x1", x)
.attr("x2", x);

d3.select(node)
.select("#intersection")
.attr("cx", x)
.attr("cy", domain[0] <= x && x <= domain[1] ? solver(x) : -10);
}
}
Insert cell
// the solver looks for the closest to the `x` point on the `path` and returns its `y`
solve = path => {
const array = d3.range(path.getTotalLength())
const bisect = d3.bisector(d => path.getPointAtLength(d).x)
const len = x => bisect.right(array, x)
return x => path.getPointAtLength(len(x)).y
}
Insert cell
data = Array.from({ length: 20 }, (_, i) => [
((i + .5) * width) / 21,
Math.random() * height
])
Insert cell
domain = d3.extent(data.map(d => Math.ceil(d[0])))
Insert cell
line = d3.line().curve(d3.curveBasis)(data)
Insert cell
Insert cell
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