32

I would like to place a title in the center of a pie/donut chart in HighCharts.

I don't see anything in the chart options that would directly enable this, so I'm thinking it requires using the Highcharts SVG renderer -- chart.renderer.text('My Text', x, y).

I have that set up but I can't get the text to be centered inside the pie. Percentages don't seem to be accepted for x and y values. Is there a programmatic way to get it centered inside the plot, and to survive container resizing?

Update: Setting x and y to 50% works fine to center a circle (using renderer.circle(x, y, radius))—but not to center text (using renderer.text(text, x, y)).

See result here: http://jsfiddle.net/supertrue/e2qpa/

supertrue
  • 2,049
  • 5
  • 30
  • 49

7 Answers7

56

Use this code to center chart title vertically:

title: {
    verticalAlign: 'middle',
    floating: true
}

Example

Donut chart with title in the center

Edit

Since version 2.1 The floating property can be omitted as the documentation states it is implied by the presence of the verticalAlign property

When a value is given, the title behaves as floating.

Pavel Chuchuva
  • 22,633
  • 10
  • 99
  • 115
37

You need to take into account the location of the chart, so if you use the 'left' and 'top' attributes, you can add on half the width of the plot and subtract half the width of your text bounding box. This would yield the exact center:

text = chart.renderer.text("My Text").add();
textBBox = text.getBBox();
x = chart.plotLeft + (chart.plotWidth  * 0.5) - (textBBox.width  * 0.5);
y = chart.plotTop  + (chart.plotHeight * 0.5) - (textBBox.height * 0.5);
text.attr({x: x, y: y});

Apparently the bounding box will be 0s unless you add it first.

Correction:

y = chart.plotTop  + (chart.plotHeight * 0.5) + (textBBox.height * 0.25);

So, my original thought, and this seemed fine, was that the text would be aligned by the upper left, however it is done by the bottom left instead. Thus, instead of subtracting half the height, we actually need to add it. What confuses me, and something I don't understand yet, is that to get the center you add only 25% of the height rather then 50%. Note: This does not appear to work on IE 7 or 8.

MAJOR UPDATE

http://jsfiddle.net/NVX3S/2/

<- Centered text that works in all browers

What this new update does is it adds a new element using jquery after the chart is done. This works in all browers that I have tested (including IE7, 8, 9, Firefox and Chrome).

var textX = chart.plotLeft + (chart.plotWidth  * 0.5);
var textY = chart.plotTop  + (chart.plotHeight * 0.5);

// The width and height need to be calculated properly, so I made it a span.
var span = '<span id="pieChartInfoText" style="position:absolute; text-align:center;">';
span += '<span style="font-size: 32px">Upper</span><br>';
span += '<span style="font-size: 16px">Lower</span>';
span += '</span>';

$("#addText").append(span);
span = $('#pieChartInfoText');
span.css('left', textX + (span.width() * -0.5));
span.css('top', textY + (span.height() * -0.5));
Community
  • 1
  • 1
johnstorm
  • 412
  • 3
  • 3
  • 1
    Thanks, this is very informative—I didn't know about the plotWidth and plotHeight properties. Only thing is it doesn't readjust when resized. See http://jsfiddle.net/supertrue/tH8FY/ (Also for some reason, the placement looks off center.) Is there some way to use groups or percentage-based positioning to get this to work? – supertrue Mar 20 '12 at 03:28
  • So, looking further into it, apparently the bounding box will be 0s unless you add it first. I updated the example above. More unfortunately, I found how to center it on chrome, however this doesn't work on IE 7 or 8. I edited your example to demonstrate: http://jsfiddle.net/NVX3S/ – johnstorm Mar 21 '12 at 15:33
  • Works great, thanks. One small caveat, the height of the Title appears to throw off the vertical position just slightly (I measure 60px between top of span and the circle of the chart, and 80px at the bottom). Adding Title height (aprox 18px) to plotHeight seems to fix it `var textY = chart.plotTop + ((chart.plotHeight + 18) * 0.5);` Now, how to get Title height dynamically? http://jsfiddle.net/64td8/ – Sully Feb 19 '14 at 18:35
  • I was thinking that highcharts might be providing an option to do so.I was looking for a property in their API reference. – techie_28 Jun 23 '16 at 06:10
  • One of the most important lines of this answer (for me) was `What confuses me, and something I don't understand yet, is that to get the center you add only 25% of the height rather then 50%` – Jay Sep 15 '16 at 10:22
  • I did a pretty similar version of this earlier and forgot it. Now after having the problem again, I googled and got your solution. Nice. I needed this for Angular2 though so I did an Angular version of this. – Janos Vinceller Oct 21 '20 at 22:14
10

The best solution is to rely on series center, instead of plotHeight or plotWidth.

var chart = new Highcharts.Chart({
    chart: {
        renderTo: 'container',
        type: 'pie'
    },
    plotOptions: {
        pie: {
            //innerSize: '60%'
        }
    },
    title: {
        text: ''
    },
    series: [{
        data: [
            ['Firefox', 2262],
            ['IE7', 3800],
            ['IE6', 1000],
            ['Chrome', 1986]
            ]}]
},

function(chart) { // on complete
    var textX = chart.plotLeft + (chart.series[0].center[0]);
    var textY = chart.plotTop  + (chart.series[0].center[1]);

    var span = '<span id="pieChartInfoText" style="position:absolute; text-align:center;">';
    span += '<span style="font-size: 32px">Upper</span><br>';
    span += '<span style="font-size: 16px">Lower</span>';
    span += '</span>';

    $("#addText").append(span);
    span = $('#pieChartInfoText');
    span.css('left', textX + (span.width() * -0.5));
    span.css('top', textY + (span.height() * -0.5));
});

Working demo: http://jsfiddle.net/4dL9S/

Paweł Fus
  • 44,795
  • 3
  • 61
  • 77
2

Just add the following.

title: { text : 'title to display in the middle' verticalAlign: 'middle', y: 5 },

Kifayat Ullah
  • 579
  • 1
  • 5
  • 14
1

First, you may want to check the html in your fiddle. You had a width on your container of 500 instead of 500px.

<div id="container" style="height: 400px; width: 500px"></div>​

Second, this fiddle is a bit quick and dirty, but I think it accomplishes what you wanted?

http://jsfiddle.net/e2qpa/3/

mg1075
  • 17,985
  • 8
  • 59
  • 100
  • I know I can position it manually, but what I'm looking for is a solution that will center it no matter the size of the container. I updated my fiddle to have a container without a fluid size—http://jsfiddle.net/supertrue/e2qpa/ – supertrue Mar 19 '12 at 04:22
0
var newChart = new Highcharts.Chart(options);

//Set No data text
var textX = newChart.plotLeft + (newChart.plotWidth * 0.5);
var textY = newChart.plotTop + (newChart.plotHeight * 0.3);
var textWidth = 500;
textX = textX - (textWidth / 2);

newChart.renderer.label('<div style="width: ' + textWidth + 'px; text-align: center"><span>Dati non disponibili per questa selezione</span></div>', textX, textY, null, null, null, true)
        .css({
            fontSize: '16px',
        }).add();
Striezel
  • 3,693
  • 7
  • 23
  • 37
Giampaolo
  • 1
  • 1
  • 3
    Please explain your code and how it solves the OP's question. Read https://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers – Nic3500 Aug 01 '18 at 12:45
0

I found this works when there is a legend and you set the text you want in the centre of the chart as the title:

events: {
    load: function() {
        const titleHeight = this.title.getBBox().height;
        this.title.attr({
            y: this.plotHeight / 2 + titleHeight / 2,
        });
    },
    redraw: function() {
        const titleHeight = this.title.getBBox().height;
        this.title.attr({
            y: this.plotHeight / 2 + titleHeight / 2,
        });
    },
},
ldam
  • 4,412
  • 6
  • 45
  • 76