今天复习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;
}
效果