function stackedBar (data, {
height = 200,
barHeight = 100,
halfBarHeight = barHeight / 2,
f = d3.format('.1f'),
margin = {top: 20, right: 10, bottom: 20, left: 10},
w = width - margin.left - margin.right,
h = height * 0.66,
colors = ["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33"]
} = {}) {
const total = d3.sum(data, d => d.value);
console.info('total', total);
function groupDataFunc(data) {
const percent = d3.scaleLinear()
.domain([0, total])
.range([0, 100])
let cumulative = 0
const _data = data.map(d => {
cumulative += d.value
return {
value: d.value,
cumulative: cumulative - d.value,
label: d.label,
percent: percent(d.value)
}
}).filter(d => d.value > 0)
return _data
};
const groupData = groupDataFunc(data);
console.info('groupData', groupData);
const svg = DOM.svg(width, height);
const sel = d3.select(svg);
const xScale = d3.scaleLinear()
.domain([0, total])
.range([0, w]);
const join = sel.selectAll('g')
.data(groupData)
.join('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
join.append('rect')
.attr('class', 'rect-stacked')
.attr('x', d => xScale(d.cumulative))
.attr('y', h / 2 - halfBarHeight)
.attr('height', barHeight)
.attr('width', d => xScale(d.value))
.style('fill', (d, i) => colors[i]);
join.append('text')
.attr('class', 'text-value')
.attr('text-anchor', 'middle')
.attr('x', d => xScale(d.cumulative) + (xScale(d.value) / 2))
.attr('y', (h / 2) + 5)
.text(d => d.value);
join.append('text')
.attr('class', 'text-percent')
.attr('text-anchor', 'middle')
.attr('x', d => xScale(d.cumulative) + (xScale(d.value) / 2))
.attr('y', (h / 2) - (halfBarHeight * 1.1))
.text(d => f(d.percent) + ' %');
join.append('text')
.attr('class', 'text-label')
.attr('text-anchor', 'middle')
.attr('x', d => xScale(d.cumulative) + (xScale(d.value) / 2))
.attr('y', (h / 2) + (halfBarHeight * 1.1) + 20)
.style('fill', (d, i) => colors[i])
.text(d => d.label);
return svg;
}