HTML/JS Canvas 甜甜圈图 如何创建重叠的圆形笔画?

HTML/JS Canvas Donut Chart How to create round strokes with overlap?

我的圆环图无法正常工作,这是我的问题。我想创建一个这样的圆环图:

但是我的甜甜圈图现在是这样的:

如您所见,笔划在正确的方向上没有重叠。我想这可能是因为我开始从右到左画笔画。相反,它应该从左到右绘制它们,所以左边的“圆角端”是可见的,而不是右边的圆角端。

这是我目前尝试过的方法:

//function to draw the donut chart, ctx = context, cx - cy = position, radius and arcwith
dmbChart(ctx, cx, cy, radius, arcwidth) {
   var tot = 0;
   var accum = 0;
   var PI = Math.PI;
   var PI2 = PI * 2;
   var offset = -PI/2;

   for(var i = 0; i < this.canvasValues.length; i++) {
     tot += this.canvasValues[i];
   }  

   //Donut Sectors Color: Draw each stroke based on the value (canvasValues) and Color (canvasColors)
   for(var i = 0; i < this.canvasValues.length; i++) {
    ctx.lineWidth = arcwidth;
    ctx.beginPath();
    ctx.lineCap = "round";
    ctx.arc(cx, cy, radius, offset + PI2 * (accum/tot), offset + PI2 * ((accum + this.canvasValues[i]) / tot));
    ctx.strokeStyle = this.canvasColors[i];
    ctx.stroke(); 

    accum += this.canvasValues[i];
   }
 }

如你所见,我得到的值是每个笔画应该有多长的百分比和颜色。从顶部开始,我从顶部 -> 右侧 -> 底部 -> 左侧绘制每一个,这就是结果。但是我怎样才能修改它以获得最上面的结果?

编辑: 在@Helder Sepulveda 的帮助下,我现在这样创建了它。我更改了很多计算,修复了更改带来的一些错误。现在唯一的问题是它没有在顶部开始绘制。如您所见,绿色笔划应该从顶部开始:

function dmbChart(ctx, cx, cy, radius, arcwidth) { 
  var canvasValues =  [30, 5, 15, 10, 10, 10, 10, 10];
  var canvasColors = ["#10dc60", "#DDDDDD", "#0cd1e8", "#ffce00", "#7044ff", "#f04141", "#ffea00", "#ee82ee"];
  ctx.lineWidth = arcwidth;
  ctx.lineCap = "round";
 
  
  var accum = canvasValues.reduce((a,b) => a + b, 0);  

  for (var i = canvasValues.length-1; i >= 0; i--) {
    var radians = canvasValues[i] / 100 * 360 * Math.PI / 180

    ctx.beginPath();
    ctx.arc(cx, cy, radius, accum, accum - radians, true);
    ctx.strokeStyle = canvasColors[i];
    ctx.stroke();    
    accum -= radians;
  }
  
  ctx.beginPath();
  ctx.arc(cx, cy, radius, accum, accum - (0.1 / 100 * 360 * Math.PI / 180), true);  
  ctx.strokeStyle = canvasColors[canvasColors.length - 1];
  ctx.stroke();
}

const canvas = document.getElementById("c");
canvas.width = canvas.height = 140;
const ctx = canvas.getContext("2d");

dmbChart(ctx, 70, 70, 50, 30)
<canvas id="c"></canvas>

我正在对 canvasValuescanvasColors 做一些假设来证明一些有用的东西:

function dmbChart(ctx, cx, cy, radius, arcwidth) {
  var accum = 0;
  var PI = Math.PI;
  var PI2 = PI * 2;
  var offset = -PI / 2;
  var canvasValues = [10, 10, 10]
  var canvasColors = ["red", "green", "blue"]
  var tot = canvasValues.reduce((a, b) => a + b, 0)

  ctx.lineWidth = arcwidth;
  ctx.lineCap = "round";

  for (var i = 0; i < canvasValues.length; i++) {
    ctx.beginPath();
    ctx.arc(cx, cy, radius, offset + PI2 * (accum / tot), offset + PI2 * ((accum + canvasValues[i]) / tot));
    ctx.strokeStyle = canvasColors[i];
    ctx.stroke();
    accum += canvasValues[i];
  }

  ctx.beginPath();
  ctx.arc(cx, cy, radius, offset, offset);
  ctx.strokeStyle = canvasColors[0];
  ctx.stroke();
}

const canvas = document.getElementById("c");
canvas.width = canvas.height = 140;
const ctx = canvas.getContext("2d");

dmbChart(ctx, 70, 70, 50, 30)
<canvas id="c"></canvas>

想法是在循环结束时用第一个值(和颜色)绘制最后一个 "short" 弧线

我还移出了循环中的几行:

  ctx.lineWidth = arcwidth;
  ctx.lineCap = "round";

可以在循环之前设置一次


这就是我们在评论中所说的反转方向

function dmbChart(ctx, cx, cy, radius, arcwidth) {
  var PI = Math.PI;
  var PI2 = PI * 2;
  var offset = -PI / 2;
  var canvasValues = [10, 10, 10]
  var canvasColors = ["red", "green", "blue"]
  var tot = canvasValues.reduce((a,b) => a + b, 0)
  var accum = tot;
  
  ctx.lineWidth = arcwidth;
  ctx.lineCap = "round";

  for (var i = canvasValues.length-1; i >= 0; i--) {
    ctx.beginPath();
    ctx.arc(cx, cy, radius, offset + PI2 * (accum / tot), offset + PI2 * ((accum + canvasValues[i]) / tot));
    ctx.strokeStyle = canvasColors[i];
    ctx.stroke();    
    accum -= canvasValues[i];    
  }

  ctx.beginPath();
  p = offset + PI2 * ((tot + canvasValues[canvasValues.length-1]) / tot)
  ctx.arc(cx, cy, radius, p, p);  
  ctx.strokeStyle = canvasColors[canvasColors.length-1];
  ctx.stroke();
}

const canvas = document.getElementById("c");
canvas.width = canvas.height = 140;
const ctx = canvas.getContext("2d");

dmbChart(ctx, 70, 70, 50, 30)
<canvas id="c"></canvas>