我创建了一个圆环图。
我试过做一个圆角的圆弧,但是由于我的数学不好没能成功。所以我在每个圆弧的 startAngle 和 endAngle 上添加了圆圈。添加了 lineWidth 来模拟间距。
问题是重叠——每个角末端的圆与下一个弧重叠。 如何避免与此设计剩余的重叠?
代码如下:
"use strict";
const canvas = document.getElementById("myCanvas");
canvas.width = 400;
canvas.height = 400;
const ctx = canvas.getContext("2d");
const PI = Math.PI;
const TAU = PI * 2;
function drawSlice(
ctx,
x,
y,
radius,
startAngle,
endAngle,
fillColor,
strokeColor,
cutout,
lineWidth
) {
ctx.fillStyle = fillColor;
ctx.strokeStyle = strokeColor;
ctx.save();
ctx.translate(x, y);
ctx.beginPath();
ctx.arc(
((radius + (radius * cutout) / 100) / 2) * Math.cos(endAngle),
((radius + (radius * cutout) / 100) / 2) * Math.sin(endAngle),
(radius - (radius * cutout) / 100) / 2 + lineWidth / 2,
0,
TAU
);
ctx.closePath();
ctx.fill();
ctx.lineWidth = lineWidth;
ctx.stroke();
ctx.beginPath();
ctx.arc(
((radius + (radius * cutout) / 100) / 2) * Math.cos(startAngle),
((radius + (radius * cutout) / 100) / 2) * Math.sin(startAngle),
(radius - (radius * cutout) / 100) / 2 + lineWidth / 2,
TAU,
0
);
ctx.fill();
ctx.stroke();
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.arc(x, y, (radius * cutout) / 100, endAngle, startAngle, true);
ctx.closePath();
ctx.fill();
ctx.stroke(); // enables to see overlap
ctx.restore();
}
class Doughnut {
constructor(options) {
this.options = options;
this.canvas = options.canvas;
this.ctx = ctx;
this.x = this.canvas.width / 2;
this.y = this.canvas.height / 2;
this.colors = options.colors;
this.totalValue = [...Object.values(this.options.data)].reduce(
(a, b) => a + b,
0
);
this.radius = Math.min(this.x, this.y) - options.padding;
}
draw() {
let colorIndex = 0;
let startAngle = -PI / 2;
for (const i in this.options.data) {
const value = this.options.data[i];
const sliceAngle = (TAU * value) / this.totalValue;
const endAngle = startAngle + sliceAngle - this.options.spacing / 100;
drawSlice(
this.ctx,
this.x,
this.y,
this.radius,
startAngle,
endAngle,
this.colors[colorIndex % this.colors.length],
"#FFF",
70,
10
);
startAngle += sliceAngle;
colorIndex++;
}
}
}
let CustomDoughnut = new Doughnut({
canvas,
padding: 20,
spacing: 0,
data: {
TV: 5,
Desktop: 5,
Phone: 5,
Laptop: 5,
},
colors: ["#80DEEE", "#FFE0E2", "#FFABE1", "#CE93DE"],
});
CustomDoughnut.draw();
<canvas id="myCanvas"></canvas>
简单的东西怎么样,比如用笔画画...
请参阅下面的示例代码:
const canvas = document.getElementById("myCanvas");
canvas.width = 200;
canvas.height = 200;
const ctx = canvas.getContext("2d");
ctx.lineCap = "round"
const PI = Math.PI;
const TAU = PI * 2;
function drawSlice(x, y, radius, startAngle, endAngle, color, lineWidth) {
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth
ctx.arc(x, y, 80, startAngle, endAngle);
ctx.stroke();
}
class Doughnut {
constructor(options) {
this.options = options;
this.x = canvas.width / 2;
this.y = canvas.height / 2;
this.colors = options.colors;
this.totalValue = [...Object.values(this.options.data)].reduce( (a, b) => a + b, 0);
this.radius = Math.min(this.x, this.y) - options.padding;
}
draw() {
let colorIndex = 0;
let startAngle = -PI / 2;
for (const i in this.options.data) {
const value = this.options.data[i];
const sliceAngle = (TAU * value) / this.totalValue;
const endAngle = startAngle + sliceAngle - this.options.spacing / 100;
drawSlice(this.x,this.y, this.radius, startAngle, endAngle, this.colors[colorIndex % this.colors.length],40);
startAngle += sliceAngle;
colorIndex++;
}
drawSlice(this.x, this.y, this.radius, -PI / 2, -PI / 2+0.01, this.colors[0], 40);
}
}
let CustomDoughnut = new Doughnut({
padding: 20,
spacing: 0,
data: {
TV: 5,
Desktop: 5,
Phone: 3,
Laptop: 7,
},
colors: ["red", "blue", "cyan", "pink"],
});
CustomDoughnut.draw();
<canvas id="myCanvas"></canvas>
你可以看到我已经重构了你的
function drawSlice
不再保存,恢复或翻译,我们只调用一次圆弧,我确实将半径硬编码为80你可以稍后更改。