canvas(六)繪制帶說明的餅圖


1.函數說明

封裝一個根據數據來繪制帶說明的餅圖的函數(插件),具體的功能包括:
隨機顏色獲取
各區間角度值的計算
扇形繪制(包括延長線及說明)
左上角顏色說明

畫布建議大小為700 * 400
傳入的數據格式為:

var data = [
    {num:"10",title:"16-22的年齡人數"},
    {num:"15",title:"23-30的年齡人數"},
    {num:"25",title:"31-35的年齡人數"},
    {num:"10",title:"36及以上的年齡人數"}
]

2.調用函數繪制餅圖

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Test</title>
    <script src="index.js"></script>
    <style>
        .box{
            width: 700px;
            height: 400px;
            margin: 20px auto;
        }
        .box > canvas{
            border:1px solid red;
        }
    </style>
</head>
<body>
    <div class="box">
        <canvas width="700" height="400"></canvas>
    </div>
</body>
<script>
    var canvas = document.querySelector("canvas")
    var ctx = canvas.getContext("2d")

    var data = [
        {num:0,title:"16-22的年齡人數"},
        {num:0,title:"23-30的年齡人數"},
        {num:0,title:"31-35的年齡人數"},
        {num:0,title:"36及以上的年齡人數"}
    ]

    //模擬數據(產生50個數據)
    var num = 50
    for(var i=0;i<num;i++){
        //隨機產生16-40的整數
        var age = Math.floor(16 + Math.random()*25)
        if(age < 23){
            data[0].num++
        }else if(age < 31){
            data[1].num++
        }else if(age < 36){
            data[2].num++
        }else{
            data[3].num++
        }
    }

    //創建餅圖對象
    var pieChart = new PieChart(ctx)
    //傳入數據開始繪制餅圖
    pieChart.init(data)
</script>

3.封裝函數的代碼

var PieChart = function(ctx) {
    this.ctx = ctx || document.querySelector('canvas').getContext("2d");
    this.w = this.ctx.canvas.width;
    this.h = this.ctx.canvas.height;
    //餅圖的圓心
    this.x0 = this.w / 2 + 50;
    this.y0 = this.h / 2;
    this.r = 150; //半徑
    //延長線的長度
    this.outLineWidth = this.r + 20;
    //說明矩形的大小
    this.rectW = 30;
    this.rectH = 16;
    this.space = 20;
}
PieChart.prototype.init = function(data) {
    this.drawPie(data);
}
PieChart.prototype.drawPie = function(data) {
    var angleList = this.transitionRadian(data);
    var startRadian = 0; //起始角度
    var rectY = this.space; //說明矩形的起始Y坐標
    for (var i = 0; i < angleList.length; i++) {
        //繪制扇形
        this.ctx.beginPath(); //開啟路徑
        //獲取隨機顏色
        var color = this.getRandomColor();
        this.ctx.fillStyle = color; //設置填充顏色
        //結束弧度 = 上一個區間的弧度 + 此區間所占的弧度
        var endRadian = startRadian + angleList[i].angle;
        this.ctx.arc(this.x0, this.y0, this.r, startRadian, endRadian);
        this.ctx.lineTo(this.x0, this.y0);
        this.ctx.fill();

        //繪制餅圖的延長線標題
        this.drawTitle(startRadian, endRadian, angleList[i].title, color);

        //繪制左上角顏色說明
        this.drawDesc(rectY, color, angleList[i].title);

        //更新prevDadian
        startRadian = endRadian;
        //更新矩形的起始Y坐標
        rectY += (this.rectH + 10);
    }
}
PieChart.prototype.drawTitle = function(startRadian, endRadian, title, color) {
    //計算中心角度
    var middleRadian = (startRadian + endRadian) / 2;
    //以outLineWidth為直角邊
    //根據正弦 余弦求出兩個邊的長度,再結合圓心的坐標,求出延長線兩點的坐標
    var outX = this.x0 + this.outLineWidth * Math.cos(middleRadian);
    var outY = this.y0 + this.outLineWidth * Math.sin(middleRadian);
    //設置字體(設置字體要在計算字體寬度之前)
    this.ctx.font = '12px 微軟雅黑';
    //設置文字基線
    this.ctx.textBaseline = 'bottom';
    //設置描邊顏色
    this.ctx.strokeStyle = color;
    //計算下划線的終點坐標及文字對齊方式
    if (outX >= this.x0) {
        //在右邊
        var underlineX = outX + this.ctx.measureText(title).width;
        this.ctx.textAlign = 'left';
    } else {
        //在左邊
        var underlineX = outX - this.ctx.measureText(title).width;
        this.ctx.textAlign = 'right';
    }
    //繪制延長線
    this.ctx.beginPath();
    this.ctx.moveTo(this.x0, this.y0);
    this.ctx.lineTo(outX, outY);
    this.ctx.lineTo(underlineX, outY);
    this.ctx.stroke();

    //繪制文本
    this.ctx.beginPath();
    this.ctx.fillText(title, outX, outY);
}

//繪制左上角的說明
PieChart.prototype.drawDesc = function(rectY, color, title) {
    this.ctx.beginPath();
    this.ctx.textAlign = 'left';
    //中線對齊
    this.ctx.textBaseline = 'middle';
    //繪制矩形
    this.ctx.fillRect(this.space, rectY, this.rectW, this.rectH);
    //繪制文字,文字的基點y坐標為矩形的垂直方向的中心
    this.ctx.fillText(title, this.space + this.rectW + 10, rectY + this.rectH / 2);
}

//為每個區間添加角度屬性
PieChart.prototype.transitionRadian = function(data) {
    //獲取統計的總人數
    var total = 0;
    for (var i = 0; i < data.length; i++) {
        total += data[i].num;
    }
    for (var i = 0; i < data.length; i++) {
        var angle = 2 * Math.PI * Number(data[i].num) / total;
        data[i].angle = angle;
    }
    return data;
}

//獲取隨機顏色
PieChart.prototype.getRandomColor = function() {
    var r = Math.round(Math.random() * 255);
    var g = Math.round(Math.random() * 255);
    var b = Math.round(Math.random() * 255);
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

4.效果圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM