chart = {
const svg = d3.select(DOM.svg(width, height));
const data = [
{frac: 0, prerequisites: [0, 0, 0]},
{frac: 0, prerequisites: [1, 1, 1, 0]},
{frac: 60, prerequisites: [1, 1]},
{frac: 100, prerequisites: [1, 1, 1]},
].map((obj, i) => ({...obj, color: d3.hsl(d3.schemeCategory10[i])}));
const [w, h, r] = [200, 80, 8];
const dr = (i, l) => (i / 3 - 0.5) * (h - 2 * r)
svg.selectAll('g').data(data).join('g')
.attr('transform', (d, i) => {
const dx = (Math.floor(i / 3) + 1) * width / 3 - w / 2;
const dy = (i % 3 + 1) * height / 4;
return `translate(${dx},${dy})`;
})
.call(s => s.selectAll('rect').data(d => ([
{width: w, color: d.color.brighter(1.4), stroke: d.color},
{width: d.frac / 100 * w, color: d.color, stroke: d.color},
])).join('rect')
.attr('width', d => d.width)
.attr('height', h)
.attr('y', -h/2)
.attr('rx', 8)
.attr('stroke', d => d.stroke)
.attr('stroke-width', 3)
.attr('fill', d => d.color)
)
.call(s => s.selectAll('circle')
.data(d => (d.prerequisites.map((state, i, arr) => ({
state: state ? 'complete' : 'incomplete',
color: d.color,
x: - 2*r,
y: dr(i, arr.length),
}))))
.join('circle')
.attr('r', r)
.attr('stroke-width', 1.4)
.attr('stroke', d => d.color)
.attr('fill', d => d.state === 'incomplete' ? d3.hsl(d.color).brighter(1.4) : d.color)
.attr('cx', d => d.x)
.attr('cy', d => d.y)
)
return svg.node()
}