設(shè)計(jì)一個(gè)靈活的、可維護(hù)CSS和SVG餅圖SVG

SVG解決方案

SVG做圖形化任務(wù)變得簡單,餅圖自然也是可以的,各種復(fù)雜的效果都是可以做出來,這里主要是分享一些技巧。

讓我們從一個(gè)簡單的圓開始:

<svg?width="100"?height="100">
<circle?r="30"?cx="50"?cy="50"?/>
</svg>

然后給這個(gè)圓附上一些簡單的樣式:

circle?{
??fill:?yellowgreen;
??stroke:?#655;
??stroke-width:?30;
}
注:你可能已經(jīng)知道,CSS屬性同樣適用于SVG元素,考慮到可移植性,這將是會(huì)很方便的。

圖九:我們的起點(diǎn):一個(gè)綠色的SVG圓,填充色為#655

圖九顯示,SVG strokes不僅僅包含stroke和stroke-width屬性。它還包含一些不是很常用的屬性來微調(diào)strokes。stroke-dasharray就是其中之一。它是為了創(chuàng)建虛的strokes。例如,我們可以這樣用:

stroke-dasharray:?20?10;

圖十:一個(gè)簡單的dashed stroke,由stroke-dasharray所創(chuàng)建

上面的CSS代碼表示我們要虛實(shí)相間的圓(實(shí)線部分寬度為20,間隔部分寬度為10)。到現(xiàn)在為止,你可能想知道這個(gè)SVG與餅圖究竟有啥關(guān)系?當(dāng)我們把實(shí)線部分的寬度設(shè)置為0,間隔部分寬度設(shè)置為大于或等于圓的周長,這樣就變得清晰了。(C = 2πr, so in our case C = 2π × 30 ≈ 189):

stroke-dasharray:?0?189;

圖十一:多個(gè)不同stroke-dasharray值的效果圖;從左到右依次為:0 189;40 149; 95 189; 150 189;

正如你所看到的,圖十一的第一個(gè)SVG把所有的stroke部分移除了,我們只能看到綠色的圓。然而,好玩的是當(dāng)我們開始逐漸增加stroke-dasharray屬性的第一個(gè)值時(shí),stroke部分慢慢回來了。由于間隙(gap)部分太大了,我們無法看到更多的實(shí)線部分筆畫(stroke),僅僅只有一個(gè)stroke覆蓋在圓上,看起來就像是我們所指定的圓的周長的百分比。

你可能已經(jīng)開始試圖去弄清楚究竟發(fā)生了什么:如果我們減小圓的半徑到足夠小,以至于完全被筆畫(stroke)所覆蓋,我們最終會(huì)得到類似于餅圖的東西。例如,圖十二,如果你將半徑設(shè)置為25,并且將筆觸的寬度設(shè)置為50會(huì)發(fā)生什么?下面的代碼所呈現(xiàn)出來的圖形如下:

圖十二:我們的SVG慢慢的有點(diǎn)像餅圖了

記住:SVG筆觸總是一半在所對(duì)應(yīng)的元素內(nèi),一半在元素外。將來我們將控制這一行為。

<svg?width="100"?height="100">
??<circle?r="25"?cx="50"?cy="50"?/>
</svg>
circle?{
??fill:?yellowgreen;
??stroke:?#655;
??stroke-width:?50;
??stroke-dasharray:?60?158;?/*?2π?×?25?≈?158?*/
}

現(xiàn)在,把它變成一個(gè)我們?cè)谥暗慕鉀Q方案中所呈現(xiàn)的餅圖就變得更簡單了:我們只要在筆觸的下一層畫一個(gè)大的綠色的圓,然后順時(shí)針旋轉(zhuǎn)90°,這樣,是他看起來像是從12點(diǎn)鐘方向開始。由于<svg>元素也是一個(gè)HTML元素,我們同樣可以給它寫樣式:

svg?{
??transform:?rotate(-90deg);
??background:?yellowgreen;
??border-radius:?50%;}

圖十三:最終的SVG餅圖

你可以看到最終的效果圖(圖十三)。這種技術(shù)使得餅圖從0到100%的動(dòng)畫效果更加簡單。我們僅僅需要?jiǎng)?chuàng)建一個(gè)CSS動(dòng)畫,使得屬性stroke-dasharray的值從0 158到158 158;

@keyframes?fillup?{
??to?{?stroke-dasharray:?158?158;?}
}

circle?{
??fill:?yellowgreen;
??stroke:?#655;
??stroke-width:?50;
??stroke-dasharray:?0?158;
??animation:?fillup?5s?linear?infinite;
}

作為額外的改進(jìn),我們可以指定圓的半徑以使得它的周長為(無限接近于)100,這樣我們就能方便的指定stroke-dasharray的長為百分比,而不需要去做額外的計(jì)算。由于周長=2πr,所以,半徑r=100÷2π≈15.915494309,我們可以大約的認(rèn)為是16。我們還將在viewBox屬性中設(shè)置SVG的尺寸而不是直接設(shè)置它的width和height,以使其適應(yīng)期容器的大小。

經(jīng)過這些修改,圖十三餅圖將變成:

<svg?viewBox="0?0?32?32">
??<circle?r="16"?cx="16"?cy="16"?/>
</svg>
svg?{
??width:?100px;?height:?100px;
??transform:?rotate(-90deg);
??background:?yellowgreen;
??border-radius:?50%;
}

circle?{
??fill:?yellowgreen;
??stroke:?#655;
??stroke-width:?32;
??stroke-dasharray:?38?100;?/*?for?38%?*/
}

注意到了沒有?現(xiàn)在設(shè)置百分比將變得非常簡單。當(dāng)然,即使已經(jīng)變得如此簡單了,我們?nèi)匀徊辉敢馊ブ貜?fù)設(shè)置每一個(gè)SVG餅圖。是時(shí)候讓JavaScript為我們提供一點(diǎn)點(diǎn)自動(dòng)化的幫助的時(shí)候了。我們將寫一小段腳本來接管如下的簡單的HTML標(biāo)記:

<div?class="pie">20%</div>
<div?class="pie">60%</div>

并且在每個(gè).pie元素中添加內(nèi)聯(lián)SVG,并附帶所有的必要元素和屬性。它還將添加一個(gè)<title>元素,以幫助讀屏器用戶也能知道餅圖的百分比的值。最終的腳本如下:

$$('.pie').forEach(function(pie)?{
??var?p?=?parseFloat(pie.textContent);
??var?NS?=?"http://www.w3.org/2000/svg";
??var?svg?=?document.createElementNS(NS,?"svg");
??var?circle?=?document.createElementNS(NS,?"circle");
??var?title?=?document.createElementNS(NS,?"title");
??circle.setAttribute("r",?16);
??circle.setAttribute("cx",?16);
??circle.setAttribute("cy",?16);
??circle.setAttribute("stroke-dasharray",?p?+?"?100");
??svg.setAttribute("viewBox",?"0?0?32?32");
??title.textContent?=?pie.textContent;
??pie.textContent?=?'';
??svg.appendChild(title);
??svg.appendChild(circle);
??pie.appendChild(svg);});

這就是SVG的餅圖。你可能會(huì)認(rèn)為CSS的方法更好,因?yàn)樗拇a更簡單并且也更少的外來元素。然而,相對(duì)于純CSS來說,SVG的方法也有一定的長處:

  • 它非常容易添加第三種顏色:只要添加另外一種筆觸,并用stroke-dashoffset設(shè)置筆觸的偏移量。或者,將stroked長度添加到之前的圓的長度。你如何能夠?qū)⒌谌N顏色添加到第一張解決方案做的餅圖里呢?

  • 我們不需要額外擔(dān)心打印問題,因?yàn)镾VG元素被認(rèn)為是內(nèi)容并打印,就像<img>元素一樣。第一種方案取決于背景,因此不會(huì)打印。

  • 我們能夠通過內(nèi)聯(lián)樣式來改變顏色,這意味著我們能夠很方便的通過JavaScript腳本來改變(e.g.,取決于用戶輸入)。第一張方案依賴于偽元素,除了繼承之外,它不支持內(nèi)聯(lián)樣式,這并不總是方便的。

  • 未來的餅圖

    錐形梯度在這里也將非常有幫助。餅圖所需要的是一個(gè)圓形元素,具有兩個(gè)顏色停止點(diǎn)的錐形漸變。 例如,圖5中的40%餅圖將簡單如下:

    .pie?{
    ??width:?100px;?height:?100px;
    ??border-radius:?50%;
    ??background:?conic-gradient(#655?40%,?yellowgreen?0);
    }

    此外,一旦CSS Values Level 3中定義的更新的attr()函數(shù)被廣泛實(shí)現(xiàn),您將能夠使用簡單的HTML屬性來控制百分比:

    background:?conic-gradient(#655?attr(data-value?%),?yellowgreen?0);

    這也使得它非常容易添加第三種顏色。 例如,對(duì)于像上面上顯示的餅圖,我們只需添加兩個(gè)顏色:

    background:?conic-gradient(deeppink?20%,?#fb3?0,?#fb3?30%,?yellowgreen?0);

    錐形梯度在這里也將非常有幫助。

    這個(gè)餅圖就基本做出來了,大家有問題嗎? 同時(shí)大家學(xué)習(xí)可以加入我們的學(xué)習(xí)群 497187010 一起學(xué)習(xí)和交流哦 另有學(xué)習(xí)資料和 學(xué)習(xí)交流 解答大家的學(xué)習(xí)問題

    最后編輯于
    ?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
    平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

    推薦閱讀更多精彩內(nèi)容