方案1: border + clip-path
画圆
直接使用用border画圆
// html
<div class="bg"></div>
// css
.bg {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
border: 10px solid #000000;
border-radius: 50%;
}
进度条
使用border + clip-path完成进度条逻辑。js辅助控制
// html
<div class="progress" id="progress"></div>
// css
.progress {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
border: 10px solid red;
border-radius: 50%;
}
// js
function getPathByDeg(deg) {
const xLength = Math.sin(deg);
const yLength = Math.cos(deg);
const xPos = 1 + xLength;
const yPos = 1 - yLength;
if(deg <= Math.PI / 2) {
return `(
50% 0%,
${xPos / 2 * 100}% 0%,
${xPos / 2 * 100}% ${yPos / 2 * 100}%,
50% 50%
)`
} else if(deg > Math.PI / 2 && deg <= Math.PI) {
return `(
50% 0%,
100% 0%,
100% ${yPos / 2 * 100}%,
${xPos / 2 * 100}% ${yPos / 2 * 100}%,
50% 50%
)`
} else if(deg > Math.PI && deg < Math.PI / 2 * 3) {
return `(
${xPos / 2 * 100}% ${yPos / 2 * 100}%,
50% 50%,
50% 0%,
100% 0%,
100% 100%,
${xPos / 2 * 100}% 100%,
${xPos / 2 * 100}% ${yPos / 2 * 100}%,
50% 50%
)`
} else if(deg >= Math.PI / 2 * 3) {
return `(
${xPos / 2 * 100}% ${yPos / 2 * 100}%,
50% 50%,
50% 0%,
100% 0%,
100% 100%,
0% 100%,
0% ${yPos / 2 * 100}%,
${xPos / 2 * 100}% ${yPos / 2 * 100}%,
50% 50%
)`
}
}
function draw() {
const path = getPathByDeg(currentDegree);
progressDom.style.clipPath = `polygon${path}`;
requestAnimationFrame(function () {
currentDegree = (currentDegree + Math.PI / 180) % (2 * Math.PI);
draw();
});
}
const progressDom = document.getElementById("progress");
let currentDegree = 0;
draw();
clip-path裁剪方式创建元素的可显示区域。区域内的部分显示,区域外的隐藏。实际原理是这样的
方案2: svg
画圆
使用circle + stroke属性
stroke: 定义了给定图形元素的外轮廓的颜色,用在svg的circle上,也就类似于边框
stroke-width 属性指定了当前对象的轮廓的宽度(注意这个宽度的变化是向图形内外同时扩大的,比如circle的半径是50px, stroke-width为10px,则会获得45px半径的园和10px的stroke边框)
// 部分代码
<circle
:cx="ringOption?.ringCenterX"
:cy="ringOption?.ringCenterY"
:r="ringOption?.ringRadius"
fill="none"
:stroke="ringOption?.ringBgColor"
:stroke-width="ringOption?.ringWidth"
/>
便可以获得一个圆形图
进度条
stroke-dasharray: 这个比较复杂,可以参考MDN上的属性说明,简单来说,就是控制stroke的长度。
于是,我们可以在上面的svg下再贴一个circle作为进度条
// 部分代码
<circle
:cx="ringOption?.ringCenterX"
:cy="ringOption?.ringCenterY"
:r="ringOption?.ringRadius"
fill="none"
stroke="url(#gradientColor)"
:stroke-width="ringOption?.ringWidth"
:stroke-dasharray="`${ringPercent[index]} ${ringOption?.ringLength}`"
/>
这个方案比使用border + clip-path更加灵活,毕竟svg的还有很多功能可以使用
方案3: canvas
这种就没有写demo了,原理应该和上面两种方式类似是两个园叠加。可以参照上面的实现思路 + canvas api实现