javascript - Rotating dataLabels in a Highcharts pie chart - Stack Overflow

I'm trying to rotate and position the dataLabels in each segment of a Highcharts pie chart and jus

I'm trying to rotate and position the dataLabels in each segment of a Highcharts pie chart and just feel like Im getting myself deeper and deeper without getting closer to a solution. Would love some tips or suggestions.

A graphic to illustrate the desired goal:

There will be three segments in my pie chart. I would ideally like:

  • Each dataLabel to be rotated to basically create a center line for each segment (illustrated by the magenta lines); and
  • The dataLabel to be centered in the segment, regardless of type size.

Suggestions on where to get started with this, or a sample that gets me close?

$(function () {
	$('#container').highcharts({
		chart: {
			type: 'pie',
			backgroundColor: 'transparent',
			spacing: [0, 0, 0, 0],
			margin: [0, 0, 0, 0],
			events: {
				load: function() {
					$.each(this.series[0].data, function(index, point) {

						var degree = (point.angle * 180) / Math.PI;
						var rotation = 0;
						(degree < 0) && (degree += 360);

						// If the slice is in the left half, then rotate 180
						// so the text won't look upside down
						if (degree >= 90 && degree <= 270) {
							rotation = degree - 180;
							point.dataLabel.x = 0;
							point.dataLabel.y = 0;
							point.dataLabel.translateX = (point.labelPos[2] + point.labelPos[4]) / 2;
							point.dataLabel.translateY = (point.labelPos[3] + point.labelPos[5]) / 2;
						} else {
							point.dataLabel.x = 0;
							point.dataLabel.y = 0;
							rotation = degree - 180;
							point.dataLabel.translateX = (point.labelPos[2] + point.labelPos[4]) / 2;
							point.dataLabel.translateY = (point.labelPos[3] + point.labelPos[5]) / 2;
						}

						point.dataLabel.rotation = Math.floor(rotation);
						point.dataLabel.show();
						point.dataLabel.updateTransform();
					});
				}
			}
		},
		title: {
			text: null
		},
		yAxis: {
			title: {
				text: 'Total percent market share'
			}
		},
		plotOptions: {
			pie: {
				borderColor: 'rgb(243, 243, 243)',
				borderWidth: 2,
				shadow: false,
				center: ['50%', '50%'],
				colors: ['rgb(77, 196, 215)', 'rgb(50, 68, 132)', 'rgb(85, 119, 183)']
			}
		},
		tooltip: {
			enabled: false
		},
		series: [{
			type: 'pie',
			name: 'Votes',
			data: [
				['Yes', 9],
				['No', 5],
				['Undecided', 2]
			],
			size: '90%',
			dataLabels: {
				formatter: function () {
					return this.point.name;
				},
				color: 'white',
				connectorWidth: 0,
				distance: -80
			}
		}]
	});
});
<script src=".1.1/jquery.min.js"></script>
<script src=".js"></script>
<div id="container" style="height: 600px; width: 100%;"></div>

I'm trying to rotate and position the dataLabels in each segment of a Highcharts pie chart and just feel like Im getting myself deeper and deeper without getting closer to a solution. Would love some tips or suggestions.

A graphic to illustrate the desired goal:

There will be three segments in my pie chart. I would ideally like:

  • Each dataLabel to be rotated to basically create a center line for each segment (illustrated by the magenta lines); and
  • The dataLabel to be centered in the segment, regardless of type size.

Suggestions on where to get started with this, or a sample that gets me close?

$(function () {
	$('#container').highcharts({
		chart: {
			type: 'pie',
			backgroundColor: 'transparent',
			spacing: [0, 0, 0, 0],
			margin: [0, 0, 0, 0],
			events: {
				load: function() {
					$.each(this.series[0].data, function(index, point) {

						var degree = (point.angle * 180) / Math.PI;
						var rotation = 0;
						(degree < 0) && (degree += 360);

						// If the slice is in the left half, then rotate 180
						// so the text won't look upside down
						if (degree >= 90 && degree <= 270) {
							rotation = degree - 180;
							point.dataLabel.x = 0;
							point.dataLabel.y = 0;
							point.dataLabel.translateX = (point.labelPos[2] + point.labelPos[4]) / 2;
							point.dataLabel.translateY = (point.labelPos[3] + point.labelPos[5]) / 2;
						} else {
							point.dataLabel.x = 0;
							point.dataLabel.y = 0;
							rotation = degree - 180;
							point.dataLabel.translateX = (point.labelPos[2] + point.labelPos[4]) / 2;
							point.dataLabel.translateY = (point.labelPos[3] + point.labelPos[5]) / 2;
						}

						point.dataLabel.rotation = Math.floor(rotation);
						point.dataLabel.show();
						point.dataLabel.updateTransform();
					});
				}
			}
		},
		title: {
			text: null
		},
		yAxis: {
			title: {
				text: 'Total percent market share'
			}
		},
		plotOptions: {
			pie: {
				borderColor: 'rgb(243, 243, 243)',
				borderWidth: 2,
				shadow: false,
				center: ['50%', '50%'],
				colors: ['rgb(77, 196, 215)', 'rgb(50, 68, 132)', 'rgb(85, 119, 183)']
			}
		},
		tooltip: {
			enabled: false
		},
		series: [{
			type: 'pie',
			name: 'Votes',
			data: [
				['Yes', 9],
				['No', 5],
				['Undecided', 2]
			],
			size: '90%',
			dataLabels: {
				formatter: function () {
					return this.point.name;
				},
				color: 'white',
				connectorWidth: 0,
				distance: -80
			}
		}]
	});
});
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.highcharts./highcharts.js"></script>
<div id="container" style="height: 600px; width: 100%;"></div>

Share Improve this question edited Jan 31, 2015 at 17:29 Brandon Durham asked Jan 31, 2015 at 6:22 Brandon DurhamBrandon Durham 7,72713 gold badges66 silver badges113 bronze badges 3
  • Please provide a live demo, and show us what you have done till now. – Raein Hashemi Commented Jan 31, 2015 at 8:48
  • 1 This is the best I can do. jsfiddle/6cn6dtyj Can you share your progress? – Hristo Ivanov Commented Jan 31, 2015 at 11:51
  • Added a new code snippet to share my work thus far. – Brandon Durham Commented Jan 31, 2015 at 17:29
Add a ment  | 

2 Answers 2

Reset to default 4

Highcharts is not providing options for auto rotating data labels in pie chart. You can write your custom function for dataLabels rotation.

Here is simple example how you can do it:

var allY, angle1, angle2, angle3,
    rotate = function () {
        $.each(options.series, function (i, p) {
            angle1 = 0;
            angle2 = 0;
            angle3 = 0;
            allY = 0;
            $.each(p.data, function (i, p) {
                allY += p.y;
            });

            $.each(p.data, function (i, p) {
                angle2 = angle1 + p.y * 360 / (allY);
                angle3 = angle2 - p.y * 360 / (2 * allY);
                p.dataLabels.rotation = -90 + angle3;
                angle1 = angle2;
            });
        });
    };

First I am calculating sum of all Y values. Then I am calculating the angle of middle of all pie slices. Then I am rotating data labels by the same angle.

example: http://jsfiddle/izothep/j7as86gh/6/

similar topic: Radial Pie Chart Datalabels in Highcharts

I found rotating the labels themselves to be problematic, because when using highcharts to rotate them, it seems to rotate them about their own axis. To achieve the best result, you want to rotate the label about the origin of the pie chart. To acplish this, I appended absolutely positioned divs directly on top of the pie chart, and iterated over the points to calculate the rotation based on percentages. The downside, of course, is that external divs are being used for the labels, rather than highcharts's own labeling functions.

Here is the code I added:

First, some CSS styles for the divs which hold the labels, and the pie chart itself:

CSS

div#container{
    position:relative;
}
div.outerContainer{
    width:600px;
    height:40px;
    position:absolute;
    top:280px;
    display:none;
    color:white;
    font-family:Helvetica, Arial, Sans;
    font-size:16px;
    font-weight:bold;
    text-transform:uppercase;
}
div.outerContainer > span{
    float:left;
    width:300px;
    text-align:center;
    height:40px;
    line-height:40px;
}

Then, custom load event code to calculate the labels

        load: function () {
            var cumulativePercentage = 0;
            var $labelTemplate = $("<div class=outerContainer><span class=left></span><span class=right></span></div>");
            $.each(this.series[0].data, function (i, point) {
                $label=$labelTemplate.clone();
                $label.find('span').text(point.name);
                var angle=-90+(cumulativePercentage+point.percentage/2)*360/100;
                if (angle > 90) {
                    angle=angle+180;
                    $label.find('span.right').css({visibility:'hidden'});
                }
                else {
                    $label.find('span.left').css({visibility:'hidden'});
                }
                $label.css({transform:'rotate('+angle+'deg)'});    
                cumulativePercentage+=point.percentage;


                $('#container').append($label);

            });
            $('div.outerContainer').show();
        }

Also, I deleted the dataLabels property.

Brief explanation:

cumulativePercent keeps track of how much of the pie each section contributes, so that we can insert the label exactly in the middle of each section. We check if the angle is greater than 90 degrees so that we can

  1. Flip the label div so that the text is not upside down (or leave it if less than 90 degrees)

  2. Decide if the text should be on the left or right side of the div, depending on its orientation.

See it in action:

  $('#container').highcharts({
        chart: {
            type: 'pie',
            backgroundColor: 'transparent',
            spacing: [0, 0, 0, 0],
            margin: [0, 0, 0, 0],
            events: {
                load: function () {
                    var cumulativePercentage = 0;
                    var $labelTemplate = $("<div class=outerContainer><span class=left></span><span class=right></span></div>");
                    $.each(this.series[0].data, function (i, point) {
                        $label = $labelTemplate.clone();
                        $label.find('span').text(point.name);
                        var angle = -90 + (cumulativePercentage + point.percentage / 2) * 360 / 100;
                        if (angle > 90) {
                            angle = angle + 180;
                            $label.find('span.right').css({visibility: 'hidden'});
                        }
                        else {
                            $label.find('span.left').css({visibility: 'hidden'});
                        }
                        $label.css({transform: 'rotate(' + angle + 'deg)'});
                        cumulativePercentage += point.percentage;


                        $('#container').append($label);

                    });
                    $('div.outerContainer').show();
                }
            }
        },
        title: {
            text: null
        },
        yAxis: {
            title: {
                text: 'Total percent market share'
            }
        },
        plotOptions: {
            pie: {
                borderColor: 'rgb(243, 243, 243)',
                borderWidth: 2,
                shadow: false,
                center: ['50%', '50%'],
                colors: ['rgb(77, 196, 215)', 'rgb(50, 68, 132)', 'rgb(85, 119, 183)']
            }
        },
        tooltip: {
            enabled: false
        },
        series: [{
                type: 'pie',
                name: 'Votes',
                data: [
                    ['Yes', 9],
                    ['No', 5],
                    ['Undecided', 2]
                ],
                size: '90%'
            }]
    });
    div#container{
        position:relative;
    }
    div.outerContainer{
        width:600px;
        height:40px;
        position:absolute;
        top:280px;
        display:none;
        color:white;
        font-family:Helvetica, Arial, Sans;
        font-size:16px;
        font-weight:bold;
        text-transform:uppercase;
    }
    div.outerContainer > span{
        float:left;
        width:300px;
        text-align:center;
        height:40px;
        line-height:40px;
    }
<div id="container" style="height: 600px; width: 600px;"></div>

<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.highcharts./highcharts.js"></script>

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744289183a4566949.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信