Wie füge ich mit Chart.js Text in das Donut-Diagramm ein?


Antworten:


36

Sie müssen den Code wie folgt ändern: in chart.Doughnut.defaults

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

und dann in Funktion drawPieSegments

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

Siehe diesen Pull: https://github.com/nnnick/Chart.js/pull/35

Hier ist eine Geige http://jsfiddle.net/mayankcpdixit/6xV78/ , die dasselbe implementiert.


2
Gibt es noch jemanden, der diese drawPieSegments-Funktion nicht finden kann?
Yulian

2
Erwähnenswert ist, dass es mit v2 nicht funktioniert. Verwenden Sie den enthaltenen jsfiddle-Code für eine einfache Verwendung
Alwin Kesler

1
Wie füge ich das% in eine neue Zeile ein? wird das unterstützt?
user7334203

1
Ist das immer noch die Lösung?
ACB

@ ArunC.B - scrollen Sie nach unten
ashleedawg

175

Keine der anderen Antworten ändert die Größe des Textes basierend auf der Textmenge und der Größe des Donuts. Hier ist ein kleines Skript, mit dem Sie eine beliebige Textmenge dynamisch in der Mitte platzieren können. Die Größe wird automatisch geändert.

Beispiel: http://jsfiddle.net/kdvuxbtj/

Donut mit dynamischem Text in der Mitte

Es wird jede Menge Text in dem Donut benötigt, der perfekt für den Donut geeignet ist. Um ein Berühren der Kanten zu vermeiden, können Sie eine Seitenpolsterung als Prozentsatz des Durchmessers der Innenseite des Kreises festlegen. Wenn Sie es nicht einstellen, wird es standardmäßig auf 20 gesetzt. Sie auch die Farbe, die Schriftart und den Text. Das Plugin kümmert sich um den Rest.

Der Plugin-Code beginnt mit einer Basisschriftgröße von 30px. Von dort aus wird die Breite des Texts überprüft, mit dem Radius des Kreises verglichen und die Größe basierend auf dem Verhältnis von Kreis zu Textbreite geändert.

Die Standardschriftgröße beträgt mindestens 20 Pixel. Wenn der Text bei der Mindestschriftgröße die Grenzen überschreitet, wird der Text umbrochen. Die Standardzeilenhöhe beim Umbrechen des Texts beträgt 25 Pixel, Sie können sie jedoch ändern. Wenn Sie die Standard-Mindestschriftgröße auf false setzen, wird der Text unendlich klein und wird nicht umgebrochen.

Es hat auch eine maximale Standardschriftgröße von 75px, falls nicht genügend Text vorhanden ist und die Beschriftung zu groß wäre.

Dies ist der Plugin-Code

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

Und Sie verwenden die folgenden Optionen in Ihrem Diagrammobjekt

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

Dank an @Jenna Sloan für die Hilfe bei der in dieser Lösung verwendeten Mathematik.


5
Funktioniert super! Die meisten anderen Optionen werden unterbrochen, wenn sich die Legende rechts oder links befindet.
Louisav

2
Tolle Lösung!
JustLooking

3
Ich habe Ihre Geige aktualisiert und eine maximale Schriftgröße hinzugefügt: jsfiddle.net/nkzyx50o/3059
Felix Geenen

4
Kann der Text in mehrere Zeilen aufgeteilt werden? Mein Text hat 6 Wörter und sein Überlaufen zwischen den Grenzen des Ausschnitts
Quanda

2
Vielen Dank, dass dies auch für mich funktioniert, aber wie füge ich mehrzeiligen Text hinzu?
Ashutosh Shrestha

54

Hier finden Sie ein bereinigtes und kombiniertes Beispiel für die oben genannten Lösungen - reaktionsschnell (versuchen Sie, die Größe des Fensters zu ändern), unterstützt die Selbstausrichtung der Animation und unterstützt QuickInfos

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:

Gleiche Funktionalität, jedoch für chart.js Version 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
Ich bekomme Uncaught TypeError: Cannot read property 'extend' of undefinedirgendwelche Ideen?
Max Rose-Collins

2
Sie können die Textfarbe auch mit ctx.fillStyle = 'black' ändern.
Adrian Lopez

Dies schreibt immer wieder über den Text, wenn das Diagramm durch die Bereitstellung neuer Datenparameter aktualisiert wird
techie_28

Haben Sie die Lösung dafür gefunden?
Cmyker

@Cmyker die CSS / HTML-Lösung könnte helfen, aber das exportiert den mittleren Text nicht, wenn das Diagramm als PNG exportiert wird. Irgendwelche Ideen, um dies zu korrigieren? Dies war eine vollständige Lösung, nur dass der mittlere Bereich beim Aktualisieren des Diagramms nicht gelöscht wird .
Techie_28

38

Ich würde es vermeiden, den Code von chart.js zu ändern, um dies zu erreichen, da dies mit normalem CSS und HTML ziemlich einfach ist. Hier ist meine Lösung:

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

Die Ausgabe sieht folgendermaßen aus:

Geben Sie hier die Bildbeschreibung ein


4
Warum nicht? Fügen Sie einfach @ media-Abfragen zu Ihren Klassen hinzu.
Mattias

2
Es funktioniert nicht für mich, ich benutze eine reaktionsschnelle Methode, also kann ich keine festen Werte verwenden. :(
Massa

2
@Massa Haben Sie versucht, Medienabfragen für die verschiedenen Auflösungen zu verwenden? Oder das CSS ändern, das ich geschrieben habe, um% anstelle von px zu verwenden?
Mattias

2
@ Mattias Dies war eine nette Lösung, aber der zentrale Text wird nicht exportiert, wenn das Diagramm als PNG heruntergeladen wird.
Techie_28

1
@ techie_28 gültiger Punkt, habe das nicht berücksichtigt, da in der Frage der Export überhaupt nicht erwähnt wurde.
Mattias

20

Das funktioniert auch an meinem Ende ...

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

Geben Sie hier die Bildbeschreibung ein


4
Ich habe Ihre Lösung verwendet, weil sie die schnellste war und ihre Aufgabe erfüllt. Vielen Dank!
MDT

@ Amrik Singh Dies ist in der Tat eine gute Lösung, aber der mittlere Text wird nicht exportiert, wenn das Diagramm als PNG-Bild heruntergeladen wird.
Techie_28

Schöne Lösung, es braucht nicht viel Mühe.
Shashank

Du bist mein Typ! Ich kann keine Lösung in Angularjs finden und obwohl ich das nie so mache. Tolle.
Nomi Ali

1
schöne, schnelle und saubere Lösung
Khaleel

11

Basis auf @ rap-2-h Antwort, hier der Code für die Verwendung von Text auf Donut-Diagramm auf Chart.js für die Verwendung in Dashboard wie. Es hat eine dynamische Schriftgröße für die Reaktionsoption.

HTML:

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

Skript:

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

Hier der Beispielcode. Versuchen Sie, die Größe des Fensters zu ändern. http://jsbin.com/wapono/13/edit


1
Dies sollte die akzeptierte Antwort sein, wenn Reaktionsfähigkeit erforderlich ist (mein Fall).
Greg Blass

2
Wenn Sie QuickInfos haben, verschwindet der Text beim Hover.
Yulian

Fehler "jQuery.Deferred Ausnahme: Diagramm ist nicht definiert"
Kiquenet

11

Sie können CSS mit relativer / absoluter Positionierung verwenden, wenn Sie möchten, dass es reagiert. Außerdem kann es problemlos mit mehreren Leitungen umgehen.

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>

schöne Lösung :)
Manza

Super Arbeit, Bruder, du hast meinen Tag gemacht
DVP SmartCreators Inc, wir machen den

8

Dies basiert auf Cmykers Update für Chart.js 2. (als weitere Antwort veröffentlicht, da ich noch keinen Kommentar abgeben kann)

Ich hatte ein Problem mit der Textausrichtung in Chrome, wenn die Legende angezeigt wird, da die Diagrammhöhe dies nicht enthält und sie daher in der Mitte nicht richtig ausgerichtet ist. Dies wurde behoben, indem dies bei der Berechnung von fontSize und textY berücksichtigt wurde.

Ich habe den Prozentsatz innerhalb der Methode berechnet und nicht einen festgelegten Wert, da ich mehrere davon auf der Seite habe. Es wird davon ausgegangen, dass Ihr Diagramm nur 2 Werte hat (andernfalls wie viel Prozent davon? Und dass der erste derjenige ist, für den Sie den Prozentsatz anzeigen möchten. Ich habe auch eine Reihe anderer Diagramme, also überprüfe ich, ob type = donut. Ich verwende nur Donuts, um Prozentsätze anzuzeigen, damit es für mich funktioniert.

Die Textfarbe scheint ein bisschen ein Hit und Miss zu sein, abhängig von der Reihenfolge, in der die Dinge ausgeführt werden usw. Daher stieß ich beim Ändern der Größe auf ein Problem, dass der Text seine Farbe ändern würde (in einem Fall zwischen Schwarz und Primärfarbe und in einem anderen Fall zwischen Sekundärfarbe und Weiß) Ich "speichere" unabhängig vom vorhandenen Füllstil, zeichne den Text (in der Farbe der Primärdaten) und stelle dann den alten Füllstil wieder her. (Die Beibehaltung des alten Füllstils scheint nicht erforderlich zu sein, aber Sie wissen es nie.)

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

Sie können auch den Code von mayankcpdixit in die folgende onAnimationCompleteOption einfügen :

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

Der Text wird nach der Animation angezeigt


6
Gut, aber der Text verschwindet beim Schweben
rnaud

1
Richtig, Text verschwindet beim Schweben ... :( Wäre toll, wenn der Text nicht verschwunden wäre, eine Idee, wie das geht? Danke
MDT

@MDT @maud kann mit der saveMethode
techie_28

7

Ich erstelle eine Demo mit 7 jQueryUI Slider und ChartJs (mit dynamischem Text)

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

Geben Sie hier die Bildbeschreibung ein


3

Die Antwort von @ rap-2-h und @Ztuons Ch lässt nicht zu, dass die showTooltipsOption aktiv ist, aber Sie können eine Sekunde erstellen und überlagerncanvas Objekt hinter dem Objekt .

Der wichtige Teil ist das Styling, das in den Divs und für das Canvas-Objekt selbst erforderlich ist, damit sie übereinander gerendert werden.

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>

Hier ist die jsfiddle: https://jsfiddle.net/68vxqyak/1/


1

@Cmyker, großartige Lösung für chart.js v2

Eine kleine Verbesserung: Es ist sinnvoll, nach der entsprechenden Canvas-ID zu suchen (siehe das modifizierte Snippet unten). Andernfalls wird der Text (dh 75%) auch in der Mitte anderer Diagrammtypen auf der Seite gerendert.

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

Da eine Legende (siehe: http://www.chartjs.org/docs/latest/configuration/legend.html ) die Diagrammhöhe vergrößert, sollte der Wert für die Höhe durch den Radius ermittelt werden.


0

Zunächst einmal ein großes Lob für die Wahl von Chart.js! Ich benutze es für eines meiner aktuellen Projekte und ich liebe es absolut - es macht den Job perfekt.

Obwohl Beschriftungen / QuickInfos noch nicht Teil der Bibliothek sind, sollten Sie sich diese drei Pull-Anforderungen ansehen:

Und wie Cracker0dks erwähnt, verwendet Chart.jscanvas zum Rendern verwendet, sodass Sie auch einfach Ihre eigenen Tooltips implementieren können, indem Sie direkt damit interagieren.

Hoffe das hilft.


0

Die Lösung von Alesana funktioniert im Allgemeinen sehr gut für mich, aber wie andere wollte ich angeben können, wo Zeilenumbrüche auftreten. Ich habe einige einfache Änderungen vorgenommen, um Zeilen mit '\ n' Zeichen zu umbrechen, solange der Text bereits umbrochen wird. Eine vollständigere Lösung würde das Umbrechen erzwingen, wenn der Text '\ n' Zeichen enthält, aber ich habe im Moment keine Zeit, dies mit der Schriftgröße zu tun. Die Änderung zentriert sich beim Wickeln auch horizontal etwas besser (vermeidet Leerzeichen). Der Code ist unten (ich kann noch keine Kommentare posten).

Es wäre cool, wenn jemand dieses Plug-In auf GitHub stellen würde ...

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;
      }
    }
  }
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.