【问题标题】:HTML5 Canvas pie chartHTML5 Canvas 饼图
【发布时间】:2011-08-09 11:56:24
【问题描述】:

我正在尝试创建一个简单的饼图,如下图所示:

图表将显示测验的结果,用户可以选择 a、b 或 c。它们是 10 个问题,每个问题用户只能选择一个选项。

我想要做的是通过传入 a、b 或 c 的值来显示饼图,其中每个段的百分比为 100%。

到目前为止,我有以下内容:

var greenOne = "#95B524";
var greenTwo = "#AFCC4C";
var greenThree = "#C1DD54";

function CreatePieChart() {
  var chart = document.getElementById('piechart');
  var canvas = chart.getContext('2d');
  canvas.clearRect(0, 0, chart.width, chart.height);

  var total = 100;

  var a = 3;
  var b = 4;
  var c = 3;

  for (var i = 0; i < 3; i++) {
    canvas.fillStyle = "#95B524";
    canvas.beginPath();
    canvas.strokeStyle = "#fff";
    canvas.lineWidth = 3;
    canvas.arc(100, 100, 100, 0, Math.PI * 2, true);
    canvas.closePath();
    canvas.stroke();
    canvas.fill();
  }
}
CreatePieChart();
&lt;canvas id="piechart" width="200" height="200"&gt;&lt;/canvas&gt;

颜色特定于段的大小,因此绿色一用于最大,绿色三用于最小。

谢谢

【问题讨论】:

  • 多一点努力可能会有很长的路要走。你到底是什么问题?
  • 我不知道从哪里开始绘制数据和绘制图表

标签: javascript canvas


【解决方案1】:

即使在搜索了 Google 并反复检查了我的弧度值等之后。我仍然遇到了这个问题,所以我创建了一个 jsFiddle 供人们使用作为一个活生生的例子和也将在下面发布代码。 (更新:fiddle v2 中还添加了笔画和标签。)

var canvas = document.getElementById("can");
var ctx = canvas.getContext("2d");
var lastend = 0;
var data = [200, 60, 15]; // If you add more data values make sure you add more colors
var myTotal = 0; // Automatically calculated so don't touch
var myColor = ['red', 'green', 'blue']; // Colors of each slice

for (var e = 0; e < data.length; e++) {
  myTotal += data[e];
}

for (var i = 0; i < data.length; i++) {
  ctx.fillStyle = myColor[i];
  ctx.beginPath();
  ctx.moveTo(canvas.width / 2, canvas.height / 2);
  // Arc Parameters: x, y, radius, startingAngle (radians), endingAngle (radians), antiClockwise (boolean)
  ctx.arc(canvas.width / 2, canvas.height / 2, canvas.height / 2, lastend, lastend + (Math.PI * 2 * (data[i] / myTotal)), false);
  ctx.lineTo(canvas.width / 2, canvas.height / 2);
  ctx.fill();
  lastend += Math.PI * 2 * (data[i] / myTotal);
}
&lt;canvas id="can" width="200" height="200" /&gt;

【讨论】:

  • 我喜欢这个,它超级简单,非常轻巧,不需要任何外部脚本,如 jQuery 等。这对我有好处,因为我计划使用通过部分请求加载的数百个脚本大声笑
  • 这太棒了!我可以补充一点,如果您希望这些段从午夜位置开始,请初始化 var lastend = -1.57。 1.57 是圆弧度数的四分之一。谢谢。
  • 没错,但将其初始化为var lastend = - Math.PI / 2以更好地表明您的意思。 :-)
【解决方案2】:

我喜欢上一个答案,但我觉得它缺乏代码清晰度,并且没有真正涵盖如何使用标签。

为了便于声明,我将值移动到数据对象数组中。其他值,如百分比,我明确声明为数据对象的属性,或作为单独的变量。我认为这样更容易阅读。

如果您对此感兴趣,重构还可以更轻松地将值绑定到输入框。

要了解我的意思并使用这些值,请查看此 CodePen:http://codepen.io/zfrisch/pen/pRbZeb

  var data = [{
    label: "one",
    value: 100,
    color: 'white'
  }, {
    label: "two",
    value: 100,
    color: 'skyBlue'
  }, {
    label: "three",
    value: 100,
    color: 'yellow'
  }];

  var total = 0;
  for (obj of data) {
    total += obj.value;
  }

  var canvas = document.getElementById('myCanvas');
  var ctx = canvas.getContext('2d');
  var previousRadian;
  var middle = {
    x: canvas.width / 2,
    y: canvas.height / 2,
    radius: canvas.height / 2,
  };
  
   //background
  ctx.beginPath();
  ctx.arc(middle.x, middle.y, middle.radius, 0, 2 * Math.PI);
  ctx.closePath();
  ctx.stroke();
  ctx.fillStyle = "black";
  ctx.fill();
   //end of background

  for (obj of data) {
    previousRadian = previousRadian || 0;
    obj.percentage = parseInt((obj.value / total) * 100)
    
    ctx.beginPath();
    ctx.fillStyle = obj.color;
    obj.radian = (Math.PI * 2) * (obj.value / total);
    ctx.moveTo(middle.x, middle.y);
    //middle.radius - 2 is to add border between the background and the pie chart
    ctx.arc(middle.x, middle.y, middle.radius - 2, previousRadian, previousRadian + obj.radian, false);
    ctx.closePath();
    ctx.fill();
    ctx.save();
    ctx.translate(middle.x, middle.y);
    ctx.fillStyle = "black";
    ctx.font = middle.radius / 10 + "px Arial";
    ctx.rotate(previousRadian + obj.radian);
    var labelText = "'" + obj.label + "' " + obj.percentage  + "%";
    ctx.fillText(labelText, ctx.measureText(labelText).width / 2, 0);
    ctx.restore();

    previousRadian += obj.radian;
  }
&lt;canvas id="myCanvas" width="500" height="500" &gt;&lt;/canvas&gt;

【讨论】:

    【解决方案3】:

    我之前遇到过同样的问题,但后来我能够解决这个问题。

    我缺少的是我在上下文中绘制了一个拱门并试图填充它,因此颜色遍布整个圆圈,因为现在上下文仅绑定在从中心到起点的半径线之间的拱门和拱门来约束上下文。

    但是从拱的末端到中心的线没有其他边界,只要我使用以下方法绘制那条线:

    ctx.lineTo(center coordinates of circle);
    

    我有一个完整的饼图边界,所以现在如果我在上下文中填充颜色,它不会散布在整个圆圈内,而是仅限于该饼图。

    【讨论】:

      【解决方案4】:

      这是一个饼图,没有使用外部库,使用 html5 画布:

      See the code

      但最好使用库来绘制图表。在apex-charts 中有一个名为sparkline 的选项,它可以帮助您删除多余的东西并绘制一个最小且干净的图表。

      这是一个使用apex-charts 库的干净甜甜圈图。 (使用sparkline 选项删除多余的东西):

      var options = {
        series: [620, 40],
        labels: ['Finished', 'Unfinished'],
        chart: {
          type: 'donut',
          sparkline: {
            enabled: true,
          }
        },
        plotOptions: {
          pie: {
            donut: {
              labels: {
                show: true,
                total: {
                  showAlways: false,
                  show: true,
                  label: 'Total'
                }
              }
            }
          }
        },
      };
      var chart = new ApexCharts(document.querySelector("#chart"), options);
      chart.render();
      
      

      See it on codepen

      【讨论】:

        猜你喜欢
        • 2019-01-27
        • 1970-01-01
        • 2012-05-18
        • 2014-12-17
        • 2014-11-07
        • 2011-12-09
        • 2011-08-28
        • 1970-01-01
        相关资源
        最近更新 更多