Как добавить текст внутри диаграммы пончика, используя Chart.js? - программирование
Подтвердить что ты не робот

Как добавить текст внутри диаграммы пончика, используя Chart.js?

Как визуализировать текст внутри диаграммы пончика, я использую ChartJs.

4b9b3361

Ответ 1

Вам нужно изменить код: в 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/, реализующая то же самое.

Ответ 2

Вот вычищенный и комбинированный пример из вышеперечисленных решений - отзывчивый (попробуйте изменить размер окна), поддерживает самовыравнивание анимации, поддерживает всплывающие подсказки

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>

Ответ 3

Ни один из других ответов не изменяет размер текста, исходя из количества текста и размера пончика. Вот небольшой script, который вы можете использовать для динамического размещения любого текста в середине, и он автоматически изменит его размер. http://jsfiddle.net/nkzyx50o/

Пончик с динамическим текстом в среднем

В пончике будет приниматься любое количество текста, идеально подходящего для пончика. Чтобы не касаться краев, вы можете установить боковое наложение в процентах от диаметра внутренней части круга. Если вы не установите его, оно будет равно 20. Вы также можете указать цвет, шрифт и текст. Плагин позаботится об остальном.

Код плагина начнется с базового размера шрифта 30 пикселей. Оттуда он проверит ширину текста и сравнит его с радиусом круга и изменит его размер на основе соотношения ширины круга/текста.

Это код плагина

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

Ответ 4

Я бы не стал модифицировать код 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

Ответ 5

База на @rap-2-h answer, Здесь приведен код для использования текста на диаграмме пончика на Chart.js для использования на панели управления. Он имеет динамический размер шрифта для гибкой опции.

HTML:

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

Script:

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

Ответ 6

Это также работает в моем конце...

<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

Ответ 7

Это основано на обновлении Cmyker для Chart.js 2. (опубликовано как еще один ответ, поскольку я еще не могу прокомментировать)

У меня возникла проблема с выравниванием текста в Chrome, когда легенда отображается, так как высота диаграммы не включает это, поэтому она не выравнивается правильно посередине. Исправлено это, учтя это при вычислении fontSize и textY.

Я вычислял процент внутри метода, а не заданное значение, поскольку у меня их несколько на странице. Предполагается, что ваша диаграмма имеет только 2 значения (в противном случае это процент от?), И первый - это тот, на который вы хотите показать процент. У меня также есть множество других диаграмм, поэтому я делаю чек для типа = пончик. Я использую пончики, чтобы показывать проценты, чтобы он работал у меня.

Цвет текста кажется немного удачным и пропущенным, в зависимости от того, какие вещи выполняются в и т.д., поэтому я столкнулся с проблемой при изменении размера текста, который изменил бы цвет (между черным и основным цветом в одном случае, а также вторичным цветом и белым цветом другой), поэтому я "сохраняю" любой существующий стиль заполнения, рисую текст (в цвет первичных данных), а затем восстанавливаю старый стиль заполнения. (Сохранение старого стиля заполнения не кажется необходимым, но вы никогда не знаете.)

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>

Ответ 8

Вы также можете вставить код mayankcpdixit в опции onAnimationComplete:

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

Текст будет показан после анимации

Ответ 9

Я создаю демо с 7 JQuieryUI Slider и ChartJs (с динамическим текстом внутри)

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

введите описание изображения здесь

Ответ 10

@rap-2-h и @Ztuons Ch answer не позволяют использовать параметр showTooltips, но вы можете создать и наложить второй объект canvas за один рендеринг диаграммы.

Важной частью является стилизация, требуемая в divs и для самого объекта 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>

Ответ 11

Прежде всего, надобно выбрать Chart.js! Я использую его в одном из моих текущих проектов, и мне это очень нравится - он отлично работает.

Хотя метки/всплывающие подсказки еще не входят в библиотеку, вы можете взглянуть на эти три запроса на растяжение:

И, как упоминалось Cracker0dks, Chart.js использует canvas для рендеринга, чтобы вы могли просто реализовать свои собственные всплывающие подсказки, напрямую взаимодействуя с ним.

Надеюсь, что это поможет.

Ответ 12

@Cmyker, отличное решение для chart.js v2

Одно небольшое улучшение: имеет смысл проверить соответствующий идентификатор canvas, см. ниже приведенный ниже фрагмент. В противном случае текст (т.е. 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) увеличивает высоту диаграммы, значение высоты должно быть получено радиусом.