{
const width = 800;
const height = 300;
const margin = 30;
const svg = d3.create("svg").attr("width", width).attr("height", height);
const pitch = soccer
.pitch()
.height(height)
.rotate(false)
.clip([
[0, 0],
[105, 68]
]);
const scaleX = d3.scaleLinear().domain([0, 1]).range([0, 105]);
const scaleY = d3.scaleLinear().domain([0, 1]).range([0, 68]);
const scaleC = d3
.scaleOrdinal()
.domain(["home", "away"])
.range(["orange", "blue"])
.unknown("red");
svg.append("g").call(pitch);
const snapshot = tracking.filter((d) => d.frame_id === frame);
const layer = svg.select("#above");
layer
.append("g")
.selectAll("circle")
.data(snapshot)
.join("circle")
.attr("class", (d) => `id-${d.id}`)
.attr("debug", (d) => console.log("debug:", d))
.attr("cx", (d) => scaleX(d.x))
.attr("cy", (d) => scaleY(d.y))
.attr("r", (d) => (d.team === "ball" ? 0.4 : 0.8))
.attr("fill", "none")
.attr("stroke-width", 0.3)
.attr("stroke", (d) => scaleC(d.team))
.on("mouseover", mouseover);
const delaunay = d3.Delaunay.from(
snapshot
.filter((d) => d.id !== "ball")
.map((d) => [scaleX(d.x), scaleY(d.y)])
);
const voronoi = delaunay.voronoi([0, 0, 105, 68]);
layer
.append("g")
.attr("class", "voronoi")
.selectAll("path")
.data(snapshot)
.join("path")
.attr("class", (d) => `id-${d.id}`)
.attr("d", (_, i) => voronoi.renderCell(i))
.attr("fill", "none")
.attr("stroke", showVoronoi ? "black" : "none")
.attr("stroke-width", 0.3)
.attr("opacity", 0.8)
.attr("stroke-dasharray", "1,2")
.attr("pointer-events", "all")
.on("mouseover", mouseover)
.on("mouseleave", mouseleave);
function mouseover(event, d) {
const className = d3.select(this).attr("class");
d3.select(`.${className}`).attr("stroke-width", 1);
}
function mouseleave(event, d) {
const className = d3.select(this).attr("class");
d3.select(`.${className}`).attr("stroke-width", 0.3);
}
return svg.node();
}