function gridDiagram(grid, options = {}) {
const { xmargin = 80, ymargin = 80, cellSize = 40, edgeSize = 60 } = options;
const { umin, umax, vmin, vmax } = grid.limits();
const svgCoords = (tcoords) => {
const [x, y] = grid.cartesian(tcoords);
return { x: x * edgeSize + xmargin, y: y * edgeSize + ymargin };
};
const p = svgCoords(new TCoord(umin, vmin));
const q = svgCoords(new TCoord(umax, vmax));
const width = Math.abs(q.x - p.x) + xmargin * 2;
const height = Math.abs(q.y - p.y) + ymargin * 2;
const svg = htl.svg`<svg width=${width} height=${height} viewbox="${
p.x - xmargin
} ${p.y - ymargin} ${width} ${height}" style="font-family:sans-serif;">`;
const sel = d3.select(svg);
for (let u = umin; u <= umax; u++) {
for (let v = vmin; v <= vmax; v++) {
const src = new TCoord(u, v);
if (!grid.getCell(src)) continue;
const { x: x1, y: y1 } = svgCoords(src);
let edges = new Set();
for (let dir of [0, 1, 2]) {
const dst = src.neighbor(dir);
if (!grid.getCell(dst)) continue;
edges.add(dir);
const { x: x2, y: y2 } = svgCoords(dst);
sel
.append("line")
.datum([src, dst])
.attr("class", "edge")
.attr("x1", x1)
.attr("x2", x2)
.attr("y1", y1)
.attr("y2", y2)
.attr("stroke", "black");
}
if (edges.has(0) && edges.has(1)) {
const dst0 = src.neighbor(0);
const dst1 = src.neighbor(1);
const [{ x: x0, y: y0 }, { x: x1, y: y1 }, { x: x2, y: y2 }] = [
svgCoords(src),
svgCoords(dst0),
svgCoords(dst1)
];
sel
.append("polygon")
.datum([src, dst0, dst1])
.attr("class", "minor")
.attr("points", `${x0},${y0} ${x1},${y1} ${x2},${y2}`)
.attr("fill", "rgba(0,0,255,0.3)");
}
if (edges.has(1) && edges.has(2)) {
const dst0 = src.neighbor(1);
const dst1 = src.neighbor(2);
const [{ x: x0, y: y0 }, { x: x1, y: y1 }, { x: x2, y: y2 }] = [
svgCoords(src),
svgCoords(dst0),
svgCoords(dst1)
];
sel
.append("polygon")
.datum([src, dst0, dst1])
.attr("class", "major")
.attr("points", `${x0},${y0} ${x1},${y1} ${x2},${y2}`)
.attr("fill", "rgba(255,0,0,0.3)");
}
}
}
const data = [...grid.cells()];
const nodes = sel
.selectAll("g.node")
.data(data)
.join("g")
.style("user-select", "none")
.attr("class", "node")
.each(function (d) {
const group = d3.select(this);
const { x, y } = svgCoords(d);
group
.attr("transform", `translate(${x},${y})`)
.append("circle")
.attr("r", cellSize / 2)
.attr("fill", "white")
.attr("stroke", "black");
group
.append("text")
.attr("alignment-baseline", "middle")
.attr("text-anchor", "middle")
.text(grid.getCell(d));
const degreeSize = cellSize * 0.5,
dr = degreeSize / 2,
dx = ((cellSize / 2) * Math.sqrt(2)) / 2;
const degreeGroup = group
.append("g")
.attr("class", "degree")
.attr("transform", `translate(${dx},${-dx})`)
.style("visibility", "hidden");
degreeGroup.append("circle").attr("r", dr).attr("fill", "black");
degreeGroup
.append("text")
.attr("alignment-baseline", "middle")
.attr("text-anchor", "middle")
.text("R")
.style("fill", "white")
.style("font-size", `60%`);
});
return svg;
}