function capsuleBar (_data, {
barCount = 100,
roundTo = 100,
label = 'label',
value_one = 'female',
value_two = 'male',
labelKey = 'label',
pairFill = ['#0b3536', '#0098d8'],
stroke_width = 10,
barWidth = 50,
barPadding = 2.6,
margin = {left: 70, top: 20, right: 30, bottom: 40}
} = {}) {
const data = _data.map(d => {
const obj = {...d};
obj.total = barCountNum(d[value_one] + d[value_two], roundTo);
obj.value_one_bars = barCountNum(d[value_one], roundTo);
return obj
})
const max = d3.max(data.map(d => d.total))
const height = max * (stroke_width * 1.4);
const width = (barWidth * barPadding) * data.length;
const w = width + (margin.left + margin.right);
const h = height + (margin.top + margin.bottom);
const yScale = d3.scaleLinear()
.domain([0, max])
.range([height, margin.top]);
const xScale = d3.scaleLinear()
.domain([0, data.length])
.range([margin.left, w])
const svg = DOM.svg(w, h);
const sel = d3.select(svg);
const join = sel.selectAll('g')
.data(data)
.join('g')
.attr('transform', (d, i) => {
return `translate(${xScale(i)}, ${margin.top})`
});
join.selectAll('line')
.data(d => d3.range(d.total).map(() => d.value_one_bars))
.join('line')
.attr('y1', (d, i) => yScale(i))
.attr('y2', (d, i) => yScale(i))
.attr('x1', 0)
.attr('x2', barWidth)
.attr('stroke-width', stroke_width)
.attr('stroke-linecap', 'round')
.attr('stroke', (value_one_bars, i) => {
if ((i + 1) <= value_one_bars) {
return pairFill[0]
} else {
return pairFill[1]
}
})
join.append('text')
.attr('x', barWidth/2)
.attr('y', height + margin.top + 8)
.attr('font-size', '11px')
.attr('text-anchor', 'middle')
.attr('fill', '#454545')
.text(d => d[label])
join.append('line')
.attr('y1', d => yScale(d.value_one_bars - 1) - stroke_width/2 -1.5)
.attr('y2', d => yScale(d.value_one_bars - 1) - stroke_width/2 -1.5)
.attr('x1', -15)
.attr('x2', barWidth + 5)
.attr('stroke', pairFill[0])
.attr('stroke-dasharray', '1 1')
.attr('stroke-width', '1px')
join.append('text')
.attr('x', -20)
.attr('y', d => yScale(d.value_one_bars - 1) - 3)
.attr('font-size', '14px')
.attr('text-anchor', 'end')
.attr('fill', pairFill[0])
.text(d => calcPctVal1(d[value_one], d[value_two]) + '%')
function barCountNum (value) {
return roundNearestX(value) / barCount;
}
function roundNearestX (num, x = 100) {
return Math.round(num / x) * x;
}
function calcPctVal1 (val1, val2) {
const total = val1 + val2
return Math.round((val1 / total) * 100);
}
return svg;
}