Search code examples
javascriptcsschart.jslabel

How to move labels' position on Chart.js pie


I'm using Chart.js and I'm trying to move the labels on my Pie chart outside of the pie area (see red X's):

enter image description here

This my code right now:

<div class="container" id="pieContainer">
    <h4 class="title">Title</h4>
    <center><canvas id="pie"></canvas></center>
</div>

<script>                                  
    var pieData = [
    {
        value: 39,
        color:"#335478",
        label: "Blue"
    },
    {
        value : 4,
        color : "#7f7f7f",
        label: "Grey"
    },
    {
        value : 57,
        color : "#99cb55",
        label: "Green"
    }
    ];

    var optionsPie = {
        responsive : true,
        tooltipEvents: [],
        showTooltips: true,
        onAnimationComplete: function() {
             this.showTooltip(this.segments, true);
        },
        tooltipTemplate: "<%= label %> - <%= value %>%"
    };
    new Chart(document.getElementById("pie").getContext("2d")).Pie(pieData, optionsPie);
</script>

I don't want to use legends and I couldn't find a built-in method to move labels. Is there a way to do that without changing chart.js? What's the best way to achieve my goal?


Solution

  • Just extend the chart to do this. If your labels are static, it might be simpler to just change the tooltipPosition method instead.


    Preview

    enter image description here


    Script

    Chart.types.Pie.extend({
        name: "PieAlt",
        initialize: function(data){
            Chart.types.Pie.prototype.initialize.apply(this, arguments);
    
            var requiredSpace = 0;
            for (var i = 0; i < data.length; i++)
                requiredSpace = Math.max(ctx.measureText(Chart.helpers.template(this.options.tooltipTemplate, data[i])).width, requiredSpace);
            this.outerRadius -= (requiredSpace + 20);
        },
        draw: function(data){
            Chart.types.Pie.prototype.draw.apply(this, arguments);
    
            var self = this;
            ctx.save();
            ctx.font = Chart.helpers.fontString(self.options.scaleFontSize, self.options.scaleFontStyle, self.options.scaleFontFamily);
                    ctx.textBaseline = "middle";
            self.segments.forEach(function (segment) {
                var outerEdge = Chart.Arc.prototype.tooltipPosition.apply({
                    x: this.chart.width / 2,
                    y: this.chart.height / 2,
                    startAngle: segment.startAngle,
                    endAngle: segment.endAngle,
                    outerRadius: segment.outerRadius * 2 + 20,
                    innerRadius: 0
                })
    
                var normalizedAngle = (segment.startAngle + segment.endAngle) / 2;
                while (normalizedAngle > 2 * Math.PI) {
                    normalizedAngle -= (2 * Math.PI)
                }
    
                if (normalizedAngle < (Math.PI * 0.4) || (normalizedAngle > Math.PI * 1.5))
                    ctx.textAlign = "start";
                else if (normalizedAngle > (Math.PI * 0.4) && (normalizedAngle < Math.PI * 0.6)) {
                    outerEdge.y += 5;
                    ctx.textAlign = "center";
                }
                else if (normalizedAngle > (Math.PI * 1.4) && (normalizedAngle < Math.PI * 1.6)) {
                    outerEdge.y - 5;
                    ctx.textAlign = "center";
                }
                else
                    ctx.textAlign = "end";
    
                ctx.fillText(Chart.helpers.template(self.options.tooltipTemplate, segment), outerEdge.x, outerEdge.y);
            });
    
            ctx.restore();
        }
    });
    

    and then

    new Chart(ctx).PieAlt(data, {
        showTooltips: false
    });
    

    Fiddle - http://jsfiddle.net/h8rggkhp/