Published
Edited
Aug 1, 2020
1 fork
Importers
21 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
subject
Insert cell
Insert cell
function clipper(inside, intersect) {
return function(subject) {
const P = [], n = subject.length;
if (!n) return P;
let p0, p1 = subject[n - 1];
let t0, t1 = inside(p1);
for (let i = 0; i < n; ++i) {
p0 = p1, p1 = subject[i];
t0 = t1, t1 = inside(p1);
if (t1 !== t0) P.push(intersect(p0, p1));
if (t1) P.push(p1);
}
return P;
};
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
inside = ({
top: ([x, y]) => y >= ymin,
right: ([x, y]) => x <= xmax,
bottom: ([x, y]) => y <= ymax,
left: ([x, y]) => x >= xmin
})
Insert cell
intersect = ({
top: ([x0, y0], [x1, y1]) => [x0 + (x1 - x0) * (ymin - y0) / (y1 - y0), ymin],
right: ([x0, y0], [x1, y1]) => [xmax, y0 + (y1 - y0) * (xmax - x0) / (x1 - x0)],
bottom: ([x0, y0], [x1, y1]) => [x0 + (x1 - x0) * (ymax - y0) / (y1 - y0), ymax],
left: ([x0, y0], [x1, y1]) => [xmin, y0 + (y1 - y0) * (xmin - x0) / (x1 - x0)]
})
Insert cell
Insert cell
Insert cell
clip = ({
top: clipper(inside.top, intersect.top),
right: clipper(inside.right, intersect.right),
bottom: clipper(inside.bottom, intersect.bottom),
left: clipper(inside.left, intersect.left)
})
Insert cell
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);
}
Insert cell
xmin = 310
Insert cell
xmax = 620
Insert cell
ymin = 120
Insert cell
ymax = 400
Insert cell
d3 = require("d3@5")
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