surveyCompareBars = function(data, labelCol, rowCols, rowLabels, annotation ) {
const pctFormat = d3.format(".0%")
const nested = rowCols.map((col, ci) => {
const label = rowLabels[ci];
const total = d3.sum(data, d => d[col])
const values = data.map(d => ({
label: d[labelCol],
value: d[col],
ratio: d[col] / total
}))
return {
label, data: values
}
});
const gridColumns = width < 500 ? "75px 1fr" : "160px 1fr"
const color = d3.scaleOrdinal()
.domain(d3.range(data.length))
.range(d3.quantize(t => d3.interpolateBlues((1 - t) * 0.6 + 0.4), data.length));
const container = d3.create("div")
.style("display", "flex")
.style("max-width", "640px")
.style("flex-direction", "column")
.style("gap", "4px")
.style("font-family", "var(--sans-serif)")
.style("font-size", "13px")
.style("line-height", "13px")
const header = container.append("div")
.style("display", "grid")
.style("grid-template-columns", gridColumns)
.style("gap", "20px")
header.append("div")
const barsHeader = header.append("div")
.style("display", "flex")
.style("align-items", "flex-end")
barsHeader.selectAll(".bars-header")
.data(nested[0].data).join("div")
.attr("class", "bars-header")
.style("width", d => d.ratio * 100 + "%")
.style("border-left", "solid 1px #ddd")
.append("div")
.style("margin", "0px 0 6px 6px")
.text(d => d.label)
const question = container.selectAll(".question")
.data(nested).join("div")
.attr("class", "question")
.style("display", "grid")
.style("grid-template-columns", gridColumns)
.style("gap", "20px")
.style("align-items", "center")
question.append("div")
.style("text-overflow", "ellipsis")
.style("white-space", "nowrap")
.style("overflow", "hidden")
.text(d => d.label)
const bars = question.append("div")
.style("display", "flex")
.style("border-radius", "5px")
.style("align-items", "center")
.style("overflow", "hidden")
const bar = bars.selectAll("div")
.data(d => d.data).join("div")
.style("background", (d, i) => color(i))
.style("border-left", "solid 1px rgba(255, 255, 255, 0.6)")
.style("width", d => d.ratio * 100 + "%")
.style("color", "rgba(255, 255, 255, 1.0)")
.style("line-height", "28px")
.style("font-weight", "bold")
.style("text-overflow", "ellipsis")
.style("white-space", "nowrap")
.style("overflow", "hidden")
.style("padding", "0 0 0 8px")
.style("box-sizing", "border-box")
.text(d => pctFormat(d.ratio))
const annotations = container.append("div")
.style("display", "grid")
.style("font-family", "var(--serif)")
.style("font-size", "14px")
.style("line-height", "1.4em")
.style("color", "#666")
.style("grid-template-columns", gridColumns)
.style("gap", "20px")
annotations.append("div")
const a = annotations.append("div").style("display", "flex");
const swoopy = a.append("svg")
.attr("width", 30)
.attr("height", 35)
.style("margin", "4px 4px")
swoopy.append("path")
.attr("stroke", "#aaa")
.attr("fill", "none")
.attr("d", `
M 25 18 C 10 18, 10 10, 10 0
M 6 4 L 10 0 L 14 4
`)
a.append("div")
.style("max-width", "250px")
.style("font-style", "italic")
.style("line-height", "1.5em")
.style("margin", "10px 0 0 0")
.text(annotation)
return container.node()
}