本文主要提供了:
- svg實現(xiàn)可交互環(huán)形圖的流程(只提供整體流程,沒有全部代碼),如果你的項目需要環(huán)形圖,你又不想引入圖表類插件,建議可以手寫一下。
- 純css實現(xiàn)的靜態(tài)/動態(tài) 的
扇形/環(huán)形進度條,順手用相同的方式制作了一個特別沒用的環(huán)形圖。。。真的是特別沒用。順便一提,環(huán)形進度條是 頭條前端社招 的一道面試題。。。
svg繪制環(huán)形圖和一些需要注意的點
來看看一個簡易的環(huán)形圖demo!不知道怎么把鼠標(biāo)也錄進去,提醒的浮窗在鼠標(biāo)右上角6px的位置。。。大致就是這樣吧,蠻好玩的

主要也就這么些東西
- 對應(yīng)的DOM結(jié)構(gòu)
- svg扇形繪制的方法
- 扇形繪制時候需要注意的點
- 數(shù)據(jù)展示的引導(dǎo)線和文案的繪制
- 數(shù)據(jù)引導(dǎo)線的防重疊避讓
- 文案的右對齊
- 鼠標(biāo)懸浮數(shù)據(jù)區(qū)域后的額外繪制和懸浮提示
第一步:對應(yīng)dom結(jié)構(gòu)
用的vue+jsx,大致內(nèi)容如下,循環(huán)體沒寫,所有內(nèi)容的id隨循環(huán)體的index變化即可,這里是單個環(huán)上數(shù)據(jù)塊的代碼,path用于畫扇形,polyline用于畫數(shù)據(jù)引導(dǎo)線,text是描述文本,分為兩塊,一個用來寫數(shù)據(jù)量,一個用于描述數(shù)據(jù)內(nèi)容。最后的circle用于把扇形遮擋成環(huán)形
<svg width="300px" height="223px">
<path
id="ring1"
onMouseenter={this.larger.bind(this, xxx)}
onMouseleave={this.smaller.bind(this, xxx)}
onClick={this.sendMessage.bind(this, xx)}
fill="#df3849"
/>
<polyline
id="line1"
onMouseenter={this.larger.bind(this, xxx)}
onMouseleave={this.smaller.bind(this, xxx)}
style="fill:transparent;stroke:#df3849;stroke-width:1"
/>
{chapterContent.task.un_submit && (<text
id="text1"
onMouseenter={this.larger.bind(this, xxx)}
onMouseleave={this.smaller.bind(this, xxx)}
onClick={this.sendMessage.bind(this, xx)}
>
<tspan class="svg-num" fill="#df3849" id="text11">
{chapterContent.task.un_submit}
</tspan>
<tspan class="svg-word" id="text12">
未提交
</tspan>
</text>
<circle cx="150" cy="115" r="37" fill="#FFF" />
</svg>
)}
第二步:svg扇形的繪制
繪制扇形的核心就是定義<path>的路徑,代碼如下
let path = document.getElementById(pathId)
/**
數(shù)組內(nèi)參數(shù)對應(yīng)的內(nèi)容是,
0~2的M代表moveTo,后面跟起點坐標(biāo);
3~5的L代表lineto,后跟某個坐標(biāo),就是劃從起點到左邊點的線;
6~11的A代表elliptical Arc,是畫橢圓弧操作,后跟兩個半徑,對應(yīng)橢圓的xr和yr;
然后是x-axis-rotation,對應(yīng)X軸的旋轉(zhuǎn)角度
接著是large-arc-flag,對應(yīng)你想要拿這兩個點畫一個鈍角弧還是銳角弧
最后是sweep-flag,順逆時針畫弧,1代表從起點到終點弧線繞中心順時針方向,0代表逆時針方向,在這里我們使用順時針就是畫一個標(biāo)準(zhǔn)的扇形,逆時針。。。大致會畫出一個缺口的圓
12~13是弧的終點坐標(biāo)
14的Z是closepath代表閉合路徑,會把弧的重點和起點連起來形成一個圖形
**/
let descriptions = ["M", 0, 0, "L", x, y, "A", r, r, 0, 1, 1, x1, y1, "Z"]
path.setAttribute("d", descriptions.join(" "))
展示下我自己寫的垃圾函數(shù),大致邏輯就是函數(shù)的參數(shù)為pathId,lineId,textId,或者這里可以換成一個統(tǒng)一的id,然后用字符串操作拼接,我這是在函數(shù)外面就拼接了。。。degree是當(dāng)前數(shù)據(jù)塊應(yīng)該占用的角度,percentage是當(dāng)前數(shù)據(jù)塊所占比例,r是扇形的半徑,offsetR是圖像在svg上的偏移量,還會根據(jù)全局的offsetX和offsetY具體調(diào)整,x和y是上個數(shù)據(jù)塊畫完的終點坐標(biāo),用于當(dāng)前數(shù)據(jù)塊的起點,當(dāng)前數(shù)據(jù)塊畫完后也會return出去一對xy,用于下個環(huán)形的繪制。
drawSector(id, lineId, textId, degree, percentage, r, offsetR, x, y) {
// 如果沒有占比,返回當(dāng)前繪畫的起點
if (percentage == 0) {
return {
x: x,
y: y
}
}
let path = document.getElementById(id)
path.setAttribute(
"transform",
"translate(" +
(offsetR + this.offsetX) +
"," +
(offsetR + this.offsetY) +
")"
)
// 如果占比100%。走額外的圓形繪畫邏輯,結(jié)束后續(xù)的扇形繪畫邏輯
// 這里有個問題就是起點終點重合了似乎畫不出圓,我想的解決方案就是在同一個path內(nèi)畫半圓然后再畫一個半圓
if (percentage == 1) {
let descriptions = [
"M", 0, 0, "L", x, y, "A", r, r, 0, 1, 1, x, -y, "L", x, -y, "A", r, r, 0, 1, 1, x, y, "Z"
]
// 并在90度的位置劃線
this.drawLines(lineId, textId, r, offsetR, 270 - (percentage * 360) / 2)
path.setAttribute("d", descriptions.join(" "))
return false
}
// 正常的扇形 計算第一個點的終點坐標(biāo)
let lenghty = window.Number(percentage * 360 > 180)
let PIdegree = (degree / 180) * Math.PI
// calculatePositions是一個計算坐標(biāo)的函數(shù),其實就是Math.sin和Math.cos然后返回xy坐標(biāo)
let { x1, y1 } = this.calculatePositions(r, PIdegree)
// 畫引導(dǎo)線的函數(shù)
this.drawLines(lineId, textId, r, offsetR, degree - (percentage * 360) / 2)
// y往下是正,x往右是正
let descriptions = ["M", 0, 0, "L", x, y, "A", r, r, 0, lenghty, 1, x1, y1, "Z"]
path.setAttribute("d", descriptions.join(" "))
return {
x: x1,
y: y1
}
}
扇形繪制時候需要注意的點
1.占比為0,把自己的起點直接return出去給下一個環(huán)用
2.占比100%,似乎是需要畫2個半圓,用這種方法起點終點相同畫不出來東西
3.計算環(huán)形占用的角度,并把角度中點坐標(biāo)傳遞給劃線函數(shù),讓引導(dǎo)線從環(huán)形的中間往外指
第三步: 數(shù)據(jù)展示引導(dǎo)線的繪制
大致思路就是從環(huán)形數(shù)據(jù)塊的中點引出去一條線
drawLines(lineId, textId, r, offsetR, halfDegree) {
let path = document.getElementById(lineId)
path.setAttribute(
"transform",
"translate(" +
(offsetR + this.offsetX) +
"," +
(offsetR + this.offsetY) +
")"
)
let descriptions
// 這里會做一些特殊數(shù)據(jù)的特殊待遇。。。比如我這里有一個穩(wěn)定出現(xiàn)在第一個數(shù)據(jù)塊內(nèi)部的子數(shù)據(jù)塊我把他的引導(dǎo)線寫在了右上角。。。
if (lineId == "line5") {
let temp = halfDegree > 15 ? 15 : halfDegree
let { x1, y1 } = this.calculatePositions(r, (temp / 180) * Math.PI)
descriptions = [
`${x1},${y1}`,
`${x1 + 6},${y1 - 55}`,
`${x1 + 110},${y1 - 55}`
]
path.setAttribute("points", descriptions.join(" "))
this.drawText(textId, x1 + 50, y1 - 55, offsetR)
return false
}
let { x1, y1 } = this.calculatePositions(r, (halfDegree / 180) * Math.PI)
// 此處省略1w字的引導(dǎo)線避讓規(guī)則,封裝的很差,沒臉展示
// ...
// 第1,2,3,4象限的普通引導(dǎo)線繪制規(guī)則
if (halfDegree < 90) {
descriptions = [
`${x1},${y1}`,
`${x1 + 10},${y1 - 6}`,
`${x1 + 65},${y1 - 6}`
]
path.setAttribute("points", descriptions.join(" "))
this.drawText(textId, x1 + 30, y1 - 6, offsetR)
this.beforeYPosition = y1 - 6
} else if (halfDegree < 180) {
descriptions = [
`${x1},${y1}`,
`${x1 + 10},${y1 + 6}`,
`${x1 + 65},${y1 + 6}`
]
path.setAttribute("points", descriptions.join(" "))
this.drawText(textId, x1 + 30, y1 + 6, offsetR)
this.beforeYPosition = y1 + 6
} else if (halfDegree < 270) {
descriptions = [
`${x1},${y1}`,
`${x1 - 10},${y1 + 6}`,
`${x1 - 65},${y1 + 6}`
]
path.setAttribute("points", descriptions.join(" "))
this.drawText(textId, x1 - 65, y1 + 6, offsetR)
this.beforeYPosition = y1 + 6
} else {
descriptions = [
`${x1},${y1}`,
`${x1 - 10},${y1 - 6}`,
`${x1 - 65},${y1 - 6}`
]
path.setAttribute("points", descriptions.join(" "))
this.drawText(textId, x1 - 65, y1 - 6, offsetR)
this.beforeYPosition = y1 - 6
}
}
引導(dǎo)線繪制時候需要注意的點
1.從環(huán)形中點開始畫引導(dǎo)線,第1象限往右上偏移,第2象限往右下偏移,第3象限往左上偏移,第4象限往左上偏移,
2.引導(dǎo)線和文本如何避免重疊,這里我省略掉了我不太完善的防重疊代碼,大致思路就是,每次畫完一個引導(dǎo)線,用this.beforeYPosition記錄y軸坐標(biāo)位置,再記錄一個象限狀態(tài)或者角度值,下次繪制的時候發(fā)現(xiàn)y軸坐標(biāo)相差小于某一閾值(比如我這里是35)并且在同一象限,我們就會讓線繞的遠(yuǎn)一點,每個象限會有自己獨特的繞遠(yuǎn)過程,比如下面這段代碼
// 第三象限避讓示例
else if (halfDegree < 270) {
descriptions = [
`${x1},${y1}`, // 正常的起點
`${(x1 - 68) / 2},${y1}`, // 先向左走一截,是為了線不會和環(huán)形重疊
`-68,${y1 - 35}`, // 再向上35進行避讓
`-118,${y1 - 35}` // 往外延伸用于展示數(shù)據(jù)的部分
]
path.setAttribute("points", descriptions.join(" "))
this.drawText(textId, -118, y1 - 35, offsetR)
this.beforeYPosition = y1 - 35
}
第四步: 數(shù)據(jù)展示文案的繪制
在線的上方寫數(shù)字,在下面寫文字,因為文案一般都是固定的,所以位置很好定,但是數(shù)字是后端返回的,長度會變,所以右對齊的時候需要點特殊手段,大致代碼:
drawText(textId, x, y, offsetR) {
let path = document.getElementById(textId)
path.setAttribute(
"transform",
"translate(" +
(offsetR + this.offsetX) +
"," +
(offsetR + this.offsetY) +
")"
)
let path1 = document.getElementById(textId + "2")
this.drawNum(textId, x, y, offsetR)
this.drawPureText(path1, x, y, offsetR)
},
drawPureText(path, x, y) {
path.setAttribute("x", x)
path.setAttribute("y", y + 12)
},
drawNum(textId, x, y) {
let number
let {
un_submit,
wait,
revising,
done,
wanke_unsubmit
} = this.chapterContent.task
switch (textId) {
case "text1":
number = un_submit
break
case "text2":
number = wait
break
case "text3":
number = revising
break
case "text4":
number = done
break
case "text5":
number = wanke_unsubmit
x += 25
break
default:
break
}
if (x > 0) {
// 第1、2象限右對齊
if (number >= 100) {
x += 8
} else if (number >= 10) {
x += 18
} else {
x += 28
}
}
let path = document.getElementById(textId + "1")
path.setAttribute("x", x)
path.setAttribute("y", y - 4)
},
文本繪制時候需要注意的點似乎也就只有1,2象限的右對齊問題
最后一步:鼠標(biāo)懸浮數(shù)據(jù)區(qū)域后的額外繪制和懸浮提示
我這里是監(jiān)聽MouseEenter和MouseLeave然后對相關(guān)的部分進行重新繪制,代碼如下:
larger(index) {
this.showFloatRemind = 1
let { total, un_submit, wait, wanke_unsubmit } = this.chapterContent.task
if (index == 1) {
window.cancelAnimationFrame(this.firstAnimation)
let animation = () => {
this.onlyDrawSector(
"ring" + index,
(un_submit / total) * 360,
un_submit / total,
this.first_range,
65,
0,
-this.first_range
)
this.first_range += 0.5
if (this.first_range < 70) {
this.firstAnimation = window.requestAnimationFrame(animation)
}
}
animation()
}
// 省略其他index
},
smaller(index) {
this.showFloatRemind = 0
let { total, un_submit, wait, wanke_unsubmit } = this.chapterContent.task
if (index == 1) {
window.cancelAnimationFrame(this.firstAnimation)
let animation = () => {
this.onlyDrawSector(
"ring" + index,
(un_submit / total) * 360,
un_submit / total,
this.first_range,
65,
0,
-this.first_range
)
this.first_range -= 0.5
if (this.first_range > 65) {
this.firstAnimation = window.requestAnimationFrame(animation)
}
}
animation()
}
}
需要注意的點就是利用requestAnimationFrame,和在切換狀態(tài)時記得清除掉無用的requestAnimationFrame狀態(tài),防止出現(xiàn)bug
扇形
今年3月份還是5月份看了個挺有趣的技術(shù)分享,講的是css變量的應(yīng)用,里面主要講的是如何用css變量+opacity+rotate實現(xiàn)一個扇形,具體方式如下
<!DOCTYPE html>
<html>
<head>
<style>
.pie-simple {
width: 128px;
height: 128px;
background-color: white;
border-radius: 50%;
overflow: hidden;
}
.pie-left,
.pie-right {
width: 50%;
height: 100%;
float: left;
position: relative;
overflow: hidden;
}
.pie-left::before,
.pie-right::before,
.pie-right::after {
content: '';
position: absolute;
width: 100%; height: 100%;
background-color: red;
}
.pie-left::before {
left: 100%;
transform-origin: left;
transform: rotate(calc(3.6deg * (var(--percent) - 50)));
opacity: calc(99999 * (var(--percent) - 50));
}
.pie-right::before {
right: 100%;
transform-origin: right;
transform: rotate(calc(3.6deg * var(--percent)));
}
.pie-right::after {
opacity: calc(99999 * (var(--percent) - 50));
}
</style>
</head>
<body>
<div class="pie-item">
<p>10%大小</p>
<div class="pie-simple" style="--percent: 10;">
<div class="pie-left"></div>
<div class="pie-right"></div>
</div>
</div>
<div class="pie-item">
<p>40%大小</p>
<div class="pie-simple" style="--percent: 40;">
<div class="pie-left"></div>
<div class="pie-right"></div>
</div>
</div>
<div class="pie-item">
<p>80%大小</p>
<div class="pie-simple" style="--percent: 80;">
<div class="pie-left"></div>
<div class="pie-right"></div>
</div>
</div>
<div class="pie-item">
<p>99%大小</p>
<div class="pie-simple" style="--percent: 99;">
<div class="pie-left"></div>
<div class="pie-right"></div>
</div>
</div>
</body>
</html>
這只是一個靜態(tài)的扇形展示,核心思想是利用css變量控制opacity,opacity為負(fù)數(shù)被認(rèn)為是0,大于1被認(rèn)為是1。
效果圖大致就是這樣的:

總結(jié)一下發(fā)生了啥:
- 正方形被一分為二,左邊一個白色矩形div,右邊一個白色矩形div,超出正方形的部分overflow掉
- 左邊div的:before 有背景色有透明度且轉(zhuǎn)動 ,負(fù)責(zé)控制扇形超過50%時,左側(cè)部分的顯示
- 右邊div的:after 有背景色有透明度不轉(zhuǎn)動,負(fù)責(zé)控制扇形超過50%后,右側(cè)部分全部顯示
- 右邊div的:before 有背景色不透明且轉(zhuǎn)動 ,負(fù)責(zé)控制扇形小于50%時,右側(cè)部分的顯示
關(guān)于扇形的動畫放在環(huán)形進度條里一起再說
環(huán)形進度條
環(huán)形進度條最直觀的實現(xiàn)方式其實就是一個大的扇形扣上個一個小圓,代碼和上面的差不多,不過扇形/餅狀圖一般可以是靜態(tài)的,但是進度條普遍都是是動態(tài)的,如果讓css變量實現(xiàn)的環(huán)形進度條動起來?主要介紹下面兩個方案:
1. 保留css變量,使用animation來實現(xiàn)動畫
css變量并不支持平滑的過度,但是你可以在固定幀規(guī)定變量的值,你可以寫的足夠細(xì),動畫就足夠順化,但是平時也會經(jīng)??吹侥欠Nduangduangduang~一截一截往前蹦的進度條。
.pie-simple {
animation: round 10s linear infinite;
}
@keyframes round{
0%{--percent: 0;}
10%{--percent: 10;}
20%{--percent: 20;}
30%{--percent: 30;}
40%{--percent: 40;}
50%{--percent: 50;}
60%{--percent: 60;}
70%{--percent: 70;}
80%{--percent: 80;}
90%{--percent: 90;}
100%{--percent: 100;}
}
順帶一說只有Chrome能像上面那么寫,火狐需要把變量和使用到變量的屬性都塞到keyframe里,ie和safari干脆就直接不支持了。。。
我在DOM.style里找不到css變量對應(yīng)的屬性,所以似乎沒法直接通過requestAnimationFrame控制--percent來實現(xiàn)動畫,但是可以在CSSRuler里用js手撕關(guān)鍵幀。下圖是示例

2. 移除css變量,使用animation來實現(xiàn)動畫
因為兼容性和幀的復(fù)雜性問題,實現(xiàn)動畫還是放棄css變量比較好,最直觀的影響就是不能讓opacity實現(xiàn)有效的突變,把opacity放在動畫里會有漸變的過程,所以這里又出現(xiàn)了兩種解決方案:
a.給左側(cè)矩形div增加一個偽類,用于沒有超過50%左側(cè)的白色遮蓋,利用animation的steps()實現(xiàn)opacity的突變,代碼如下
<!DOCTYPE html>
<html>
<head>
<style>
.pie-simple {
position: relative;
width: 128px;
height: 128px;
background-color: white;
border-radius: 50%;
overflow: hidden;
}
.pie-left,
.pie-right {
width: 50%;
height: 100%;
float: left;
position: relative;
overflow: hidden;
}
.pie-left::before,
.pie-right::before,
.pie-left::after,
.pie-right::after{
content: '';
position: absolute;
width: 100%; height: 100%;
background-color: red;
}
.pie-left::after{
background: #fff
}
.pie-left::before {
left: 100%;
transform-origin: left;
animation: fuspin 10s linear infinite;
}
.pie-left::after {
animation: second-half-hide 10s steps(1, end) infinite;
}
.pie-right::before {
right: 100%;
transform-origin: right;
animation: spin 10s linear infinite;
}
.pie-right::after {
animation: second-half-show 10s steps(1, end) infinite;
}
@keyframes spin {
0% { transform: rotate(0); }
100% { transform: rotate(360deg); }
}
@keyframes fuspin {
0% { transform: rotate(180deg); }
100% { transform: rotate(540deg); }
}
@keyframes second-half-hide {
0% { opacity: 1; }
50%, 100% { opacity: 0; }
}
@keyframes second-half-show {
0% { opacity: 0; }
50%, 100% { opacity: 1; }
}
.cover{
width: 120px;
height: 120px;
border-radius: 50%;
background: #fff;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto;
}
</style>
</head>
<body>
<div class="pie-item">
<div class="pie-simple">
<div class="pie-left"></div>
<div class="pie-right"></div>
<div class="cover"></div>
</div>
</div>
</body>
</html>
效果圖如下,gif顯得有點卡,實際是很流暢的,在mac的chrome下左側(cè)會有個縫隙,白色的:after并不能完全蓋住紅色的:before。。。在window的chrome下就沒有
b.只使用2個帶背景色的偽類,利用超出overflow+兩者的動畫錯開實現(xiàn)空白占位和有色占位代碼如下
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.pie-spin {
position: relative;
width: 128px; height: 128px;
background-color: white;
border-radius: 50%;
overflow: hidden;
}
.pie-spin-left,
.pie-spin-right {
width: 50%; height: 100%;
float: left;
position: relative;
overflow: hidden;
}
.pie-spin-left::before,
.pie-spin-right::before {
content: '';
position: absolute;
width: 100%; height: 100%;
background-color: red;
}
.pie-spin-left::before {
left: 100%;
transform-origin: left;
animation: spinWait 3.2s infinite linear;
}
.pie-spin-right::before {
right: 100%;
transform-origin: right;
animation: spinWait 3.2s infinite linear;
}
@keyframes spinWait {
0% { transform: rotate(0deg); }
50%, 100% { transform: rotate(180deg); }
}
@keyframes spinWait {
0%, 50% { transform: rotate(0deg); }
100% { transform: rotate(180deg); }
}
.cover{
width: 120px;
height: 120px;
border-radius: 50%;
background: #fff;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto;
}
</style>
</head>
<body>
<div class="pie-spin">
<div class="pie-spin-left"></div>
<div class="pie-spin-right"></div>
<div class="cover"></div>
</div>
</body>
</html>
效果圖如下,因為只有兩個塊,沒有遮罩層,不顯示的時候躲在對邊等待轉(zhuǎn)動,所以也不會出現(xiàn)那一個小小的縫隙

環(huán)形圖
上面的idea過于舒暢,導(dǎo)致我當(dāng)初第一反應(yīng)就是用css變量或者偽類的旋轉(zhuǎn)和遮蓋來先出一版,調(diào)試了大概一個下午,最后也只能是正常的展示吧,因為一層一層的遮蓋導(dǎo)致懸浮點擊的交互根本無從入手,最后5個數(shù)據(jù)塊,20個偽類層巒疊嶂弄得我十分難受,如果你只是想要一個不能動的環(huán)形圖,也是能夠?qū)崿F(xiàn)的,注意后出現(xiàn)的部分的:before和:after的z-index高于前者就行,代碼如下
<!DOCTYPE html>
<html>
<head>
<style>
.round-container{
position: relative;
height: 150px;
}
.pie-simple {
position: absolute;
width: 130px;
height: 130px;
top: 10px;
left: 60px;
background-color: white;
border-radius: 50%;
overflow: hidden;
/*box-shadow: 1px 1px 1px 3px rgba(0,0,0,0.1)*/
}
.pie-left,
.pie-right {
position: absolute;
width: 50%;
height: 100%;
float: left;
overflow: hidden;
}
.pie-left{
left: 0;
top: 0
}
.pie-right {
left: 50%;
top: 0;
}
.pie-left::before,
.pie-right::before,
.pie-right::after {
content: '';
position: absolute;
width: 100%; height: 100%;
background-color: #df3849;
}
.pie-left::before {
left: 100%;
transform-origin: left;
transform: rotate(calc(3.6deg * (var(--percent) - 50)));
opacity: calc(99999 * (var(--percent) - 50));
}
.pie-right::before {
right: 100%;
transform-origin: right;
transform: rotate(calc(3.6deg * var(--percent)));
}
.pie-right::after {
opacity: calc(99999 * (var(--percent) - 50));
}
.a .pie-left::before{
z-index: 300;
}
.b .pie-left::before{
: 200;
background-color:#6434e5;
}
.c .pie-left::before{
z-index: 100;
background-color:#4d8ef6;
}
.d .pie-left::before{
z-index: 50;
background-color:#69a42f;
}
.a .pie-right::before{
z-index: 300;
}
.b .pie-right::before{
z-index: 200;
background-color:#6434e5;
}
.c .pie-right::before{
z-index: 100;
background-color:#4d8ef6;
}
.d .pie-right::before{
z-index: 50;
background-color:#69a42f;
}
.a .pie-right::after{
z-index: 300;
}
.b .pie-right::after{
z-index: 200;
background-color:#6434e5;
}
.c .pie-right::after{
z-index: 100;
background-color:#4d8ef6;
}
.d .pie-right::after{
z-index: 50;
background-color:#69a42f;
}
.b{
width: 129px;
height: 129px;
top: 10.5px;
left: 60.5px;
}
.c{
width: 128px;
height: 128px;
top: 11px;
left: 61px;
}
.e {
width: 100px;
height: 100px;
top: 25px;
left: 75px;
}
.e .pie-right::after{
z-index: 400;
background-color:#ff8d05;
}
.e .pie-right::before{
z-index: 400;
background-color:#ff8d05;
}
.e .pie-left::before{
z-index: 400;
background-color:#ff8d05;
}
.cover{
position: absolute;
top: 40px;
left: 90px;
width: 70px;
height: 70px;
z-index: 9999;
background-color: white;
border-radius: 50%;
overflow: hidden;
}
</style>
</head>
<body>
<div class="round-container">
<div class="pie-simple a" style="--percent: 20;">
<div class="pie-left"></div>
<div class="pie-right"></div>
</div>
<div class="pie-simple b" style="--percent: 60;">
<div class="pie-left"></div>
<div class="pie-right"></div>
</div>
<div class="pie-simple c" style="--percent: 80;">
<div class="pie-left"></div>
<div class="pie-right"></div>
</div>
<div class="pie-simple d" style="--percent: 100;">
<div class="pie-left"></div>
<div class="pie-right"></div>
</div>
<div class="pie-simple e" style="--percent: 10;">
<div class="pie-left"></div>
<div class="pie-right"></div>
</div>
<div class="cover"></div>
</div>
</body>
<script type="text/javascript">
</script>
</html>
靜態(tài)的效果如下:

因為這個是一層一層蓋住的,你想讓一個環(huán)放大,之前被擋住的地方就漏出來了~所以解決方案是讓每一個的環(huán)都是從上一個環(huán)結(jié)束的位置開始,但是這樣有感覺好麻煩,而且你把鼠標(biāo)浮上去。。。你根本拿不到你想要的event.target[手動捂臉],所以我只能用svg去畫了。。。
最后,感謝看官看到最后~