Chart.js - 增加图例和图表之间的间距

57
我有一个条形图,在其中绘制了3条垂直线,每条线都有其自己的标签。我希望这些标签出现在y轴上方(例如在30%线条之上),但在图例下方。我无法找到如何增加顶部图例和图表之间的空间,以便我可以让我的垂直线标签(15、24和33)不接触图表本身,但在图例下方。有什么想法吗?

Example Chart

14个回答

45

如果您想增加所有图表中的间距,您可以在创建之前添加以下代码:

Chart.Legend.prototype.afterFit = function() {
    this.height = this.height + 50;
};

当然,我没有尝试过,但我认为你可以改变它(或在此之前复制原始图表对象,以保留原始填充)。

再见,


4
非常好,完全符合我的需求,谢谢! - Steve Bauman
1
我在2年前发布了这个问题,如果图例在下方,我认为有一个技巧可以解决。 - Dorian Maliszewski
@DorianMaliszewski 哦不错,你有链接吗?我现在也正在尝试解决这个问题... - A Friend
1
@DorianMaliszewski 有更新版本吗?虽然我对chartjs非常陌生,但它似乎无法与3.9.1一起使用。 - user19881049
这在较新版本中已经完全不起作用了。 - Pepe Alvarez

36

如果您想在应用程序中仅对一些图表应用图例下方填充:

ChartJS >= 2.1.0

Chart.plugins.register({
  id: 'paddingBelowLegends',
  beforeInit: function(chart, options) {
    chart.legend.afterFit = function() {
      this.height = this.height + 50;
    };
  }
});

// ----------------------------------
// disable the plugin only for charts
// where you DO NOT WANT the padding
// ----------------------------------

// for raw ChartJS use:
var chart = new Chart(ctx, {
  config: {
    plugins: {
      paddingBelowLegends: false
    }
  }
});

// for angular-chartjs:
$scope.myChart.options.plugins = { paddingBelowLegends: false }
// then in template:
// <canvas class="chart ..." chart-options="myChart.options" ... />

ChartJS >= 2.5.0

支持每种图表的特定插件,可以实现以下操作:

var chart = new Chart(ctx, {
  plugins: [{
    beforeInit: function(chart, options) {
      chart.legend.afterFit = function() {
        this.height = this.height + 50;
      };
    }
  }]
});

请参见 ChartJS文档,并受到此答案的启发


22

如果有人想知道为什么在Chart.js 3.3.0中afterFit解决方案不起作用,那是因为afterFit函数已从图例插件中删除。

如果您想通过利用fit函数使其正常工作,可以尝试这个hacky解决方案/解决方法:

const plugin = {
  beforeInit(chart) {
    // Get a reference to the original fit function
    const originalFit = chart.legend.fit;

    // Override the fit function
    chart.legend.fit = function fit() {
      // Call the original function and bind scope in order to use `this` correctly inside it
      originalFit.bind(chart.legend)();
      // Change the height as suggested in other answers
      this.height += 15;
    }
  }
}

我知道这不是一个理想的解决方案,但在我们有原生支持这个图例填充的之前,恐怕现在这就是我们能够做到的最好了。


20

很遗憾,因为没有配置选项来处理这个问题,您能够实现所需的结果的唯一方法是扩展Chart.Legend并实现afterFit()回调函数。

这里有一个快速的codepen示例,展示如何做到这一点。要更改间距,只需更改第9行中的值(当前设置为50)。此外,这当然仅适用于顶部的图例。希望这个示例足够清晰,让您在需要将图例移动到其他位置时进行修改。


1
我理解你在这里做的基本概念,但我自己永远没有机会。谢谢。这个完美地运行! - Bryan Lewis
好的,也许你可以帮忙解决一个小问题。这个解决方案看起来很完美,但我不能再点击图例中的单个项目来切换数据了。有什么想法吗? - Bryan Lewis
@BryanLewis 在 CodePen 示例中,我可以轻松点击标注项而不会出现任何问题(您在 CodePen 中无法正常工作吗?)。 如果您正在谈论特定实现(而非 CodePen 示例),请确保复制我的示例中的第 13-60 行代码(这是使单击行为正确的原因)。 - jordanwillis
你的 CodePen 示例可以运行,我已经复制了所有内容,但是它对我仍然不起作用。我认为我的 chart.js 代码中可能有其他干扰因素。我会进一步测试。谢谢。 - Bryan Lewis
1
@jordanwillis 我尝试了你的CodePen示例。它可以工作,但在我的情况下,图例在应用后不再居中对齐。图例位于顶部位置。 - Sonali
当你说居中对齐时,你是否意味着图例位置设置为左侧?如果是这样,那么你需要调整新图例中的“宽度”属性而不是“高度”。如果这不是你的意思,那么我不确定你所说的居中对齐是什么意思。 - jordanwillis

9
这篇文章在我研究了两天之后帮助了我。
Chart.Legend.prototype.afterFit = function() {
    this.height = this.height + 50;
};

请在module.ts文件中更新此内容。


3
同上。 - Ringo
我已经添加了在 Angular 项目中应该更新的位置。 - Sahil Ralkar

8

我正在使用react-chartjs-2(但这只是一个端口,并使用相同的配置对象),我能够通过更改嵌套在图例配置中的标签配置来实现这一点:

chartOptions = {
  legend: {
    labels: {
      padding: 50 -> this one.
    }
  },

你可以在这里查看属性描述: https://www.chartjs.org/docs/latest/configuration/legend.html 希望这能有所帮助。

21
这会在多行图例项中添加一些填充,但不会明确在图例和图表之间添加空白。 - Ringo
另外,请注意路径为chart.options.plugins.legend.labels.padding。 - BurninLeo

2
我已经尝试了上述方法在我的react(react-chartjs-2)项目中,但没有成功。这里有一个不同的方法,即创建位于图表外部的自定义图例,因此您可以更好地控制它。
  1. 隐藏默认图例
  2. 使用任何ref方法获取图例对象。
  3. 循环并使用html和css制作自定义图例。
  4. 示例codesanbox
我知道OP不是关于reactjs组件的问题,但作为一个常见问题,这将有所帮助。
原始参考链接:Orginal reference

2
如果您想在应用程序中仅为某些图表应用图例下方的填充,请使用以下方法:

ChartJS >= 2.1.0

注意:请确保将其添加到plugins而不是options.plugins中。

Chart.plugins.register({
  id: 'paddingBelowLegends',
  beforeInit: function(chart, options) {
    chart.legend.afterFit = function() {
      this.height = this.height + 50;
    };
  }
});

// ----------------------------------
// disable the plugin only for charts
// where you DO NOT WANT the padding
// ----------------------------------

// for raw ChartJS use:
var chart = new Chart(ctx, {
  config: {
    plugins: {
      paddingBelowLegends: false
    }
  }
});

对于使用 react-chartjs-2 的 React 用户:

import { Line } from "react-chartjs-2";
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend } from "chart.js";
  ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend);
<Line
        data={{
          datasets: trendsData?.map((trend, idx) => ({
            type: "line",
            label: trend.domainName,
            data: trend.domainTrends.map(d => d.value),
            backgroundColor: getDomainColor(idx).backgroundColor,
            borderColor: getDomainColor(idx).color,
            pointRadius: 0,
            tension: 0.3
          })),
          labels: trendsData?.[0]?.domainTrends.map(d => d.date)
        }}
        options={{
          plugins: {
            legend: {
              display: true,
              align: "start",
              labels: {
                font: { size: 14 }
              }
            }
          }
        }}
        plugins={[
          {
            id: "increase-legend-spacing",
            beforeInit(chart) {
              // Get reference to the original fit function
              const originalFit = (chart.legend as any).fit;
              // Override the fit function
              (chart.legend as any).fit = function fit() {
                // Call original function and bind scope in order to use `this` correctly inside it
                originalFit.bind(chart.legend)();
                this.height += 20;
              };
            }
          }
        ]}
      />

1

对于ng2-charts@^3.1.0,按照这个答案进行操作即可,在此增加一步:

this.options.labels.padding = 40;
//this.height += 15;

或者使用title.padding配置(这将在图形下创建一个不可见的标题,因此有点hacky):
    plugins: {
      legend: {
        display: true,
        position: 'bottom',
        title: {
          display: true,
          padding: 10,
        },

Stackblitz


1
标题实际上添加了一些填充,但它位于Lexend框的正上方,即OP设置其图例的位置。 - Pepe Alvarez

1
如果使用react-chartjs-2并且想避免使用自定义插件,那么一个巧妙的解决方案是使用一个带有空标签的虚假x轴。
<Chart options={{
  scales: {
    x: {
      // Your real x-axis options
    },
    xTopPadding: {
      // Fake x-axis for padding
      position: 'top',
      labels: [''],
      grid: {
        drawOnChartArea: false,
        drawTicks: true,
        ticksWidth: 0,
        ticksLength: 0, // Increase ticksLength to increase the "padding"
      },
    }
  }
}} />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接