随手画个饼状图及时钟

今天复习canvas,随手画了个饼状图及时钟。

首先注意canvas中画圆用的是弧度而不是角度,但一般情况下角度对我们来说更直观,所以需要将角度转成弧度,很简单,一个圆角度为360,而弧度为2π,写个函数转换一下就行。

//角度转弧度,angle to radian
function a2r(angle){
    return angle*Math.PI/180;
}

然后还有个注意事项是canvas中画圆中角度0度是在正上方,而弧度0度在正右方(也就是说画圆弧默认会在正右方开始),所以要想从正上方开始画那就写初始弧度为 -90*Math.PI/180

计算圆弧上某点坐标,注意canvas用的要用弧度

上图是数学上的算法,在canvas中记两条公式就行了:

  • 圆弧上点x坐标 = 圆心x + Math.cos(弧度) * 半径
  • 圆弧上点y坐标 = 圆心y + Math.sin(弧度) * 半径

使用路径之前先beginPath

实现代码

//绘制饼状图
        function pieChart(arr){
            var total = 0;      //传入数组各项值总和
            arr.forEach(function(item){
                total += item;
            });
            var angleArr = [];      //传入的数组各项相对角度
            var uncludeLastTotal = 0;       //不包括最后一项的总角度和
            for(var i=0; i<arr.length; i++){        
                if(i == arr.length-1){      //如果是最后一项,就直接用360减去之前的总和
                    angleArr.push(360-uncludeLastTotal);
                }else{           //否则计算角度,四舍五入
                    angleArr.push(Math.round(360*arr[i]/total));
                    uncludeLastTotal += Math.round(360*arr[i]/total);
                }
            }
            var nowAngle = 0;       //当前角度,初始值为0
            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext('2d');
            var cx = 400, cy = 200, r = 100;    //圆心和半径
            angleArr.forEach(function(item){
                var startAng = nowAngle, endAng = nowAngle+item;     //起始及结束角度
                nowAngle += item;
                var x = cx + Math.sin(a2r(startAng)) * r;    //圆弧上坐标x
                var y = cy - Math.cos(a2r(startAng)) * r;    //圆弧上坐标y
                
                ctx.beginPath();
                ctx.moveTo(cx, cy);
                ctx.lineTo(x, y);
                ctx.arc(cx, cy, r, a2r(startAng-90), a2r(endAng-90))     //用的参数是弧度
                ctx.fillStyle = randomColor();
                ctx.closePath();
                ctx.fill();
            })
            // return angleArr;
        }

        pieChart([3, 6, 15, 13, 22, 8])
        // console.dir(canvas)
        
        //随机颜色值
        function randomColor(){
            var r = Math.floor(Math.random()*256);
            var g = Math.floor(Math.random()*256);
            var b = Math.floor(Math.random()*256);
            return `rgb(${r},${g},${b})`;
        }

        //角度转弧度
        function a2r(angle){
            return angle*Math.PI/180;
        }

效果

画时钟

其实画时钟很简单,主要是用到canvas中的旋转rotate()以及位移translate()两个方法。不过在使用canvas变换方法还是有要注意的地方,比如说:

1、先变换在画图。

2、rotate()的旋转中心在画布原点而不是所画图形的中心,要想绕自己中心旋转可以先将自己中心与画布原点重合,然后旋转,然后再平移。

3、变换方法书写与执行是倒序的,比如想要先旋转再平移,那就先写translate()再写rotate()。

4、使用变换方法是先save()(保存之前的画布状态),最后restore()(恢复之前的画布状态)。

实现代码

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
setInterval(function () {
    var rotateAngle = 0;
    canvas.width = canvas.clientWidth;
    canvas.height = canvas.clientHeight;
    var cvW = canvas.width, cvH = canvas.height;
    // 以画布长和宽中较小的为标尺,用该标尺制定时钟尺寸的自适应
    var ruler = cvW > cvH ? cvH : cvW;
    // 大刻度宽高
    var dkdWidth = ruler/30, dkdHeight = ruler/60;
    // 小刻度宽高
    var xkdWidth = ruler/50, xkdHeight = ruler/100;
    //清画布
    ctx.clearRect(0, 0, cvW, cvH);
    //画时钟刻度
    for (var i = 0; i < 60; i++) {
        rotateAngle += 6;
        // canvas变换之前先save保存canvas状态(颜色,宽高,变换等),不包括图形本身
        ctx.save();
        //canvas变换方法执行顺序是倒序的
        ctx.translate(cvW/2, cvH/2);     //再平移
        ctx.rotate(a2r(rotateAngle));        //先旋转
        if (i % 5 == 4) {
            ctx.fillRect(ruler/3, -dkdHeight/2, dkdWidth, dkdHeight);
        } else {
            ctx.fillRect((ruler/3 + (dkdWidth - xkdWidth)), -xkdHeight/2, xkdWidth, xkdHeight);
        }
        ctx.restore();
    }

    var time = new Date();
    var hour = time.getHours();
    var minute = time.getMinutes();
    var second = time.getSeconds();

    //时针
    ctx.save();
    ctx.translate(cvW/2, cvH/2);
    ctx.rotate(a2r((hour * 30 + minute / 2) - 90));
    ctx.fillStyle = '#666';
    ctx.fillRect(-dkdWidth, -3, ruler/3-dkdWidth*4, dkdHeight);
    ctx.restore();

    //分针
    ctx.save();
    ctx.translate(cvW/2, cvH/2);
    ctx.rotate(a2r(minute * 6 - 90));
    ctx.fillStyle = 'blue';
    ctx.fillRect(-dkdWidth, -2, ruler/3-dkdWidth*2, xkdHeight);
    ctx.restore();

    //秒针
    ctx.save();
    ctx.translate(cvW/2, cvH/2);
    ctx.rotate(a2r(second * 6 - 90));
    ctx.fillStyle = 'red';
    ctx.fillRect(-dkdWidth, -1, ruler/3-dkdWidth, xkdHeight < 2 ? 1 : 2);
    ctx.restore();
}, 1000)

//角度转弧度,angle to radian
function a2r(angle) {
    return angle * Math.PI / 180;
}

效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值