Jak dodać tekst do wykresu pierścieniowego za pomocą Chart.js?


Odpowiedzi:


38

Musisz zmodyfikować kod, taki jak: w chart.Doughnut.defaults

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

a potem w funkcji drawPieSegments

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

Zobacz to wyciągnięcie: https://github.com/nnnick/Chart.js/pull/35

tutaj jest skrzypce http://jsfiddle.net/mayankcpdixit/6xV78/ implementujące to samo.


2
Czy jest ktoś, kto nie może znaleźć tej funkcji drawPieSegments?
Julian

2
Warto wspomnieć, że nie działa z v2. Użyj dołączonego kodu jsfiddle dla łatwego użycia
Alwin Kesler

1
Jak dodać% w nowej linii? czy to jest obsługiwane?
user7334203

1
Wciąż to jest rozwiązanie?
ACB

@ ArunC.B - przewiń w dół
ashleedawg

179

Żadna z pozostałych odpowiedzi nie zmienia rozmiaru tekstu na podstawie ilości tekstu i rozmiaru pączka. Oto mały skrypt, którego możesz użyć do dynamicznego umieszczenia dowolnej ilości tekstu pośrodku i automatycznie zmieni jego rozmiar.

Przykład: http://jsfiddle.net/kdvuxbtj/

Pączek Z Dynamicznym Tekstem w środku

Zajmie to dowolną ilość tekstu w pączku o rozmiarze idealnym do pączka. Aby uniknąć dotykania krawędzi, możesz ustawić wypełnienie boczne jako procent średnicy wewnętrznej strony koła. Jeśli go nie ustawisz, domyślnie będzie to 20. Ty także kolor, czcionka i tekst. Wtyczka zajmie się resztą.

Kod wtyczki będzie zaczynał się od podstawowego rozmiaru czcionki 30 pikseli. Stamtąd sprawdzi szerokość tekstu i porówna go z promieniem koła i zmieni jego rozmiar na podstawie stosunku szerokości koła do tekstu.

Ma domyślny minimalny rozmiar czcionki 20 pikseli. Jeśli tekst przekroczyłby granice przy minimalnym rozmiarze czcionki, tekst zostanie zawinięty. Domyślna wysokość linii podczas zawijania tekstu to 25 pikseli, ale można ją zmienić. Jeśli ustawisz domyślny minimalny rozmiar czcionki na false, tekst stanie się nieskończenie mały i nie będzie zawijany.

Ma również domyślny maksymalny rozmiar czcionki 75 pikseli na wypadek, gdyby nie było wystarczającej ilości tekstu, a napis byłby zbyt duży.

To jest kod wtyczki

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

W obiekcie wykresu używasz następujących opcji

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

Podziękowania dla @Jenna Sloan za pomoc w matematyce zastosowanej w tym rozwiązaniu.


5
Działa świetnie! Większość innych opcji nie działa, gdy legenda znajduje się po prawej lub lewej stronie.
louisav

2
Świetne rozwiązanie!
JustLooking

3
Zaktualizowałem twoje skrzypce i dodałem maksymalny rozmiar czcionki: jsfiddle.net/nkzyx50o/3059
Felix Geenen

4
Czy można podzielić tekst na kilka wierszy? Mój tekst ma 6 słów i jest przepełniony między granicami wycinanki
Quanda.

2
Dziękuję, to też działa dla mnie, ale jak dodać tekst wieloliniowy?
Ashutosh Shrestha,

54

Tutaj jest uporządkowany i połączony przykład powyższych rozwiązań - responsywny (spróbuj zmienić rozmiar okna), obsługuje samoregulację animacji, obsługuje podpowiedzi

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>

AKTUALIZACJA 17.06.16:

Ta sama funkcjonalność, ale dla chart.js w wersji 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>


3
Mam Uncaught TypeError: Cannot read property 'extend' of undefinedjakieś pomysły?
Max Rose-Collins

2
Możesz także zmienić kolor tekstu za pomocą ctx.fillStyle = 'black';
Adrian Lopez

powoduje to
ciągłe nadpisywanie

Czy znalazłeś rozwiązanie tego problemu?
Cmyker

@Cmyker rozwiązanie CSS / HTML może pomóc, ale nie eksportuje środkowego tekstu, gdy wykres jest eksportowany jako PNG. Czy są jakieś pomysły, aby to naprawić? To było kompletne rozwiązanie, ale nie wyczyściło środkowego obszaru po odświeżeniu wykresu .
techie_28

38

Unikałbym modyfikowania kodu chart.js, aby to osiągnąć, ponieważ jest to dość łatwe w przypadku zwykłego CSS i HTML. Oto moje rozwiązanie:

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

Wynik wygląda następująco:

wprowadź opis obrazu tutaj


5
Dlaczego nie? Po prostu dodaj @ media-queries do swoich zajęć.
Mattias,

2
Dla mnie to nie działa, używam sposobu responsywnego, więc nie mogę używać stałych wartości. :(
Massa,

2
@Massa. Czy próbowałeś używać zapytań o media dla różnych rozdzielczości? Albo zmodyfikowanie napisanego przeze mnie css, aby używał% zamiast px?
Mattias

2
@Mattias to było fajne rozwiązanie, ale centralny tekst nie jest eksportowany, gdy wykres jest pobierany jako plik PNG.
techie_28

1
@ techie_28 ważny punkt, nie wziął tego pod uwagę, ponieważ pytanie w ogóle nie wspominało o eksporcie.
Mattias,

21

To też działa na mój koniec ...

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

wprowadź opis obrazu tutaj


5
Skorzystałem z Twojego rozwiązania, ponieważ było najszybsze i spełnia swoje zadanie. Dzięki!
MDT

@Amrik Singh jest to rzeczywiście dobre rozwiązanie, ale tekst w środku nie zostanie wyeksportowany, jeśli wykres zostanie pobrany jako obraz PNG.
techie_28

Niezłe rozwiązanie, nie wymaga wiele kłopotów.
Shashank,

jesteś moim kolesiem! Nie mogę znaleźć rozwiązania w angularjs i nigdy nie robię tego w ten sposób. Niesamowity.
Nomi Ali

1
piękna, szybka i czysta poprawka
Khaleel

11

Opieraj się na odpowiedzi @ rap-2-h, tutaj kod do używania tekstu na wykresie pierścieniowym na Chart.js do użycia w desce rozdzielczej. Ma dynamiczny rozmiar czcionki dla opcji responsywnej.

HTML:

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

Scenariusz:

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

Tutaj przykładowy kod. Spróbuj zmienić rozmiar okna. http://jsbin.com/wapono/13/edit


1
To powinna być akceptowana odpowiedź w przypadku potrzeby responsywności (mój przypadek).
Greg Blass

2
Jeśli masz podpowiedzi, tekst znika po najechaniu kursorem.
Julian

Błąd „jQuery.Deferredception: Chart is not defined”
Kiquenet,

11

Możesz użyć CSS z pozycjonowaniem względnym / bezwzględnym, jeśli chcesz, aby był responsywny. Ponadto może z łatwością obsługiwać wiele linii.

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>

piękne rozwiązanie :)
Manza

Super robota, bracie, zrobiłeś mój dzień
DVP SmartCreators Inc robimy

8

Jest to oparte na aktualizacji Cmykera dla Chart.js 2. (opublikowanej jako kolejna odpowiedź, ponieważ nie mogę jeszcze komentować)

Miałem problem z wyrównaniem tekstu w przeglądarce Chrome, gdy legenda jest wyświetlana, ponieważ wysokość wykresu nie obejmuje tego, więc nie jest prawidłowo wyrównana na środku. Naprawiono to, biorąc to pod uwagę przy obliczaniu fontSize i textY.

Obliczyłem procent wewnątrz metody, a nie ustaloną wartość, ponieważ mam ich wiele na stronie. Założenia są takie, że twój wykres ma tylko 2 wartości (w przeciwnym razie jaki jest procent? I że pierwsza jest tą, dla której chcesz wyświetlić procent. Mam też kilka innych wykresów, więc sprawdzam typ = pączek. Używam pączków tylko do wyświetlania procentów, więc to działa dla mnie.

Kolor tekstu wydaje się nieco chybiony, w zależności od kolejności, w jakiej działają itp., Więc napotkałem problem podczas zmiany rozmiaru, że tekst zmieniał kolor (między czarnym a podstawowym w jednym przypadku i drugorzędnym i białym w innym), więc „Zapisuję” bez względu na istniejący styl wypełnienia, rysuję tekst (w kolorze danych podstawowych), a następnie przywracam stary styl wypełnienia. (Zachowanie starego stylu wypełnienia nie wydaje się potrzebne, ale nigdy nie wiadomo).

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


7

Możesz również wkleić kod mayankcpdixit w onAnimationCompleteopcji:

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

Tekst zostanie wyświetlony po animacji


6
Dobrze, ale tekst znika po najechaniu
rnaud

1
Dobrze, tekst znika po najechaniu myszą ... :( Byłoby wspaniale, gdyby tekst nie zniknął, jakikolwiek pomysł jak to zrobić? Dzięki
MDT

@MDT @maud może być przy użyciu savemetody
techie_28

7

Tworzę demo z 7 suwakami jQueryUI i ChartJs (z dynamicznym tekstem w środku)

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 W JSFIDDLE

wprowadź opis obrazu tutaj


3

Odpowiedź @ rap-2-h i @Ztuons Ch nie pozwala na showTooltipsaktywowanie tej opcji, ale możesz utworzyć i canvasumieścić drugi obiekt za tym, który renderuje wykres.

Ważną częścią jest stylizacja wymagana w elementach div i samym obiekcie kanwy, tak aby renderowały się jeden na drugim.

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>

Oto jsfiddle: https://jsfiddle.net/68vxqyak/1/


1

@Cmyker, świetne rozwiązanie dla chart.js v2

Jedno małe ulepszenie: warto sprawdzić odpowiedni identyfikator kanwy, zobacz zmodyfikowany fragment poniżej. W przeciwnym razie tekst (np. 75%) jest również renderowany w środku innych typów wykresów na stronie.

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

Ponieważ legenda (patrz: http://www.chartjs.org/docs/latest/configuration/legend.html ) powiększa wysokość wykresu, wartość wysokości należy uzyskać na podstawie promienia.


0

Przede wszystkim chwała za wybór Chart.js! Używam go w jednym z moich obecnych projektów i absolutnie go kocham - doskonale spełnia swoje zadanie.

Chociaż etykiety / podpowiedzi nie są jeszcze częścią biblioteki, możesz rzucić okiem na te trzy żądania ściągnięcia:

I, jak Cracker0dks wspomniano, Chart.js zastosowańcanvas do renderowania, więc równie dobrze możesz po prostu zaimplementować własne podpowiedzi z nimi bezpośrednio w interakcję.

Mam nadzieję że to pomoże.


0

Rozwiązanie Alesany ogólnie działa bardzo dobrze dla mnie, ale podobnie jak inne chciałem móc określić, gdzie występują przerwy w linii. Wprowadziłem kilka prostych modyfikacji, aby zawijać wiersze po znakach „\ n”, o ile tekst jest już zawijany. Bardziej kompletne rozwiązanie wymusiłoby zawijanie, gdyby w tekście były jakieś znaki „\ n”, ale w tej chwili nie mam czasu, aby to zadziałało z rozmiarami czcionek. Podczas owijania zmiana powoduje również nieco lepsze wyśrodkowanie w poziomie (pozwala uniknąć końcowych spacji). Kod poniżej (nie mogę jeszcze dodawać komentarzy).

Fajnie by było, gdyby ktoś umieścił tę wtyczkę na GitHubie ...

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 lines = [];
      var chunks = txt.split('\n');
      for (var m = 0; m < chunks.length; m++) {
        var words = chunks[m].split(' ');
        var line;

        // Break words up into multiple lines if necessary
        for (var n = 0; n < words.length; n++) {
          var testLine = (n == 0) ? words[n] : 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;
          }
        }
        lines.push(line);
      }

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

      // All but last line
      for (var n = 0; n < lines.length; n++) {
        ctx.fillText(lines[n], centerX, centerY);
        centerY += lineHeight;
      }
    }
  }
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.