Public
Edited
Nov 20, 2022
1 fork
1 star
Insert cell
# Inversion in a circle
Insert cell
Insert cell
Insert cell
md`## Inverse point in a circle`
Insert cell
Insert cell
Insert cell
Insert cell
md`## Inverse line in a circle`
Insert cell
{
const { point, vector, line, circle, box, Inversion } = Flatten;

const stageBox = box(0, 0, width, height);

// Define data model
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();

// Create stage and display svg
const stage = d3.select(DOM.svg(width, height));
stage.html(model.svg());

// Define drag behaviour of point on circle
stage
.selectAll(".point_on_line") // Select points to be dragged
.data([model.point1, model.point2]) // Bind draggable element to data model
.call(
d3.drag().on("drag", (event, point) => {
event.sourceEvent.stopPropagation();
point.x += event.dx;
point.y += event.dy;
model.recalculate();
update();
})
);

stage
.select("#line") // Select points to be dragged
.data([model.line]) // Bind draggable element to data model

.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();

// Update stage after model changed
function update() {
// Update point that dragged
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);
}
}
Insert cell
md`## Inverse circle in a circle`
Insert cell
Insert cell
Insert cell
height = {
return width > 400 ? 400 : 200; // less value for narrow device
}
Insert cell
html`
<style type="text/css">
#point {
fill: magenta;
}
#circle {
fill: transparent;
cursor: move;
}
#point_on_circle {
cursor: move;
}
#point_on_line {
cursor: move;
}
#point:hover {
opacity: 0.4;
cursor: move;
}
#reflected_point {
fill: blue
}
#inversion_circle {
stroke-dasharray: 5
}
</style>
`
Insert cell
Flatten = require("@flatten-js/core")
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