使用Chart.js自定义标签

时间:2016-10-02 11:33:34

标签: javascript charts

查看chart.js的advanced tooltipslegend configuration,我不知道如何为我的图表实现以下标签样式。

enter image description here

如何输出此圆环图的每个部分的数字,并将这些数字连接到图表的每个部分?

如果使用Chart.js无法实现,那么有人可以指向一个允许我这样做的图表库吗?

new Chart(document.querySelector('#chart'), {
    type: 'doughnut',
    data: {
        labels: [
            'Red',
            'Blue',
            'Yellow'
        ],
        datasets: [{
            data: [300, 50, 100],
            backgroundColor: [
                '#FF6384',
                '#36A2EB',
                '#FFCE56'
            ],
            hoverBackgroundColor: [
                '#FF6384',
                '#36A2EB',
                '#FFCE56'
            ]
        }]
    },
    options: {
        legend: {
            display: false
        }
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.min.js"></script>

<canvas id="chart" width="400" height="400"/>

2 个答案:

答案 0 :(得分:3)

我发现chartjs很难处理(但是它很好用)。您可以尝试D3,它是高度可定制的。它使用svgs而不是canvas创建图表,因此元素更易于访问和使用。

这是代码,但它不会在原地运行,因为它需要带有数据的外部CSV文件,以及防止CORs错误的Web服务器。这是您的数据的CSV(data.csv):

percentage_label,percentage
19,19
10,10
32,32
39,39

var width = 960,
    height = 500,
    radius = Math.min(width, height) / 2;

var color = d3.scale.ordinal()
    .range(["#fdb92e", "#c02f8e", "#1aaaa9", "#ffffff"]);

var arc = d3.svg.arc()
    .outerRadius(radius - 70)
    .innerRadius(radius - 180);

var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) { return d.population; });

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

d3.csv("data.csv", type, function(error, data) {
  if (error) throw error;

  var g = svg.selectAll(".arc")
      .data(pie(data))
    .enter().append("g")
      .attr("class", "arc");

  g.append("path")
      .attr("d", arc)
      .style("fill", function(d) { return color(d.data.percentage_label); })
      .style("stroke-width","0px");

  g.append("text")
      .attr("transform", function(d) { 
    return "translate(" + ( (radius + 30) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) + ", " + ( -1 * (radius - 10) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +")";})
      .attr("dy", ".5em")
      .style("fill","#ffffff")
      .style("font-size","40px")
      .text(function(d) { return (d.data.percentage_label + "%"); });
     
    g.append("circle")
      .attr("transform", function(d) {return "translate(" + arc.centroid(d) + ")";})
      .attr("r", 5)
      .style("fill","#ffffff");
    g.append("circle")
      .attr("transform", function(d) {return "translate(" + ( (radius - 20) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) + ", " + ( -1 * (radius - 50) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +")";})
      .attr("r", 5)
      .style("fill","#ffffff");
      
      function lineCoordinates(d,x) {
          /* x: coordinate to return */
          //not the most efficient method
          var pa = [];
          var p1 = arc.centroid(d);
          pa.push(p1[0]);
          pa.push(p1[1]);
          pa.push( (radius - 20) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) );
          pa.push( -1 * (radius - 50) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) );
          return pa[x];
      }
    g.append("line")
      .style("stroke","white")
      .style("stroke-width","2px")
      .attr("x1",function(d) { return lineCoordinates(d,0);})
      .attr("y1", function(d) { return lineCoordinates(d,1);})
      .attr("x2", function(d) { return lineCoordinates(d,2);})
      .attr("y2", function(d) { return lineCoordinates(d,3);});
});


function type(d) {
  d.population = +d.percentage_label;
  return d;
}
body {
    background-color: #F68135;
}

.arc text {
  font: 10px sans-serif;
  text-anchor: middle;
}

.arc path {
  stroke: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

我的结果相当接近:

enter image description here

以下是我对基本D3圆环图进行的修改(基于此示例:https://bl.ocks.org/mbostock/3887193):

  • 改变了内半径和半径(半径?)
  • 更改颜色(这是scale.ordinal部分)
  • 为标签添加了样式
  • 将标签从片段的中心移出(因为涉及一些弧形数学,这很有帮助:Label outside arc (Pie chart) d3.js
  • 为标注线的端点添加了一对圆圈
  • 为标注添加了行
  • 添加了一个小函数(lineCoordinates),使定位数学更容易处理

我确信这一切都可以削减并提高效率。我还建议使分段颜色与标签/标注颜色不同(一个标注在最后一个分段上丢失)。

我没有相同的标签字体,但因为这是使用SVG完成的,所以您可以轻松地使用样式更改字体。 Chartjs的情况并非如此(当我尝试修改Chartjs中的标签样式时遇到了同样的问题)。

D3具有比Chartjs更陡峭的学习曲线,但是一旦掌握了它,你几乎可以做任何与它相关的图形。官方网站在这里https://d3js.org/

答案 1 :(得分:1)

Custom positioning of individual point labels is possible with Charts.js Data Labels Plugin.

Source: https://github.com/chartjs/chartjs-plugin-datalabels

The radial positioning is illustrated here: https://chartjs-plugin-datalabels.netlify.com/guide/positioning.html

Positioning example