HTML5的canvas的實用入門小實例,一步步一起來。學(xué)習(xí)的最好方法就是實踐,參考HTML 5 Canvas 參考手冊,再加上自己的嘗試和實踐,馬上就可以得到canvas時鐘啦。在線演示
帶陰影表盤
- 獲取當(dāng)前canvas的寬高
var width=ctx.canvas.width;
- 聲明半徑r時預(yù)留一些陰影和線寬的寬度
var r=width/2-8;
- 陰影:
shadowBlur, shadowColor, shadowOffsetX, ctx.shadowOffsetY
- 漸變:
createRadialGradient, addColorStop
- 圓:
arc
- 圓周率,PI大寫:
Math.PI
- 重新映射中心
translate
刻度
- 把陰影去掉
- 重新從(0,0)開始,不然會從圓上3的位置開始
ctx.beginPath();
- 刻度是一條條的線,用
lineTo, stroke
- 刻度均勻分布表盤,需要計算角度,需要用到正弦余弦
- 正弦sin=對邊/斜邊
- 余弦cos=鄰邊/斜邊
-
Math.sin()
和Math.cos()
中的角度是弧度,弧度=弧長/半徑
- 整點的位置是5的倍數(shù),用
i%5==0
判斷
指針
- 指針是線,用
lineTo, stroke
- 指針是旋轉(zhuǎn)的,用
rotate
- 指針帽是圓的,用
ctx.lineCap="round";
- 需要開頭
ctx.save();
,結(jié)尾ctx.restore();
,否則起始的位置就變了 - 起始角在刻度3的位置,
ctx.rotate(2*Math.PI/60*(min-15));
- 時針的位置也受分針影響,
ctx.rotate(2*Math.PI/12*(hour-3)+2*Math.PI/12/60*min);
- 先旋轉(zhuǎn)再畫線
- 秒針比較細(xì),用的是4個點描邊和填充
- 理論上3個指針函數(shù)應(yīng)該合并,但3個各有不同,我就不合并了。
- 指針固定的一端應(yīng)該留一點長度,再加一個圓固定
讓時鐘動起來
- 獲取當(dāng)前時間
new Date(); getHours(); getMinutes(); getSeconds()
- 設(shè)置定時器,每秒獲取新的時間
setInterval()
- 但是會不停重疊地畫上去, 每秒清除一次矩形:
ctx.clearRect(0,0,width,height);
修飾完善
- 因為
setInterval
是隔1秒執(zhí)行,所以要先執(zhí)行一次,不然會停頓1秒才出現(xiàn)時鐘。 - 注意哪些地方要save,哪些地方要restore,如何區(qū)分?
- 聲明一個變量
rem=width/300
,使畫布大小變化時,時鐘仍然能夠正常顯示,注意半徑r已經(jīng)和width關(guān)聯(lián),無需再重復(fù)乘以這個參數(shù)rem。
完整代碼
var canvas=document.getElementById("myCanvas");
var ctx=canvas.getContext("2d");
var width=ctx.canvas.width; //獲取當(dāng)前canvas的寬高
var height=ctx.canvas.height;
var rem=width/300; //比例,使時鐘放大時保持外觀一直
var r=width/2-8*rem; //預(yù)留了陰影和線寬的位置;因為r已經(jīng)是和width相關(guān)的,因此下面的r不需要再*rem
//畫表盤
function drawBg(){
ctx.save();
ctx.translate(width/2,width/2); //重新映射中心位置到canvas中間,默認(rèn)是在左上角
ctx.lineWidth=4*rem;
ctx.shadowBlur=3*rem;
ctx.shadowColor="#222"; //陰影的顏色深一點
ctx.shadowOffsetX=3*rem;
ctx.shadowOffsetY=3*rem;
ctx.strokeStyle="#666"; //邊框顏色
var grd=ctx.createRadialGradient(0,0,10*rem,0,0,r); // 表示漸變范圍是半徑10到r的位置
grd.addColorStop(0,"#fefefe");
grd.addColorStop(1,"#dedede");
ctx.fillStyle=grd; //這一句不能少,填充的顏色是上面定義的漸變色
ctx.arc(0,0,r,0,2*Math.PI); //這里雖然想不通為什么,但的確是減去線寬的一半。
ctx.stroke();
ctx.fill();
//ctx.restore();
}
//畫刻度
function drawScale(){
//ctx.save();
ctx.shadowBlur = 0;
ctx.shadowColor = "";
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
for(var i=0;i<60;i++){
ctx.beginPath();
if(i%5==0){
ctx.strokeStyle="#222";
ctx.lineWidth=4;
ctx.lineTo((r-8*rem)*Math.cos(2*Math.PI/60*i),(r-8*rem)*Math.sin(2*Math.PI/60*i));
}else{
ctx.strokeStyle="#666";
ctx.lineWidth=2;
ctx.lineTo((r-4*rem)*Math.cos(2*Math.PI/60*i),(r-4*rem)*Math.sin(2*Math.PI/60*i));
}
ctx.lineTo(r*Math.cos(2*Math.PI/60*i),r*Math.sin(2*Math.PI/60*i));
ctx.stroke();
}
//ctx.restore();
}
//畫時針
function drawHour(hour,min){
ctx.save(); //不加這個的話,分針直接從時針處開始算。
ctx.beginPath();
ctx.lineWidth=6*rem;
ctx.lineCap="round";
ctx.strokeStyle="#222";
ctx.rotate(2*Math.PI/12*(hour-3)+2*Math.PI/12/60*min); //起始角在3那里
ctx.moveTo(-15*rem,0);
ctx.lineTo(r/2,0);
ctx.stroke();
ctx.restore();
}
//畫分針
function drawMin(min){
ctx.save();
ctx.beginPath();
ctx.lineWidth=3*rem;
ctx.lineCap="round";
ctx.strokeStyle="#222";
ctx.rotate(2*Math.PI/60*(min-15)); //起始角在3那里
ctx.moveTo(-15*rem,0);
ctx.lineTo(r/2+30*rem,0);
ctx.stroke();
ctx.restore();
}
//畫秒針
function drawSec(sec){
ctx.save();
ctx.beginPath();
ctx.fillStyle="#c14543";
ctx.rotate(2*Math.PI/60*(sec-15)); //起始角在3那里
ctx.moveTo(-15*rem,2*rem);
ctx.lineTo(-15*rem,-2*rem);
ctx.lineTo(r-8*rem,-1*rem);
ctx.lineTo(r-8*rem,1*rem);
ctx.fill();
ctx.restore();
}
//畫固定點
function drawDot(){
ctx.beginPath();
ctx.fillStyle="#fff";
ctx.arc(0,0,6*rem,0,2*Math.PI);
ctx.fill();
}
//畫動態(tài)時鐘
function draw(){
ctx.clearRect(0,0,width,height); //每秒清除一次矩形
var date=new Date();
var h=date.getHours();
var m=date.getMinutes();
var s=date.getSeconds();
drawBg();
drawScale();
drawHour(h,m);
drawMin(m);
drawSec(s);
drawDot();
ctx.restore();
}
//定時器
var timer=setInterval(draw, 1000);
draw(); //先執(zhí)行一次,不然頁面會卡一下。