function chart(nodes, accessor) {
const height = width;
var w = width - margin.left - margin.right;
var h = width - margin.top - margin.bottom;
const ids = nodes.map(d => d.id),
matrix = ids.map(source =>
ids.map(target => ({ source, target, val: accessor({ source, target }) }))
);
function colored(d) {
const val = d.val;
if (val === "UNAVAILABLE") return "lime";
if (val === "NA") return "#ccc";
if (d.source == d.target) return "#333";
if (+val > 0) return color(+val);
return "white";
}
var x = d3
.scaleBand()
.rangeRound([0, w])
.paddingInner(0.1)
.align(0)
.domain(ids);
var svgDOM = d3
.select(DOM.svg(width, height))
.attr("class", "matrixdiagram")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom);
svgDOM.append("defs").html(css);
var svg = svgDOM.append("g");
var row = svg
.selectAll("g.row")
.data(matrix)
.enter()
.append("g")
.attr("class", "row")
.attr("transform", d => `translate(0,${x(d[0].source)})`)
.each(makeRow);
row
.append("text")
.attr("class", "label")
.attr("x", -4)
.attr("y", x.bandwidth() / 2)
.attr("dy", "0.32em")
.text(d => d[0].source);
var column = svg
.selectAll("g.column")
.data(matrix)
.enter()
.append("text")
.attr("class", "column label")
.attr("transform", d => `translate(${x(d[0].source)},0)rotate(-90)`)
.attr("x", 4)
.attr("y", x.bandwidth() / 2)
.attr("dy", "0.32em")
.text(d => d[0].source);
function makeRow(rowData) {
var cell = d3
.select(this)
.selectAll("rect")
.data(rowData)
.enter()
.append("rect")
.attr("x", d => x(d.target))
.attr("width", x.bandwidth())
.attr("height", x.bandwidth())
.style("fill-opacity", 1)
.style("fill", colored)
.on("mouseover", d => {
row
.filter(e => e[0].source === d.source)
.style("fill", "#d62333")
.style("font-weight", "bold");
column
.filter(e => e[0].source === d.target)
.style("fill", "#d62333")
.style("font-weight", "bold");
})
.on("mouseout", () => {
row.style("fill", null).style("font-weight", null);
column.style("fill", null).style("font-weight", null);
});
cell
.append("title")
.text(d =>
d.source === d.target
? d.source
: `${d.source} ↔︎ ${d.target} (${d.val})`
);
}
const zoom = d3
.zoom()
.on("zoom", ({ transform }) => svg.attr("transform", transform));
return svgDOM
.call(zoom)
.call(zoom.transform, d3.zoomIdentity.translate(margin.left, margin.top))
.node();
}