首页 文章

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

提问于
浏览
63

如何在圆环图中渲染文本,我正在使用ChartJs .

13 回答

  • 8

    @ rap-2-h和@Ztuons Ch 's answer doesn' t允许 showTooltips 选项处于活动状态,但您可以做的是在渲染图表的背后创建并叠加第二个 canvas 对象 .

    重要的部分是div中所需的样式以及canvas对象本身,以便它们在彼此之上呈现 .

    var data = [
        {value : 100, color : 'rgba(226,151,093,1)', highlight : 'rgba(226,151,093,0.75)', label : "Sector 1"},
        {value : 100, color : 'rgba(214,113,088,1)', highlight : 'rgba(214,113,088,0.75)', label : "Sector 2"},
        {value : 100, color : 'rgba(202,097,096,1)', highlight : 'rgba(202,097,096,0.75)', label : "Sector 3"}
    ]
    
    var options = { showTooltips : true };
         
    var total = 0;
    for (i = 0; i < data.length; i++) {
         total = total + data[i].value;
    }
    
    var chartCtx = $("#canvas").get(0).getContext("2d");
    var chart = new Chart(chartCtx).Doughnut(data, options);
    
    var textCtx = $("#text").get(0).getContext("2d");
    textCtx.textAlign = "center";
    textCtx.textBaseline = "middle";
    textCtx.font = "30px sans-serif";
    textCtx.fillText(total, 150, 150);
    
    <script src="https://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>
    <html>
    <body>
    <div style="position: relative; width:300px; height:300px;">
        <canvas id="text" 
                style="z-index: 1; 
                       position: absolute;
                       left: 0px; 
                       top: 0px;" 
                height="300" 
                width="300"></canvas>
        <canvas id="canvas" 
                style="z-index: 2; 
                       position: absolute;
                       left: 0px; 
                       top: 0px;" 
                height="300" 
                width="300"></canvas>
    </div>
    </body>
    </html>
    

    这是jsfiddle:https://jsfiddle.net/68vxqyak/1/

  • 0

    您必须修改代码,如: 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/实现相同的 .

  • 46

    没有其他答案根据文本的数量和甜甜圈的大小调整文本的大小 . 这是一个小脚本,您可以使用它在中间动态放置任意数量的文本,它将自动调整大小 . http://jsfiddle.net/nkzyx50o/

    Doughnut With Dynamic Text in the Middle

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

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

    这是插件代码

    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 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);
    
          //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;
    
          //Draw text in center
          ctx.fillText(txt, centerX, centerY);
        }
      }
    });
    

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

    options: {
      elements: {
          center: {
          text: 'Desktop',
          color: '#36A2EB', //Default black
          fontStyle: 'Helvetica', //Default Arial
          sidePadding: 15 //Default 20 (as a percentage)
        }
      }
    }
    

    感谢@Jenna Sloan以获得此解决方案中使用的数学方面的帮助 .

  • 2

    如果您希望它具有响应性,您可以使用具有相对/绝对定位的css . 此外,它可以轻松处理多线 .

    https://jsfiddle.net/mgyp0jkk/

    <div class="relative">
      <canvas id="myChart"></canvas>      
      <div class="absolute-center text-center">
        <p>Some text</p>
        <p>Some text</p>
      </div>
    </div>
    
  • 6

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

    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>
    

    UPDATE 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>
    
  • 11

    我会避免修改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;
    }
    

    输出如下:

    enter image description here

  • 13

    这也是我最终的工作......

    <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" />
    

    enter image description here

  • 30

    基于@ rap-2-h的答案,这里是使用Chart.js上的圆环图上的文字在仪表板中使用的代码 . 它具有动态字体大小的响应选项 .

    HTML:

    <div>text
    <canvas id="chart-area" width="300" height="300" style="border:1px solid"/><div>
    

    脚本:

    var doughnutData = [
                {
                    value: 100,
                    color:"#F7464A",
                    highlight: "#FF5A5E",
                    label: "Red"
                },
                {
                    value: 50,
                    color: "#CCCCCC",
                    highlight: "#5AD3D1",
                    label: "Green"
                }
            ];
    
    $(document).ready(function(){
      var ctx = $('#chart-area').get(0).getContext("2d");
    
      var myDoughnut = new Chart(ctx).Doughnut(doughnutData,{
         animation:true,
         responsive: true,
         showTooltips: false,
         percentageInnerCutout : 70,
         segmentShowStroke : false,
         onAnimationComplete: function() {
    
         var canvasWidthvar = $('#chart-area').width();
         var canvasHeight = $('#chart-area').height();
         //this constant base on canvasHeight / 2.8em
         var constant = 114;
         var fontsize = (canvasHeight/constant).toFixed(2);
         ctx.font=fontsize +"em Verdana";
         ctx.textBaseline="middle"; 
         var total = 0;
         $.each(doughnutData,function() {
           total += parseInt(this.value,10);
       });
      var tpercentage = ((doughnutData[0].value/total)*100).toFixed(2)+"%";
      var textWidth = ctx.measureText(tpercentage).width;
    
       var txtPosx = Math.round((canvasWidthvar - textWidth)/2);
        ctx.fillText(tpercentage, txtPosx, canvasHeight/2);
      }
     });
    });
    

    这里是示例code.try来调整窗口大小 . http://jsbin.com/wapono/13/edit

  • 25

    这是基于Cmyker对Chart.js 2的更新 . (发布为另一个答案,因为我还没有评论)

    当显示图例时,Chrome上的文本对齐存在问题,因为图表高度不包括此值,因此它未在中间正确对齐 . 通过在计算fontSize和textY时考虑到这一点来解决这个问题 .

    我计算了方法内的百分比而不是设定值,因为我在页面上有多个这样的值 . 假设您的图表只有2个值(否则是什么百分比?并且第一个是您要显示百分比的那个 . 我还有一堆其他图表,所以我检查type = donut . 我只用甜甜圈来显示百分比,所以它对我有用 .

    文字颜色似乎有点受打击和错过,这取决于事物的运行顺序等因此我在调整文本会改变颜色时遇到问题(在一种情况下黑色和原色之间,而在另一种情况下是二次色和白色)所以我“保存”现有的填充样式,绘制文本(以主数据的颜色),然后恢复旧的填充样式 . (似乎不需要保留旧的填充样式,但你永远不知道 . )

    https://jsfiddle.net/g733tj8h/

    Chart.pluginService.register({
      beforeDraw: function(chart) {
        var width = chart.chart.width,
            height = chart.chart.height,
            ctx = chart.chart.ctx,
            type = chart.config.type;
    
        if (type == 'doughnut')
        {
          var percent = Math.round((chart.config.data.datasets[0].data[0] * 100) /
                        (chart.config.data.datasets[0].data[0] +
                        chart.config.data.datasets[0].data[1]));
          var oldFill = ctx.fillStyle;
          var fontSize = ((height - chart.chartArea.top) / 100).toFixed(2);
    
          ctx.restore();
          ctx.font = fontSize + "em sans-serif";
          ctx.textBaseline = "middle"
    
          var text = percent + "%",
              textX = Math.round((width - ctx.measureText(text).width) / 2),
              textY = (height + chart.chartArea.top) / 2;
    
          ctx.fillStyle = chart.config.data.datasets[0].backgroundColor[0];
          ctx.fillText(text, textX, textY);
          ctx.fillStyle = oldFill;
          ctx.save();
        }
      }
    });
    
    var data = {
      labels: ["Red","Blue"],
      datasets: [
        {
          data: [300, 50],
          backgroundColor: ["#FF6384","#36A2EB"],
        }]
    };
    
    Chart.pluginService.register({
      beforeDraw: function(chart) {
        var width = chart.chart.width,
            height = chart.chart.height,
            ctx = chart.chart.ctx,
            type = chart.config.type;
    
        if (type == 'doughnut')
        {
        	var percent = Math.round((chart.config.data.datasets[0].data[0] * 100) /
                        (chart.config.data.datasets[0].data[0] +
                        chart.config.data.datasets[0].data[1]));
    			var oldFill = ctx.fillStyle;
          var fontSize = ((height - chart.chartArea.top) / 100).toFixed(2);
          
          ctx.restore();
          ctx.font = fontSize + "em sans-serif";
          ctx.textBaseline = "middle"
    
          var text = percent + "%",
              textX = Math.round((width - ctx.measureText(text).width) / 2),
              textY = (height + chart.chartArea.top) / 2;
    			
          ctx.fillStyle = chart.config.data.datasets[0].backgroundColor[0];
          ctx.fillText(text, textX, textY);
          ctx.fillStyle = oldFill;
          ctx.save();
        }
      }
    });
    
    var myChart = new Chart(document.getElementById('myChart'), {
      type: 'doughnut',
      data: data,
      options: {
      	responsive: true,
        legend: {
          display: true
        }
      }
    });
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.6/Chart.bundle.js"></script>
    <canvas id="myChart"></canvas>
    
  • 102

    您还可以在 onAnimationComplete 选项中粘贴mayankcpdixit的代码:

    // ...
    var myDoughnutChart = new Chart(ctx).Doughnut(data, {
        onAnimationComplete: function() {
            ctx.fillText(data[0].value + "%", 100 - 20, 100, 200);
        }
    });
    

    动画后将显示文字

  • 2

    我用7 jQueryUI Slider和ChartJs创建了一个demo(里面有动态文本)

    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 / 140).toFixed(2);
                this.chart.ctx.font = fontSize + "em Verdana";
                this.chart.ctx.textBaseline = "middle";
    
                var red = $( "#red" ).slider( "value" ),
                green = $( "#green" ).slider( "value" ),
                blue = $( "#blue" ).slider( "value" ),
                yellow = $( "#yellow" ).slider( "value" ),
                sienna = $( "#sienna" ).slider( "value" ),
                gold = $( "#gold" ).slider( "value" ),
                violet = $( "#violet" ).slider( "value" );
                var text = (red+green+blue+yellow+sienna+gold+violet) + " minutes";
                var textX = Math.round((width - this.chart.ctx.measureText(text).width) / 2);
                var textY = height / 2;
                this.chart.ctx.fillStyle = '#000000';
                this.chart.ctx.fillText(text, textX, textY);
            }
        });
    
    
    var ctx = $("#myChart").get(0).getContext("2d");
    var myDoughnutChart = new Chart(ctx).DoughnutTextInside(data, {
        responsive: false
    });
    

    DEMO IN JSFIDDLE

    enter image description here

  • 1

    @Cmyker,chart.js v2的绝佳解决方案

    一个小小的改进:检查适当的画布ID是有意义的,请参阅下面的修改后的片段 . 否则,文本(即75%)也会在页面内的其他图表类型的中间呈现 .

    Chart.pluginService.register({
        beforeDraw: function(chart) {
          if (chart.canvas.id === 'doghnutChart') {
            let width = chart.chart.width,
                height = chart.chart.outerRadius * 2,
                ctx = chart.chart.ctx;
    
            rewardImg.width = 40;
            rewardImg.height = 40;
            let imageX = Math.round((width - rewardImg.width) / 2),
                imageY = (height - rewardImg.height ) / 2;
    
            ctx.drawImage(rewardImg, imageX, imageY, 40, 40);
            ctx.save();
          }
        }
      });
    

    由于图例(参见:http://www.chartjs.org/docs/latest/configuration/legend.html)会放大图表高度,因此应通过半径获取高度值 .

  • 7

    首先,选择Chart.js的荣誉!我在我目前的一个项目中使用它,我非常喜欢它 - 它完美地完成了这项工作 .

    虽然标签/工具提示还不是库的一部分,但您可能需要查看这三个拉取请求:

    并且,正如Cracker0dks所提到的,Chart.js使用 canvas 进行渲染,因此您也可以通过交互实现自己的工具提示直接用它 .

    希望这可以帮助 .

相关问题