chartjs - 图表区域的顶部和底部填充

时间:2017-03-18 05:31:18

标签: chart.js

我需要在图表区域上方和下方添加更多空间(靠近顶部和底部比例)。 似乎只能向垂直轴添加填充。 我根据文件禁用了刻度线: http://www.chartjs.org/docs/#scales

Chart.defaults.scale.gridLines.drawTicks = false;

chartjs图表区域顶部和底部填充图像:

此外,我可以添加填充到垂直轴刻度标签(刻度)

Chart.defaults.scale.ticks.padding = 15;

如何在顶部刻度上方和底部(零)刻度上方添加填充?

3 个答案:

答案 0 :(得分:7)

有几种方法可以控制chart.js中的尺度/图例之间的填充(文档中记录的一些官方方式和其他地方描述的一些“hacky”方式)。问题是,没有办法使用现有的配置选项来控制图表中的填充(左侧比例,底部比例,顶部比例......或图例底部等)。

幸运的是,由于灵活的chart.js接口(并且因为我们可以创建新的缩放类型等),所以仍然可以毫不费力地控制填充。让我解释添加左,上和下填充的方法,然后在最后提供一个工作示例(如果你愿意,可以跳过)。

左边填充

这个很容易。有一个记录的选项来控制它。只需将scales.yAxes.ticks.padding选项设置为您想要的任何值即可。这是一个例子。

scales: {
  yAxes: [{
    ticks: {
      beginAtZero: true,
      padding: 25,
    }
  }]
}

顶部填充(或图例填充)

没有选项来控制它,所以我们必须构建它。我通过创建一个新的Legend对象并覆盖afterFit()函数来构建它,该函数使用选项上设置的paddingBottom选项宾语。这不是太难,但需要四处走动才能做到这一点。这是相关的代码。

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);
    }
  }
});

底部填充

也没有选项来控制它,因此我们也必须构建它。由于我们在这里处理一个比例,最好的方法是扩展'类别'比例并添加逻辑来处理比例paddingTop选项。阅读完源代码后,我们需要覆盖draw()函数来执行此操作。以下是相关代码(请参阅我的完整实现示例)。

// ...
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;
  }
}
// ...

这是codepen example,显示所有这些放在一起。

答案 1 :(得分:3)

编辑:这不提供图表内的提供填充(这是此问题最初的内容),而是在图表周围添加填充

对于那些仍在寻找谷歌搜索结果的人(比如我),它似乎已在以后的版本中得到解决:https://www.chartjs.org/docs/latest/configuration/layout.html#padding

let chart = new Chart(ctx, {
  type: 'line',
  data: data,
  options: {
    layout: {
        padding: {
            left: 50,
            right: 0,
            top: 0,
            bottom: 0
        }
    }
  }
});

答案 2 :(得分:0)

这不会在图表和图例之间添加填充,但上面的代码似乎不再适用于 Chart.js v3 及更高版本。这是一个解决方法插件,它填充 y 轴以确保标签(仅使用 chartjs-plugin-datalabels 检查)落在图表内。

var pluginAutoAdjustRangeY = {
   id: 'autoAdjustRangeY',
   beforeInit: function(chartInstance) {
      var legendOpts = chartInstance.options.legend;
      if (legendOpts) {
         chartInstance.legend.afterFit = function(){
            var max = 0;
            var min = 0;

            var datasets = chartInstance.data.datasets.length
            for(let i = 0; i < datasets; i++){
               var points = chartInstance.data.datasets[i].data.length
               for(let p = 0; p < points; p++){
                  var v = parseFloat(chartInstance.data.datasets[i].data[p]);
                  if(v > max) max = v; 
                  if(v < min) min = v; 
               }           
            }
           
            var range = parseInt((max - min) * ((chartInstance.options.legend.padding) || 0));
            chartInstance.options.scales.y.max = parseInt(max + range);
            if(min !== 0) chartInstance.options.scales.y.min = parseInt(min - range);
         }
      }
   },   
   beforeLayout: function(chartInstance) { //2
      if(chartInstance.options.legend){
         if(chartInstance.legend.afterFit){
            chartInstance.legend.afterFit();
         }
      }
   },
};

并且可以这样使用:

options: {
   legend: {
      padding: 0.15,  //percentage of Y range to pad ends of axis
   }
}