如何使用 Chart.js 在圆环图中添加文本?

IT技术 javascript chart.js
2021-01-19 17:38:30

如何在圆环图中呈现文本,我正在使用ChartJs

6个回答

其他答案都没有根据文本量和甜甜圈的大小调整文本大小。这是一个小脚本,您可以使用它在中间动态放置任意数量的文本,它会自动调整其大小。

示例: http : //jsfiddle.net/kdvuxbtj/

中间带有动态文本的甜甜圈

它将需要甜甜圈中适合甜甜圈大小的任意数量的文本。为避免接触边缘,您可以将侧边距设置为圆内直径的百分比。如果您不设置它,它将默认为 20。您还可以设置颜色、字体和文本。该插件负责其余的工作。

插件代码将以 30px 的基本字体大小开始。从那里它会检查文本的宽度并将其与圆的半径进行比较,并根据圆/文本宽度比调整其大小。

它的默认最小字体大小为 20 像素。如果文本超出最小字体大小的边界,它将环绕文本。环绕文本时的默认行高为 25px,但您可以更改它。如果将默认最小字体大小设置为 false,文本将变得无限小且不会换行。

它还有一个默认的最大字体大小为 75px,以防文本不够并且字体太大。

这是插件代码

Chart.pluginService.register({
  beforeDraw: function(chart) {
    if (chart.config.options.elements.center) {
      // Get ctx from string
      var ctx = chart.chart.ctx;

      // Get options from the center object in options
      var centerConfig = chart.config.options.elements.center;
      var fontStyle = centerConfig.fontStyle || 'Arial';
      var txt = centerConfig.text;
      var color = centerConfig.color || '#000';
      var maxFontSize = centerConfig.maxFontSize || 75;
      var sidePadding = centerConfig.sidePadding || 20;
      var sidePaddingCalculated = (sidePadding / 100) * (chart.innerRadius * 2)
      // Start with a base font of 30px
      ctx.font = "30px " + fontStyle;

      // Get the width of the string and also the width of the element minus 10 to give it 5px side padding
      var stringWidth = ctx.measureText(txt).width;
      var elementWidth = (chart.innerRadius * 2) - sidePaddingCalculated;

      // Find out how much the font can grow in width.
      var widthRatio = elementWidth / stringWidth;
      var newFontSize = Math.floor(30 * widthRatio);
      var elementHeight = (chart.innerRadius * 2);

      // Pick a new font size so it will not be larger than the height of label.
      var fontSizeToUse = Math.min(newFontSize, elementHeight, maxFontSize);
      var minFontSize = centerConfig.minFontSize;
      var lineHeight = centerConfig.lineHeight || 25;
      var wrapText = false;

      if (minFontSize === undefined) {
        minFontSize = 20;
      }

      if (minFontSize && fontSizeToUse < minFontSize) {
        fontSizeToUse = minFontSize;
        wrapText = true;
      }

      // Set font settings to draw it correctly.
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      var centerX = ((chart.chartArea.left + chart.chartArea.right) / 2);
      var centerY = ((chart.chartArea.top + chart.chartArea.bottom) / 2);
      ctx.font = fontSizeToUse + "px " + fontStyle;
      ctx.fillStyle = color;

      if (!wrapText) {
        ctx.fillText(txt, centerX, centerY);
        return;
      }

      var words = txt.split(' ');
      var line = '';
      var lines = [];

      // Break words up into multiple lines if necessary
      for (var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + ' ';
        var metrics = ctx.measureText(testLine);
        var testWidth = metrics.width;
        if (testWidth > elementWidth && n > 0) {
          lines.push(line);
          line = words[n] + ' ';
        } else {
          line = testLine;
        }
      }

      // Move the center up depending on line height and number of lines
      centerY -= (lines.length / 2) * lineHeight;

      for (var n = 0; n < lines.length; n++) {
        ctx.fillText(lines[n], centerX, centerY);
        centerY += lineHeight;
      }
      //Draw text in center
      ctx.fillText(line, centerX, centerY);
    }
  }
});

并且您在图表对象中使用以下选项

options: {
  elements: {
    center: {
      text: 'Red is 2/3 the total numbers',
      color: '#FF6384', // Default is #000000
      fontStyle: 'Arial', // Default is Arial
      sidePadding: 20, // Default is 20 (as a percentage)
      minFontSize: 20, // Default is 20 (in px), set to false and text will not wrap.
      lineHeight: 25 // Default is 25 (in px), used for when text wraps
    }
  }
}

信贷@Jenna斯隆与在此解决方案中使用的数学题。

可以将文本拆分为多行吗?我的文本有 6 个单词,并且在剪切块的边界之间溢出
2021-03-21 17:38:30
效果很好!当图例位于右侧或左侧时,大多数其他选项会中断。
2021-03-22 17:38:30
很棒的解决方案!
2021-03-24 17:38:30
优秀的答案。实际上最好的一个。如果您使用的是 webpack,只需导入 Chart 对象并在其上注册此插件。
2021-03-31 17:38:30
我更新了你的小提琴并添加了最大字体大小:jsfiddle.net/nkzyx50o/3059
2021-04-09 17:38:30

这是上述解决方案的清理和组合示例 - 响应式(尝试调整窗口大小),支持动画自对齐,支持工具提示

https://jsfiddle.net/cmyker/u6rr5moq/

Chart.types.Doughnut.extend({
    name: "DoughnutTextInside",
    showTooltip: function() {
        this.chart.ctx.save();
        Chart.types.Doughnut.prototype.showTooltip.apply(this, arguments);
        this.chart.ctx.restore();
    },
    draw: function() {
        Chart.types.Doughnut.prototype.draw.apply(this, arguments);

        var width = this.chart.width,
            height = this.chart.height;

        var fontSize = (height / 114).toFixed(2);
        this.chart.ctx.font = fontSize + "em Verdana";
        this.chart.ctx.textBaseline = "middle";

        var text = "82%",
            textX = Math.round((width - this.chart.ctx.measureText(text).width) / 2),
            textY = height / 2;

        this.chart.ctx.fillText(text, textX, textY);
    }
});

var data = [{
    value: 30,
    color: "#F7464A"
}, {
    value: 50,
    color: "#E2EAE9"
}, {
    value: 100,
    color: "#D4CCC5"
}, {
    value: 40,
    color: "#949FB1"
}, {
    value: 120,
    color: "#4D5360"
}];

var DoughnutTextInsideChart = new Chart($('#myChart')[0].getContext('2d')).DoughnutTextInside(data, {
    responsive: true
});
<html>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script>
<body>
    <canvas id="myChart"></canvas>
</body>
</html>

更新 17.06.16:

相同的功能,但对于 chart.js 版本 2:

https://jsfiddle.net/cmyker/ooxdL2vj/

var data = {
  labels: [
    "Red",
    "Blue",
    "Yellow"
  ],
  datasets: [
    {
      data: [300, 50, 100],
      backgroundColor: [
        "#FF6384",
        "#36A2EB",
        "#FFCE56"
      ],
      hoverBackgroundColor: [
        "#FF6384",
        "#36A2EB",
        "#FFCE56"
      ]
    }]
};

Chart.pluginService.register({
  beforeDraw: function(chart) {
    var width = chart.chart.width,
        height = chart.chart.height,
        ctx = chart.chart.ctx;

    ctx.restore();
    var fontSize = (height / 114).toFixed(2);
    ctx.font = fontSize + "em sans-serif";
    ctx.textBaseline = "middle";

    var text = "75%",
        textX = Math.round((width - ctx.measureText(text).width) / 2),
        textY = height / 2;

    ctx.fillText(text, textX, textY);
    ctx.save();
  }
});

var chart = new Chart(document.getElementById('myChart'), {
  type: 'doughnut',
  data: data,
  options: {
  	responsive: true,
    legend: {
      display: false
    }
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.6/Chart.bundle.js"></script>
<canvas id="myChart"></canvas>

@Cmyker CSS/HTML 解决方案可以提供帮助,但是当图表导出为 PNG 时它不会导出中心文本。 .
2021-03-13 17:38:30
如果通过提供新的数据参数来刷新图表,这将不断地一遍又一遍地覆盖文本
2021-04-02 17:38:30
此外,您可以使用 ctx.fillStyle = 'black'; 更改文本颜色。
2021-04-03 17:38:30
你有没有想出解决方案?
2021-04-11 17:38:30
我有Uncaught TypeError: Cannot read property 'extend' of undefined什么想法吗?
2021-04-12 17:38:30

您必须修改代码,如:在 chart.Doughnut.defaults

labelFontFamily : "Arial",
labelFontStyle : "normal",
labelFontSize : 24,
labelFontColor : "#666"

然后在功能上 drawPieSegments

ctx.fillText(data[0].value + "%", width/2 - 20, width/2, 200);

看到这个拉:https : //github.com/nnnick/Chart.js/pull/35

这是一个实现相同的小提琴http://jsfiddle.net/mayankcpdixit/6xV78/

@ArunC.B - 向下滚动
2021-03-17 17:38:30
还有其他人找不到这个 drawPieSegments 函数吗?
2021-03-23 17:38:30
值得一提的是它不适用于 v2。使用包含的 jsfiddle 代码以方便使用
2021-03-25 17:38:30
这仍然是解决方案吗?
2021-03-27 17:38:30
如何在新行中添加 %?这是支持的吗?
2021-03-30 17:38:30

我会避免修改chart.js 代码来实现这一点,因为使用常规CSS 和HTML 很容易。这是我的解决方案:

HTML:

<canvas id="productChart1" width="170"></canvas>
<div class="donut-inner">
    <h5>47 / 60 st</h5>
    <span>(30 / 25 st)</span>
</div>

CSS:

.donut-inner {
   margin-top: -100px;
   margin-bottom: 100px;
}
.donut-inner h5 {
   margin-bottom: 5px;
   margin-top: 0;
}
.donut-inner span {
   font-size: 12px;
}

输出如下所示:

在此处输入图片说明

@Mattias 这是一个不错的解决方案,但是当图表作为 PNG 下载时,中心文本不会被导出。
2021-04-03 17:38:30
@Massa 您是否尝试过针对各种分辨率使用媒体查询?或者修改我写的 css 以使用 % 而不是 px?
2021-04-05 17:38:30
为什么不?只需将@media-queries 添加到您的课程中即可。
2021-04-06 17:38:30
它对我不起作用,我使用的是响应方式,所以我不能使用固定值。:(
2021-04-06 17:38:30
@techie_28 有效点,没有考虑到这一点,因为问题根本没有提到出口。
2021-04-08 17:38:30

这也在我的最后工作......

<div style="width: 100px; height: 100px; float: left; position: relative;">
    <div
        style="width: 100%; height: 40px; position: absolute; top: 50%; left: 0; margin-top: -20px; line-height:19px; text-align: center; z-index: 999999999999999">
        99%<Br />
        Total
    </div>
    <canvas id="chart-area" width="100" height="100" />
</div>

在此处输入图片说明

你是我的哥们!我无法在 angularjs 中找到解决方案,也从来没有这样做过。惊人。
2021-03-16 17:38:30
@Amrik Singh 这确实是一个很好的解决方案,但如果将图表下载为 PNG 图像,则不会导出中心文本。
2021-03-22 17:38:30
可爱,快速和干净的修复
2021-03-22 17:38:30
不错的解决方案,它不需要太多麻烦。
2021-03-28 17:38:30
我使用了你的解决方案,因为它是最快的,而且它可以完成它的工作。谢谢!
2021-04-09 17:38:30