web-dev-qa-db-ja.com

Chart.jsを使用してドーナツチャート内にテキストを追加する方法は?

ドーナツチャート内でテキストをレンダリングする方法、私は ChartJs を使用しています。

74
batman

次のようなコードを変更する必要があります。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/ 同じものを実装しています。

29
mayankcpdixit

他の回答は、テキストの量とドーナツのサイズに基づいてテキストのサイズを変更しません。これは、任意の量のテキストを中央に動的に配置するために使用できる小さなスクリプトで、自動的にサイズが変更されます。 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 に感謝します。このソリューションで使用される数学の助けを借りてください。

133
Alesana

上記のソリューションのクリーンアップと組み合わせの例を次に示します-レスポンシブ(ウィンドウのサイズを変更してみてください)、アニメーションの自動位置合わせをサポート、ツールチップをサポート

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>
48
Cmyker

通常のCSSとHTMLを使用すると非常に簡単なので、chart.jsコードを変更してこれを実現することは避けたいと思います。私のソリューションは次のとおりです。

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

32
Mattias

これも私の終わりに働いています...

<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

15
Amrik Singh

@ 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

11
Ztuons Ch

これは、CmykerのChart.js 2の更新に基づいています(まだコメントできないため、別の回答として投稿しました)

Chromeのテキストの配置に問題がありました。凡例が表示されるとき、チャートの高さにこれが含まれないため、中央に正しく配置されません。 fontSizeとtextYの計算でこれを考慮することでこれを修正しました。

ページにこれらの値が複数あるため、設定値ではなくメソッド内のパーセンテージを計算しました。チャートには2つの値しかないと仮定します(そうでなければパーセンテージは何ですか?そして最初のものはパーセンテージを表示したいものです。他のチャートもたくさんあるのでtype = doughnutのチェックをします。私はドーナツを使ってパーセンテージを表示しているだけなので、私にとってはうまくいきます。

テキストの色は、物事がどの順序で実行されるかなどに応じて少しヒットしたりミスしたりするため、サイズ変更時にテキストの色が変わるという問題に遭遇しました(ある場合は黒とプライマリカラーの間、別の場合はセカンダリカラーとホワイトの間)既存の塗りつぶしスタイルが何であれ「保存」し、テキストを(プライマリデータの色で)描画してから、古い塗りつぶしスタイルを復元します。 (古い塗りつぶしスタイルを保持する必要はないようですが、あなたは決して知りません。)

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
Rory

MayankcpdixitのコードをonAnimationCompleteオプションに貼り付けることもできます。

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

アニメーションの後にテキストが表示されます

7
rap-2-h

7つのjQueryUI 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
});

JSFIDDLEのデモ

enter image description here

6
sgrillon

@ rap-2-hと@Ztuons Chの答えでは、showTooltipsオプションをアクティブにすることはできませんが、できることは、チャートをレンダリングするオブジェクトの後ろに2番目のcanvasオブジェクトを作成してレイヤー化することです。

重要な部分は、divおよびキャンバスオブジェクト自体に必要なスタイリングであり、それらが互いの上にレンダリングされるようにします。

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/

2
RYUUSEiiSTAR

レスポンシブにする場合は、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>
2
Dayze

@ 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 )はチャートの高さを拡大するため、高さの値は半径で取得する必要があります。

1
Larmia

まず、Chart.jsを選択したことに対する称賛です!私は現在のプロジェクトの1つでそれを使用していますが、私は絶対にそれを愛しています-それは完璧に仕事をします。

ラベル/ツールチップはまだライブラリの一部ではありませんが、次の3つのプルリクエストをご覧ください。

また、 Cracker0dks で述べたように、Chart.jsはレンダリングにcanvasを使用するため、直接対話することで独自のツールチップを実装することもできます。

お役に立てれば。

0
volpav