(Proposed solution) Multiline x-axis labels interfere with the bottom legend
- Dominant language
- JavaScript
- Stars
- 9.3k
- Forks
- 1.4k
- Avg merge
- 6d 16h
- Merged PRs (30d)
- 1
Description
I'd like to propose a fix that would handle the mess that emerges when one is having multiline labels on the x-axis while having the legend positioned at the bottom. _(which happens at least with the newest Chrome)_
**The problem:** _(don't mind the labels repeating - it's just to make them longer)_

After a few hours of figuring out how to do this I came up with a rather simplified and **_naive solution**_, that consists of 4 actual changes to the c3.js file:
Step 1: **c3.js, lines 128 - 132**
```
$$.currentMaxTickWidths = {
x: 0,
y: 0,
y2: 0
};
```
...replaced with...
```
$$.currentMaxTickWidths = $$.currentMaxTickHeights = {
x: 0,
y: 0,
y2: 0
};
```
#
Step 2: **c3.js, line 345**
```
xAxisHeight = config.axis_rotated || hasArc ? 0 : $$.getHorizontalAxisHeight('x'),
```
...replaced with...
```
xAxisHeight = config.axis_rotated || hasArc ? 0 : $$.getHorizontalAxisHeight('x') + $$.getMaxTickHeight('x', true),
```
#
Step 3: **c3.js, insert new method after the body of `c3_chart_internal_fn.getMaxTickWidth` method**
```
c3_chart_internal_fn.getMaxTickHeight = function (id, withoutRecompute) {
var $$ = this, config = $$.config,
maxHeight = 0, targetsToShow, scale, axis, body, svg;
if (withoutRecompute && $$.currentMaxTickHeights[id]) {
return $$.currentMaxTickHeights[id];
}
if ($$.svg) {
targetsToShow = $$.filterTargetsToShow($$.data.targets);
if (id === 'y') {
scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
axis = $$.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues);
} else if (id === 'y2') {
scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
axis = $$.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues);
} else {
scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
axis = $$.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues);
$$.updateXAxisTickValues(targetsToShow, axis);
}
body = this.d3.select('body').classed('c3', true);
svg = body.append('svg').style('visibility', 'hidden').style('height', 0);
svg.append('g').call(axis).each(function () {
$$.d3.select(this).selectAll('text tspan').each(function () {
var box = this.getBoundingClientRect();
if (box.height >= 0 && maxHeight < box.height) { maxHeight = box.height; }
});
});
// TODO: time lag to get maxHeight
window.setTimeout(function () {
svg.remove();
}, 100);
body.classed('c3', false);
}
$$.currentMaxTickHeights[id] = maxHeight <= 0 ? $$.currentMaxTickHeights[id] : maxHeight;
return $$.currentMaxTickHeights[id];
};
```
#
Step 4: **c3.js, remove lines 2624 - 2627**
```
// Calculate x axis height when tick rotated
if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
h = $$.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
}
```
#
**Results:**
_Solved the original problem:_

_Problem with rotated labels:_

_Solved problem with rotated labels:_

I am aware of this solution being quite naive :) ..but for the time being it fixes the problem I faced with long multiline tick labels on the x-axis, so - I wanted to share this and maybe offer this as a basis for the proper solution to be implemented in the official code. :cat2:
*_EDIT: I just found out the solution above works only in Chrome (41), not in Firefox or IE. *_
Contributor guide
Assessment
This issue has not been assessed yet.