c3 icon indicating copy to clipboard operation
c3 copied to clipboard

sub-bar label position in stacked horizontal bar chart

Open bogenpirat opened this issue 7 years ago • 2 comments

hey there,

i'm trying to create a stacked bar chart with labels' positions configured for each segment.

i have a jsbin here.

this is what it looks like now:

image

my ideal solution would be to have the sub-bar's respective labels aligned:

  • on the leftmost boundary of the leftmost sub-bar,
  • on the rightmost boundary of the rightmost sub-bar,
  • centered for the sub-bars in between

image

but i'd also be happy just having the labels centered inside each sub-bar.

i've gone through the reference material as well as examples and not found any indication that c3 has specialized API for positioning sub-bar labels.

can this be accomplished with some workaround?

thanks in advance.

bogenpirat avatar Jun 18 '17 13:06 bogenpirat

for the record, here's a really dirty workaround for this particular situation making use of onrendered, centering the text per sub-bar. should be easy to extend for the left/right requirement.

onrendered: function () {
	var centers = [];
	var widths = [];
	d3.selectAll(".c3-chart-bars .c3-target")[0].forEach(function(el) {
		var bbox = el.getBBox();
		centers.push(bbox.width/2 + bbox.x);
	});
	
	var i = 0;
	d3.selectAll(".c3-chart-text.c3-target")[0].forEach(function(el) {
		var bbox = el.getBBox();
		var newCenter = centers[i++];
		
		el.querySelector("text").setAttribute("text-anchor", "middle");
		el.setAttribute("transform", "translate(-" + (bbox.x - newCenter + bbox.width/2) + ",0)");
	});
}

bogenpirat avatar Jun 20 '17 09:06 bogenpirat

My solution required me going into the C3.js library and making changes What I did was add another config property "labelCentered" and if that is set to true then center the labels. Any horizontal chart will work, stacked or regular.

` ChartInternal.prototype.getXForText = function (points, d, textElement) { var $$ = this, box = getBBox(textElement), xPos, padding; var config = $$.config;

    if ($$.config.axis_rotated) {
        padding = $$.isBarType(d) ? 4 : 6;
        if (config.labelCentered) {
            var center = (points[1][1] - points[0][1]) / 2;
            var newPadding = (center <= padding ? padding : 0) - box.width / 2;
            var totalLeft = center + newPadding + points[0][1] > box.width ? center + newPadding + points[0][1] : padding;
            xPos = totalLeft * (d.value < 0 ? -1 : 1)
        } else {
            xPos = points[2][1] + padding * (d.value < 0 ? -1 : 1);
        }
    } else {
        xPos = $$.hasType('bar') ? (points[2][0] + points[0][0]) / 2 : points[0][0];
    } // show labels regardless of the domain if value is null


    if (d.value === null) {
        if (xPos > $$.width) {
            xPos = $$.width - box.width;
        } else if (xPos < 0) {
            xPos = 4;
        }
    }

    return xPos;
};

`

abivelj avatar Mar 26 '20 03:03 abivelj