function* animation(subject, mode) {
const svg = d3.create("svg")
.attr("viewBox", [(932 - 500) / 2, 0, 500, 500])
.attr("width", Math.min(640, width))
.attr("height", Math.min(500, width))
.style("height", "auto");
svg.append("path")
.attr("fill", "blue")
.attr("fill-opacity", 0.1)
.attr("stroke", "blue")
.attr("d", `M${subject.join("L")}Z`);
svg.append("rect")
.attr("fill", "red")
.attr("fill-opacity", 0.1)
.attr("stroke", "red")
.attr("x", mode === "left" ? xmin : -1)
.attr("y", mode === "top" ? ymin : -1)
.attr("width", mode === "right" ? xmax : 1001)
.attr("height", mode === "bottom" ? ymax : 1001);
if (!subject.length) {
yield svg.node();
return;
}
const clipped = svg.append("g");
do {
let p0, p1 = subject[subject.length - 1], t0, t1 = inside[mode](p1), P = [];
clipped.selectAll("*").remove();
yield svg.node();
for (let i = 0; i < subject.length; ++i) {
p0 = p1, t0 = t1, p1 = subject[i], t1 = inside[mode](p1);
yield Promises.delay(1000, svg.node());
clipped.append("circle")
.attr("fill", t1 ? "black" : "none")
.attr("stroke", t1 ? "none" : "black")
.attr("r", 0)
.attr("cx", p1[0])
.attr("cy", p1[1])
.transition()
.delay(t0 !== t1 ? 500 : 250)
.attr("r", 4);
if (t0 !== t1) {
let p = intersect[mode](p0, p1);
if (P.length) clipped.insert("line", "circle")
.attr("x1", P[P.length - 1][0])
.attr("y1", P[P.length - 1][1])
.attr("x2", P[P.length - 1][0])
.attr("y2", P[P.length - 1][1])
.attr("stroke", "black")
.attr("stroke-width", 1.5)
.transition()
.attr("x2", p[0])
.attr("y2", p[1]);
clipped.append("circle")
.attr("fill", "red")
.attr("r", 0)
.attr("cx", p[0])
.attr("cy", p[1])
.transition()
.delay(250)
.attr("r", 4);
P.push(p);
}
if (t1) {
if (P.length) clipped.insert("line", "circle")
.attr("x1", P[P.length - 1][0])
.attr("y1", P[P.length - 1][1])
.attr("x2", P[P.length - 1][0])
.attr("y2", P[P.length - 1][1])
.attr("stroke", "black")
.attr("stroke-width", 1.5)
.transition()
.delay(t0 !== t1 ? 250 : 0)
.attr("x2", p1[0])
.attr("y2", p1[1]);
P.push(p1);
}
}
yield Promises.delay(1000, svg.node());
if (P.length) clipped.append("line")
.attr("x1", P[P.length - 1][0])
.attr("y1", P[P.length - 1][1])
.attr("x2", P[P.length - 1][0])
.attr("y2", P[P.length - 1][1])
.attr("stroke", "black")
.attr("stroke-width", 1.5)
.transition()
.attr("x2", P[0][0])
.attr("y2", P[0][1]);
clipped.insert("path", "*")
.attr("fill", "lightgray")
.attr("fill-opacity", 0)
.attr("d", `M${clip[mode](subject).join("L")}Z`)
.transition()
.attr("fill-opacity", 1);
yield Promises.delay(5000, svg.node());
} while (loop);
}