canvas畫餅圖(2)

效果圖

兩個(gè)步驟:

第一步畫一個(gè)扇形
第二步把扇形畫滿360°
  • 來看第一個(gè)步驟埋凯,怎么畫扇形锅减?

看下面的示意圖

原理示意圖
  • 要畫扇形圖脆诉,首先需要知道圓心坐標(biāo)甚亭,然后需要知道半徑,這樣就可以畫出一條線击胜,然后在用畫圓函數(shù)obj.arc在線的終點(diǎn)坐標(biāo)根據(jù)起始角度和終止角度畫出一段弧亏狰,最后在閉合圖形,就能畫出一條弧偶摔,圖中cx暇唾、cy是圓心坐標(biāo),#1是畫出的第一段線辰斋,x策州、y是線的終點(diǎn)坐標(biāo),然后以線的終點(diǎn)坐標(biāo)為弧的起點(diǎn)坐標(biāo)宫仗,即x菱农、y怜庸,加上起始角度(圖中ang1)和終止角度(圖中ang2)畫出一段弧(圖中#2),最后閉合路徑(obj.closePath())即可以畫出圖中所示的一小段弧娇未。
  • 畫扇形步驟開始:
    先獲取canvas對(duì)象:
let c1 = document.getElementById('can');
let gd = c1.getContext('2d');
  1. 給一個(gè)圓心坐標(biāo)cx华坦、cy间驮,半徑r:
let cx=200,cy=200,r=150;
  1. 開始路徑:
gd.beginPath();
  1. 畫筆移到圓心:
gd.moveTo(cx,cy);
  1. 然后移動(dòng)到x驾凶、y畫出一條線
    那x、y怎么求呢滩褥?再來看這張圖
    原理示意圖

    已知圓心cx病蛉、cy、r和起始角度ang1要求圖中x铸题、y铡恕,利用三角函數(shù)知識(shí)可知,圖中的紅邊a=cos(ang1)r丢间,藍(lán)色邊b=sin(ang1)r探熔;而x、y的值就是圓心坐標(biāo)分別加上a和b烘挫,就是我們求的線的終點(diǎn)坐標(biāo)即弧的起點(diǎn)坐標(biāo)诀艰。
    假設(shè)我們令起始角度ang1=30°柬甥,終止角度ang2=80°,由于Math.cos和Math,sin的參數(shù)是弧度制其垄,因此我們還需要一個(gè)函數(shù)把角度制轉(zhuǎn)成弧度制:
function d2a(n){//角度轉(zhuǎn)弧度
      return n*Math.PI/180;
 }
function a2d(n){//弧度轉(zhuǎn)角度
      return n*180/Math.PI;
}
            
let startAng=30,endAng=80;
let x=cx+Math.cos(d2a(startAng)),y=cy+Math.sin(d2a(startAng));

把線畫過去

gd.lineTo(x,y);
  1. 然后畫豢疗选:
gd.arc(cx,cy,r,d2a(startAng),d2a(endAng),false);
  1. 最后閉合路徑、填充:
gd.closePath();
gd.fillStyle='orange';
gd.fill();

扇形就畫出來了:


扇形
  • 接下來第二個(gè)步驟绿满,把扇形畫滿360°

在解決這個(gè)問題之前臂外,先要解決一個(gè)問題:怎么把一份數(shù)據(jù)用餅狀圖表示出來?
再來看那個(gè)圖:


原理示意圖

假設(shè)一份數(shù)據(jù)包含200個(gè)男的喇颁,100個(gè)女的和50個(gè)其他漏健,那么200/(200+100+50)≈0.571就是性別為男的占比,用0.571*360=205.56就是200個(gè)男的在餅狀圖中占了多少度橘霎,這個(gè)角度就是我們要用的起始角度蔫浆,終止角度就是起始角度+弧長(zhǎng)就自己給我們畫出來了

  • 那么需要畫多少個(gè)扇形呢?
    有多少份數(shù)據(jù)就畫多少個(gè)扇形
    例:
let datas=[     
                {name:'菠菜',data:300,color:'#f5c'},
                {name:'玉米',data:200,color:'#dd0'},
                {name:'花生',data:20,color:'#0fc'},
                {name:'大豆',data:180,color:'#f85'}
]

這是我們的數(shù)據(jù)姐叁,菠菜300斤瓦盛,餅圖顏色etc.現(xiàn)在需要用餅狀圖把他表示出來
我們把前面畫扇形的函數(shù)封裝一下,然后用一個(gè)循環(huán)遍歷數(shù)組就可以畫出來了
封裝:

function pie(startAng, endAng, color) {
                let x = cx + r*Math.cos(d2a(startAng)), y = cy + r*Math.sin(d2a(startAng));

                gd.beginPath();
                //#1
                gd.moveTo(cx, cy);
                gd.lineTo(x, y);
                //#2
                gd.arc(cx, cy, r, d2a(startAng), d2a(endAng), false);
                //#3
                gd.closePath();

                gd.fillStyle = color;
                gd.fill();         
            }
原理示意圖

先求出總共有多少斤:

let sum=0;
datas.forEach(data=>{
sum+=data.data;
})

在畫餅圖的時(shí)候我們還需要一個(gè)變量now外潜,用來記錄當(dāng)前的角度原环,然后用now+我們算出來的在餅狀圖占多少度就是我們要畫的一個(gè)扇形

let now=0;

開始畫:

datas.forEach(data=>{
                let ang=360*data.data/sum;//求出需要畫多少度
                pie(now,now+ang,data.color);//畫扇形
                
                //添加名字
                let mid=(now+now+ang)/2;//取每一塊扇圖的中間位置為字體的坐標(biāo)
                let x = cx + r*Math.cos(d2a(mid)), y = cy + r*Math.sin(d2a(mid));//算出字體的x、y坐標(biāo)
                gd.font='bold 20px 宋體';//添加字體
                if(mid<180){//如果小于180°就讓坐標(biāo)大一點(diǎn)橡卤,文字往下走
                    gd.fillText(data.name,x+30,y+30);
                }else{//如果大于180°就讓坐標(biāo)小一點(diǎn)扮念,文字往上走
                    gd.fillText(data.name,x-30,y-30);
                }
                
                now+=ang;//更新now

            })

完整代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        body {
            background: gray;
            text-align: center;
        }
    </style>
    <script>
        window.onload = function () {
            let c1 = document.getElementsByTagName('canvas')[0];
            let gd = c1.getContext('2d');
            let cx = 400, cy = 300, r = 150;

            function d2a(n) {//角度轉(zhuǎn)弧度
                return n * Math.PI / 180;
            }
            function a2d(n) {//弧度轉(zhuǎn)角度
                return n * 180 / Math.PI;
            }

            function pie(startAng, endAng, color) {
                let x = cx + r*Math.cos(d2a(startAng)), y = cy + r*Math.sin(d2a(startAng));

                gd.beginPath();
                //#1
                gd.moveTo(cx, cy);
                gd.lineTo(x, y);
                //#2
                gd.arc(cx, cy, r, d2a(startAng), d2a(endAng), false);
                //#3
                gd.closePath();

                gd.fillStyle = color;
                gd.fill();         
            }

            let datas=[//數(shù)據(jù)
                {name:'菠菜',data:300,color:'#f5c'},
                {name:'玉米',data:200,color:'#dd0'},
                {name:'花生',data:20,color:'#0fc'},
                {name:'大豆',data:180,color:'#f85'}
            ]
            let sum=0,now=0;
            datas.forEach(data=>{
                sum+=data.data;//求出總和
            })

            datas.forEach(data=>{
                let ang=360*data.data/sum;//求出需要畫多少度
                pie(now,now+ang,data.color);//畫扇形
                
                //添加名字
                let mid=(now+now+ang)/2;//取每一塊扇圖的中間位置為字體的坐標(biāo)
                let x = cx + r*Math.cos(d2a(mid)), y = cy + r*Math.sin(d2a(mid));//算出字體的x损搬、y坐標(biāo)
                gd.font='bold 20px 宋體';//添加字體
                if(mid<180){//如果小于180°就讓坐標(biāo)大一點(diǎn)碧库,文字往下走
                    gd.fillText(data.name,x+30,y+30);
                }else{//如果大于180°就讓坐標(biāo)小一點(diǎn),文字往上走
                    gd.fillText(data.name,x-30,y-30);
                }  
                now+=ang;//更新now
            })
        }
    </script>
</head>
<body>
    <canvas width="800" height="600" style="background:white;"></canvas>
</body>
</html>
原理示意圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巧勤,一起剝皮案震驚了整個(gè)濱河市嵌灰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颅悉,老刑警劉巖沽瞭,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異剩瓶,居然都是意外死亡驹溃,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門延曙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來豌鹤,“玉大人,你說我怎么就攤上這事枝缔〔几恚” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)灵临。 經(jīng)常有香客問我截型,道長(zhǎng),這世上最難降的妖魔是什么儒溉? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任宦焦,我火速辦了婚禮,結(jié)果婚禮上顿涣,老公的妹妹穿的比我還像新娘赶诊。我一直安慰自己,他們只是感情好园骆,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布舔痪。 她就那樣靜靜地躺著,像睡著了一般锌唾。 火紅的嫁衣襯著肌膚如雪锄码。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天晌涕,我揣著相機(jī)與錄音滋捶,去河邊找鬼。 笑死余黎,一個(gè)胖子當(dāng)著我的面吹牛重窟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惧财,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼巡扇,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了垮衷?” 一聲冷哼從身側(cè)響起厅翔,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搀突,沒想到半個(gè)月后刀闷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仰迁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年甸昏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徐许。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡施蜜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绊寻,到底是詐尸還是另有隱情花墩,我是刑警寧澤悬秉,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站冰蘑,受9級(jí)特大地震影響和泌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜祠肥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一武氓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧仇箱,春花似錦县恕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至权逗,卻和暖如春美尸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背斟薇。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工师坎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人堪滨。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓胯陋,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親袱箱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子遏乔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

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

  • 參考自《Cocoa-Charts》 本篇介紹如何使用CoreGraphics繪制一個(gè)坐標(biāo)系 為了學(xué)習(xí)如何繪制各種圖...
    ChinaChong閱讀 2,324評(píng)論 0 53
  • 1、餅圖可以應(yīng)用在多方面犯眠,比如 財(cái)務(wù)類資金用途占比統(tǒng)計(jì)按灶、生活類個(gè)人喜好占比症革、等等筐咧,待產(chǎn)品提出這樣得效果,我們可以隨...
    冒泡人生閱讀 522評(píng)論 0 3
  • 一直想研究南丁格爾玫瑰圖噪矛,但是好長(zhǎng)一段時(shí)間都不得法門量蕊,寫完用Tableau畫環(huán)形圖系列后,雖然能畫出來但是不知道原...
    掃地sir閱讀 13,942評(píng)論 8 10
  • 關(guān)于這個(gè)話題雖然說有點(diǎn)敏感吧艇挨,但是我還是要提出來的残炮,并不是所有的莆田微商都是這樣的,很多黑商都是利用“莆田是造假出...
    Nxeexx閱讀 1,566評(píng)論 0 1
  • 李石卵自傳分為了兩個(gè)部分“詩(shī)和遠(yuǎn)方”和“生活的茍且” 缩滨。詩(shī)和遠(yuǎn)方向大家展現(xiàn)生活的美好势就,希望能讓你在不易的...
    李石卵閱讀 262評(píng)論 0 0