在 Highcharts 饼图中旋转数据标签

Rotating dataLabels in a Highcharts pie chart

我正在尝试在 Highcharts 饼图的每个部分中旋转和定位数据标签,但感觉自己越来越深入,却没有接近解决方案。希望得到一些提示或建议。

说明预期目标的图形:

我的饼图将分为三个部分。我理想情况下喜欢:

关于从哪里开始的建议,或者让我接近的示例?

$(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.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<div id="container" style="height: 600px; width: 100%;"></div>

我发现旋转标签本身是有问题的,因为当使用 highcharts 旋转它们时,它似乎绕着它们自己的轴旋转。为获得最佳结果,您需要围绕饼图的原点旋转标签。为此,我将绝对定位的 div 直接附加在饼图的顶部,并迭代这些点以根据百分比计算旋转。当然,缺点是外部 div 用于标签,而不是 highcharts 自己的标签函数。

这是我添加的代码:

首先,CSS 包含标签的 CSS 样式,以及饼图本身:

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

然后,自定义load事件代码来计算标签

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

另外,我删除了dataLabels属性。

简要说明:

cumulativePercent 跟踪每个部分贡献了多少馅饼,以便我们可以将标签恰好插入每个部分的中间。我们检查角度是否大于 90 度,这样我们就可以

  1. 翻转标签div使文字不上下颠倒(小于90度则保留)

  2. 根据其方向决定文本应该位于 div 的左侧还是右侧。

查看实际效果:

  $('#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.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>

Highcharts 未提供在饼图中自动旋转数据标签的选项。您可以为数据标签旋转编写自定义函数。

这是一个简单的例子,你可以怎么做:

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

首先我计算所有 Y 值的总和。然后我计算所有饼图中间的角度。然后我将数据标签旋转相同的角度。

示例: http://jsfiddle.net/izothep/j7as86gh/6/

类似主题: