There are a few ways to control padding between scales/legends in chart.js (some official ways documented in the docs and some "hacky" ways described elsewhere). The problem is, there just isn't a way to use the existing configuration options to control padding through out the chart (left scale, bottom scale, top scale...or bottom of legend, etc.).
Fortunately, because of the flexible chart.js interfaces (and because we can create new scale types, etc.), it is still possible to control the padding without too much fuss. Let me explain the way to add left, top, and bottom padding and then provide a working example at the end very end (skip ahead if you so desire).
Left Padding
This one is easy. There is a documented option to control this. Just set the scales.yAxes.ticks.padding
option to whatever value you want. Here is an example.
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
padding: 25,
}
}]
}
Top Padding (or Legend Padding)
There is no option to control this so we have to build it in. I built it in by creating a new Legend object and overwriting the afterFit()
function that uses a paddingBottom
option set on the options object. This isn't too difficult but requires a round around way to do it. Here is the relevant code.
function getBoxWidth(labelOpts, fontSize) {
return labelOpts.usePointStyle ?
fontSize * Math.SQRT2 :
labelOpts.boxWidth;
};
Chart.NewLegend = Chart.Legend.extend({
afterFit: function() {
this.height = this.height + this.options.paddingBottom;
},
});
function createNewLegendAndAttach(chartInstance, legendOpts) {
var legend = new Chart.NewLegend({
ctx: chartInstance.chart.ctx,
options: legendOpts,
chart: chartInstance
});
if (chartInstance.legend) {
Chart.layoutService.removeBox(chartInstance, chartInstance.legend);
delete chartInstance.newLegend;
}
chartInstance.newLegend = legend;
Chart.layoutService.addBox(chartInstance, legend);
}
// Register the legend plugin
Chart.plugins.register({
beforeInit: function(chartInstance) {
var legendOpts = chartInstance.options.legend;
if (legendOpts) {
createNewLegendAndAttach(chartInstance, legendOpts);
}
},
beforeUpdate: function(chartInstance) {
var legendOpts = chartInstance.options.legend;
if (legendOpts) {
legendOpts = Chart.helpers.configMerge(Chart.defaults.global.legend, legendOpts);
if (chartInstance.newLegend) {
chartInstance.newLegend.options = legendOpts;
} else {
createNewLegendAndAttach(chartInstance, legendOpts);
}
} else {
Chart.layoutService.removeBox(chartInstance, chartInstance.newLegend);
delete chartInstance.newLegend;
}
},
afterEvent: function(chartInstance, e) {
var legend = chartInstance.newLegend;
if (legend) {
legend.handleEvent(e);
}
}
});
Bottom Padding
There is also no option to control this, so we have to also build it in. Since we are dealing with a scale here, the best way to do this is extending the 'category' scale and add logic to handle a scale paddingTop
option. After reading through the source, we need to overwrite the draw()
function to do this. Here is the relevant code (see my example for the full implementation).
// ...
if (isHorizontal) {
if (options.position === 'bottom') {
// bottom
textBaseline = !isRotated? 'top':'middle';
textAlign = !isRotated? 'center': 'right';
labelY = me.top + tl + me.options.paddingTop;
} else {
// top
textBaseline = !isRotated? 'bottom':'middle';
textAlign = !isRotated? 'center': 'left';
labelY = me.bottom - tl;
}
}
// ...
Here is a codepen example showing all this put together.