chart = {
const svg = d3.create("svg").attr('width', width);
svg
.selectAll("rect")
.data(bars)
.join("rect")
.attr("fill", d => color(d._.name))
.attr("x", d => d.pos * size + margin.left)
.attr("y", 0)
.attr("width", d => d.size * size)
.attr("height", barHeight)
.append("title")
.text(d => `${d._.name}: ${d._.value.toLocaleString()}`);
let has = { above: false, below: false };
svg
.append("g")
.attr(
"font-family",
"-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji"
)
.attr("font-size", 12)
.attr("text-anchor", "middle")
.selectAll("text")
.data(bars.filter(d => !d._.hideLabel))
.join("text")
.call(text =>
text
.append("tspan")
.attr("y", "-0.4em")
.attr("font-weight", "bold")
.attr("class", "name-span")
.text(d => d._.name)
)
.call(text =>
text
.append("tspan")
.attr("x", 0)
.attr("y", "0.7em")
.attr("fill-opacity", 0.7)
.attr("class", "value-span")
.text(d => d._.value.toLocaleString())
)
.each(function(d, i) {
const nameSpan = this.querySelector('.name-span');
const valueSpan = this.querySelector('.value-span');
const nameLength = getLength(nameSpan);
const valueLength = getLength(valueSpan);
const textWidth = Math.max(nameLength, valueLength);
const x = (d.pos + d.size / 2) * size + margin.left;
let y = barHeight / 2;
const barIsDark = isDark(color(d._.name));
if (textWidth > d.size * size) {
const orientation = i % 2 === 0 ? 'below' : 'above';
insertIndicator(this, x, {
orientation,
barIsDark,
showInnerLine: d.size * size > 2
});
if (orientation === 'below') {
has.below = true;
y = barHeight + 30;
} else {
has.above = true;
y = -25;
}
} else {
if (barIsDark) {
this.setAttribute('fill', 'white');
}
this.setAttribute('y', barHeight);
}
this.setAttribute('transform', `translate(${x}, ${y})`);
adjustText(nameSpan, nameLength, x);
adjustText(valueSpan, valueLength, x);
});
svg.attr("viewBox", [
0,
(has.above ? -40 : 0) - margin.top,
width,
barHeight +
margin.top +
(has.above ? 40 : 0) +
(has.below ? 40 : 0) +
margin.bottom
]);
return svg.node();
}