先上效果圖:css
這種圖形你們應該都見過,俗稱儀表盤,固然,上圖只是個最基本的儀表盤架子,可能在實際場景中還會其餘不少花裏胡哨的點綴,那些暫且無論,不是關鍵,這東西常常見到,但還沒親自上手在代碼層面實現過,最近作的一個需求剛好有這個場景,這裏概括一下html
大部分狀況下,對於這種偏可視化的元素,通常都選擇使用 canvas
來進行繪製,如今已經 9120
年了,線上使用 canvas
徹底沒問題git
儀表盤總體是一個複雜圖形,而複雜圖形是由簡單圖形組合而成,只要把全部組成這個儀表盤的簡單圖形繪製出來,再進行組合,整個儀表盤天然也就繪製出來了github
因此,首先對儀表盤進行分解,分解成 canvas
能繪製出的基本圖形,其主體其實就兩個圓弧,一個是底部藍色的半圓軌道,一個是表明進度的紅色圓弧,其實都是圓弧,canvas
恰好有繪製圓弧的能力,即:web
ctx.arc
複製代碼
至於動態繪製,只須要配合 requestAnimationFrame
便可canvas
const trackW = 6
const rx = 500
const ry = 500
const radius = 400
const innerLineW = 20
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
function draw (toAngle, currentAngle = Math.PI) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 半圓軌道
ctx.beginPath()
ctx.strokeStyle = '#ad80fc'
ctx.lineWidth = trackW
ctx.arc(rx, ry, radius, Math.PI, 0, false)
ctx.stroke()
// 圓弧
ctx.beginPath()
ctx.lineCap = 'round'
ctx.strokeStyle = '#fe4d55'
ctx.lineWidth = innerLineW
ctx.arc(rx, ry, radius, Math.PI, currentAngle, false)
ctx.stroke()
if (currentAngle < toAngle) {
currentAngle += 0.02
if (currentAngle > toAngle) currentAngle = toAngle
requestAnimationFrame(() => {
draw(toAngle, currentAngle)
})
}
}
draw(1.5 * Math.PI)
複製代碼
加上變量定義,花括號等幾十行代碼便可完成,因而可知,canvas
繪圖仍是很方便的,因此在可視化領域,例如一些庫或者UI
組件基本上都是以canvas
進行構建瀏覽器
canvas
實質上就是藉助 js
操縱瀏覽器 API
進行渲染,然而 UI
渲染這種事情本應該交給 CSS
來作纔是,感受用 js
直接畫多影響性能啊(實際上並不),哪有 css
來的流暢,實際上,css
徹底能夠作到app
從 css
的角度對儀表盤進行分解,一樣仍是兩個圓弧,經過設置 border-radius
屬性便可讓元素呈現整圓效果,而後再用一個矩形元素進行遮罩,決定展示出來的部分,即爲圓弧,經過控制遮罩的面積來呈現動態繪製的效果svg
<div class="arc-wrapper">
<p class="track-arc"></p>
<div class="round-box">
<p class="round"></p>
</div>
</div>
複製代碼
:root {
--arcRadius: 200px;
--rectWidth: calc(var(--arcRadius) * 2);
--trackWidth: 4px;
--roundWidth: 10px;
}
.arc-wrapper {
position: relative;
margin: 0 auto;
width: var(--rectWidth);
height: var(--arcRadius);
overflow: hidden;
background-color: pink;
}
.track-arc {
width: 100%;
height: var(--rectWidth);
box-sizing: border-box;
border-radius: 50%;
border: var(--trackWidth) solid #ad80fc;
}
.round-box {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
transform-origin: 50% 100%;
transform: rotate(-45deg);
z-index: 20;
}
.round {
width: 100%;
height: var(--rectWidth);
box-sizing: border-box;
border-radius: 50%;
border: var(--roundWidth) solid #fe4d55;
}
複製代碼
其實沒多少代碼,也沒什麼難以理解的,只不過效果彷佛微調:wordpress
因爲圓弧的線是存在寬度的,並非數學意義上的能夠忽略,canvas
繪製圓弧,是根據圓心座標和半徑進行繪製的,繪製出來的圓弧會自動根據圓弧 line
的寬度進行調整,即圓弧的半徑是圓弧線的中心位置與圓心座標距離
而經過 css
繪製的圓弧,此圓弧的半徑則是圓弧最外層邊線與圓心的座標距離:
知道了問題其實就好解決了,只要縮減軌道半圓的半徑,並對其進行必定的偏移便可:
.track-arc {
--trackArcSize: calc(var(--rectWidth) - var(--roundWidth) + var(--trackWidth));
/* 尺寸改變 */
width: var(--trackArcSize);
height: var(--trackArcSize);
box-sizing: border-box;
border-radius: 50%;
border: var(--trackWidth) solid #ad80fc;
/* 位置偏移 */
transform: translate(calc(var(--roundWidth) / 2 - var(--trackWidth) / 2), calc(var(--roundWidth) / 2 - var(--trackWidth) / 2));
}
複製代碼
而後就順眼多了:
然而,還有個問題,通常爲了呈現更加圓潤的效果,設計稿上圓弧的斷點處通常都是圓頭:而上述呈現出來的效果是直接截斷的:
通常人之因此不使用 css
來繪製儀表盤,基本都是由於這個緣由,canvas
簡簡單單經過設置一個 ctx.lineCap = 'round'
就能解決的問題。彷佛 css
無解了
乍一看好像確實沒什麼好辦法,但稍微思考下,這不就是一個圓角嗎,徹底在css
能力範圍內啊,只不過實現的方式不太那麼直接罷了
方法很簡單,就是使用一個圓角矩形覆蓋在圓弧的頂端,將圓弧自己的矩形頂端覆蓋住,圓角矩形當作是圓弧的頂端,這樣視覺上看起來不就是圓頭了嗎
<div class="round-box">
<p class="round"></p>
<p class="dot-r-box">
<span class="dot-r"></span>
</p>
</div>
複製代碼
.dot-r-box {
position: absolute;
right: 0;
bottom: 0;
width: var(--roundWidth);
height: var(--dotHeight);
background-color: var(--backColor);
}
.dot-r {
display: inline-block;
width: 100%;
height: 100%;
/* 這裏的100px只是爲了呈現出最大限度的圓角 */
border-bottom-left-radius: 100px;
border-bottom-right-radius: 100px;
background-color: var(--roundColor);
}
複製代碼
效果以下:
圓角頂端 get
一樣的,圓弧左邊的頂端也能夠這麼作
不過左邊這個頂端有個稍微須要注意的地方,由於其存在的目的是爲了當作圓弧的左斷點,可是當進度爲 0
的時候,圓弧應該是徹底不展示的,或者當進度很小的時候,圓弧應該展示的長度尚未 dot-l
的高度大,這樣就露餡了:
不過呢轉而又一想,通常實際場景中,就算進度爲 0
,咱們其實爲了看起來更符合常識直覺,也會讓圓弧展示一點點出來,只要 dot-l
的高度不是太大,或者說只要圓弧的寬度不要太寬,其實預留的這點圓弧徹底就能夠 cover
住了,不至於露餡
SVG
意爲可縮放矢量圖形,既然是圖形固然就能實現圖形,因爲其專業性,相比於上述兩種方法來講,SVG
的實現更加簡單
首先,定義一段 SVG
片斷:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="border: 1px solid red; width: 500px; height: 300px;">
<path fill="none" stroke-linecap="round" class="outerArc" />
<path fill="none" stroke-linecap="round" class="innerArc" />
</svg>
複製代碼
兩個 path
元素,第一個 outerArc
用於繪製半圓軌道,第二個用於繪製真正的進度條,經過設置這兩個 path
的 d
屬性,便可實現效果,實現的方法有不少,本文選取的方法是經過控制 path
的 stroke-dasharray
和 stroke-dashoffset
進行實現,不熟悉這兩個屬性的能夠參考文章:
效果以下:
css
的新特性 var
和 calc
還挺好用的嘛
本文示例的 Live Demo已經上傳,感興趣的能夠親自試下