{
const { point, vector, line, circle, box, Inversion } = Flatten;
const stageBox = box(0, 0, width, height);
let model = {
inversion_circle: circle(point(width / 2, height / 2), 100),
point1: point((2 * width) / 3, height / 3),
point2: point((2 * width) / 3, (2 * height) / 3),
I: undefined,
line: undefined,
reflected_shape: undefined,
recalculate: function () {
this.I = this.I || new Inversion(this.inversion_circle);
this.line = line(this.point1, this.point2);
this.reflected_shape = this.I.inverse(this.line);
},
svg: function () {
let svg =
this.inversion_circle.svg({ id: "inversion_circle" }) +
this.inversion_circle.pc.svg() +
this.point1.svg({ className: "point_on_line", r: 5 }) +
this.point2.svg({ className: "point_on_line", r: 5 }) +
this.line?.svg(stageBox, { id: "line" }) +
this.reflected_shape?.svg({ id: "reflected_shape" });
return svg;
}
};
model.recalculate();
const stage = d3.select(DOM.svg(width, height));
stage.html(model.svg());
stage
.selectAll(".point_on_line")
.data([model.point1, model.point2])
.call(
d3.drag().on("drag", (event, point) => {
event.sourceEvent.stopPropagation();
point.x += event.dx;
point.y += event.dy;
model.recalculate();
update();
})
);
stage
.select("#line")
.data([model.line])
.call(
d3
.drag()
.clickDistance([5, 5])
.on("drag", (event, line) => {
event.sourceEvent.stopPropagation();
model.point1.x += event.dx;
model.point1.y += event.dy;
model.point2.x += event.dx;
model.point2.y += event.dy;
model.recalculate();
update();
})
);
return stage.node();
function update() {
if (model.reflected_shape instanceof Flatten.Circle) {
stage
.select("#reflected_shape")
.attr("cx", model.reflected_shape.pc.x)
.attr("cy", model.reflected_shape.pc.y)
.attr("r", model.reflected_shape.r);
}
let ip = model.line.intersect(stageBox);
stage
.select("#line")
.attr("x1", ip[0]?.x)
.attr("y1", ip[0]?.y)
.attr("x2", ip[1]?.x)
.attr("y2", ip[1]?.y);
stage
.selectAll(".point_on_line")
.raise()
.attr("cx", (point) => point.x)
.attr("cy", (point) => point.y);
}
}