Reputation: 396
I have the problem that my Donut Chart isn't working as I want it to do. I want to create a Donut Chart like this one:
But my Donut Chart looks like this at the moment:
As you can see the strokes don't overlap in the right direction. I think this might be, because I start to draw the strokes from right to left. Instead it should draw them from left to right, so the left "rounded end" is visible not the right rounded end.
This is what I have tried so far:
//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];
}
}
As you can see I get the values which are the percentages how long the each stroke should be and the color. Starting on top I draw each one from top -> right -> bottom -> left and this is the result. But how can I modify it to get the result on top?
Edit: With the help of @Helder Sepulveda I created it like this now. I changed a lot of the calculations fixed some bugs which came with the changes. The only problem now is that it doesn't start to draw at the top. As you can see the green stroke should start on the top:
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>
Upvotes: 1
Views: 978
Reputation: 17594
I'm making some assumptions on canvasValues
and canvasColors
to show something working:
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>
The idea is to draw one last "short" arc with the first value(and color) at the end of the loop
I also moved a couple of lines out of the loop:
ctx.lineWidth = arcwidth;
ctx.lineCap = "round";
that could be set just once before the loop
And here is what we talked about in the comments inverting the direction
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>
Upvotes: 1