{
const height = 500;
const data = mutable circles;
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("stroke-width", 1.5);
const circle = svg.append("g")
.attr("fill", "none")
.attr("stroke", "black")
.attr("pointer-events", "all")
.selectAll("circle")
.data(data)
.join("circle")
.attr("r", ({r}) => r)
.call(d3.drag().on("drag", dragged));
const line = svg.append("line")
.attr("stroke", "red")
.attr("pointer-events", "none");
const point = svg.append("circle")
.attr("fill", "blue")
.attr("pointer-events", "none")
.attr("r", 3.5);
const orthocircle = svg.append("circle")
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-dasharray", "4,4")
.attr("pointer-events", "none");
const tangentline = svg.append("g")
.attr("stroke", "blue")
.selectAll("line")
.data(new Array(4))
.join("line");
function update() {
const [a, b] = data;
const [cx, cy] = radical(a, b);
const k = (width + height) / Math.hypot(cx, cy);
const [vx, vy] = [(b.x - cx) * k, (b.y - cy) * k];
const o = {x: cx, y: cy, r: Math.sqrt(Math.abs((cx - a.x) ** 2 + (cy - a.y) ** 2 - a.r ** 2))};
circle
.attr("cx", ({x}) => x)
.attr("cy", ({y}) => y);
point
.attr("cx", cx)
.attr("cy", cy);
orthocircle
.attr("cx", o.x)
.attr("cy", o.y)
.attr("r", o.r);
line
.attr("x1", cx - vy)
.attr("y1", cy + vx)
.attr("x2", cx + vy)
.attr("y2", cy - vx);
tangentline
.data([...intersections(o, a), ...intersections(o, b)])
.attr("x1", cx)
.attr("y1", cy)
.attr("x2", ([x]) => x)
.attr("y2", ([, y]) => y)
}
function dragged(event, d) {
d.x = event.x, d.y = event.y;
mutable circles = data;
update();
}
return svg.call(update).node();
}