初識canvas
前段時間重新看了一下canvas,覺得很有意思,現(xiàn)在總結(jié)一下,只限于基礎(chǔ)的,中間有一些小的案例,說的有一些啰嗦,建議初學(xué)者參考,歡迎批評指正,共同進(jìn)步!
首先,我們來認(rèn)識一下,什么是canvas
一、Canvas定義:
通常用于繪制圖表、動畫,通過腳本(javascript)來完成,?<canvas> 元素本身并沒有繪制能力(它僅僅是圖形的容器)
不支持canvas的瀏覽器頁面為空不顯示 (ie9以下)
可在canvas標(biāo)簽內(nèi)寫p標(biāo)簽
<p>您的瀏覽器不支持canvas</p>
支持cnavas的瀏覽器將不識別此標(biāo)簽
二、Canvas使用方法:
創(chuàng)建一個畫布,在頁面中引入canvas標(biāo)簽, 默認(rèn)寬300px ?高 150px
<canvas? id="can" ></canvas>//默認(rèn)寬300px ?高 150px
設(shè)置畫布大小的方法:
1、屬性width ?height 設(shè)置寬高,畫布上每個點都是一個像素
<canvas? id="can" width="800" height="800"></canvas>
那么問題來了
是否可以在style里面修改畫布大?。?/p>
不可以 ,畫布里面的內(nèi)容也會被縮放
獲取canvas畫布:
var oC = document.getElementById('can');
繪制繪圖環(huán)境
var cte = oC.getContext('2d');
設(shè)置繪制環(huán)境?:getContext(默認(rèn)的是2d的場景)?------方法可返回一個對象,該對象提供了用于在畫布上繪圖的方法和屬性。
繪制圖形
一 、繪制方塊
fillRect(X,Y,W,H): 默認(rèn)填充顏色是黑色
參數(shù):
X/Y:距離畫布的坐標(biāo)
W/H:矩形的寬高
var can = document.getElementById('can');//獲取畫布
var canT = can.getContext('2d');//繪制繪圖環(huán)境
canT.fillRect(10,10,100,100);//畫矩形
效果圖:

設(shè)置繪圖樣式? ? (繪制填充矩形要先設(shè)置樣式,再繪制)
fillStyle: 填充繪畫的顏色、漸變或模式
填充的矩形要設(shè)置lineJoin樣式(設(shè)置一個同坐標(biāo)的描邊矩形,設(shè)置描邊矩形的lineJoin樣式
var can = document.getElementById('can');
var canT = can.getContext('2d');
canT.fillStyle='#f40';//繪制填充矩形要先設(shè)置樣式,再繪制
canT.fillRect(10,10,100,100);
效果圖:

二,設(shè)置描邊矩形
strokeRect(X,Y,W,H): 帶邊框的方塊,默認(rèn)一像素黑色邊框
參數(shù):
X/Y:距離畫布的坐標(biāo)
W/H:矩形的寬高
var can = document.getElementById('can');
var canT = can.getContext('2d');
canT.fillStyle='#f40';
canT.fillRect(10,10,100,100);
canT.strokeRect(150,10,100,100);
效果圖:

設(shè)置繪圖樣式? ( 繪制填充矩形要先設(shè)置樣式,再繪制)
a 繪圖環(huán)境.strokeStyle='顏色'
b 繪圖環(huán)境.lineWidth ='數(shù)值'
a繪圖環(huán)境.strokeStyle='顏色'
var can = document.getElementById('can');
var canT = can.getContext('2d');//畫圖的方法和屬性放在了這里
canT.fillStyle='#f40';
canT.fillRect(10,10,100,100);
canT.strokeStyle='#f40';繪制填充矩形要先設(shè)置樣式,再繪制
canT.strokeRect(150,10,100,100);
效果圖:

b 繪圖環(huán)境.lineWidth ='數(shù)值'
var can = document.getElementById('can');
var canT = can.getContext('2d');
canT.fillStyle='#f40';
canT.fillRect(10,10,100,100);
canT.lineWidth = '30';//線條寬度,設(shè)置在繪圖前
canT.strokeStyle='#f40';//線條顏色,設(shè)置在繪圖前
canT.strokeRect(150,10,100,100);
三、邊界繪制
lineJoin: 邊界連接點樣式? 設(shè)置在繪圖前
----miter? [?ma?t?r]? [?ma?t?(r)] 默認(rèn),round(圓角),bevel [?bevl]? [?bevl](斜角)
? canT.lineWidth = '30';//線條寬度,設(shè)置在繪圖前
? canT.strokeStyle='#f40';
? canT.lineJoin='round';//圓角,設(shè)置在繪圖前
? canT.strokeRect(150,10,100,100);
效果圖:

canT.lineWidth = '30';//線條寬度,設(shè)置在繪圖前
canT.strokeStyle='#f40';
canT.lineJoin='bevel';//斜角角設(shè)置在繪圖前
canT.strokeRect(150,10,100,100);
效果圖:

四、繪制路徑
beginPath(): 開啟一條新路徑
closePath(): 閉合當(dāng)前路徑
moveTo(x,y): 定義線條開始坐標(biāo)
lineTo(x,y): 定義線條結(jié)束坐標(biāo)
stroke(): 畫線,默認(rèn)黑色
? canT.beginPath();//開啟一條新路徑
? canT.lineWidth = '30';//線條寬度,設(shè)置在繪圖前
? canT.moveTo(300,100);//定義線條開始坐標(biāo)
? canT.lineTo(400,200);//定義線條結(jié)束坐標(biāo)
? canT.stroke();// 畫線,默認(rèn)黑色
效果圖:

lineCap: 端點樣式
----butt(默認(rèn)), round(圓角),square
fill(): 填充,默認(rèn)黑色
rect(): 矩形區(qū)域(x,y,w,h)
clearRect(x,y,width,height) 方法清空給定矩形內(nèi)的指定像素。
lineCap: 端點樣式
----butt(默認(rèn)), round(圓角),square
? canT.beginPath();//開啟一條新路徑
? canT.lineWidth = '30';//線條寬度,設(shè)置在繪圖前
? canT.moveTo(300,100);//定義線條開始坐標(biāo)
? canT.lineTo(400,200);//定義線條結(jié)束坐標(biāo)
? canT.lineCap = 'round';//端點圓角
? canT.stroke();// 畫線,默認(rèn)黑色

canT.beginPath();//開啟一條新路徑
canT.lineWidth = '30';//線條寬度,設(shè)置在繪圖前
canT.moveTo(300,100);//定義線條開始坐標(biāo)
canT.lineTo(400,200);//定義線條結(jié)束坐標(biāo)
canT.lineCap = 'square';//增加原長度的1/2分到兩端
canT.stroke();// 畫線,默認(rèn)黑色
效果圖:

canT.beginPath();//開啟一條新路徑
canT.lineWidth = '30';//線條寬度,設(shè)置在繪圖前? ? ?
canT.moveTo(300,100);//定義線條開始坐標(biāo)
canT.lineTo(400,200);//定義線條結(jié)束坐標(biāo)
canT.lineCap = 'square';//增加元長度的1/2分到兩端
canT.strokeStyle = 'red';//設(shè)置顏色
canT.fill();//填充顏色
canT.stroke();// 畫線,默認(rèn)黑色
效果圖:

fill() 填充顏色
在用moveTo() lineTo()方法畫矩形時填充顏色使用,必須先設(shè)置顏色,fillStyle='顏色',再用fill()填充
? ? canT.beginPath();//開啟一條新路徑
? ? canT.lineWidth = '30';//線條寬度,設(shè)置在繪圖前? ? ?
? ? canT.moveTo(100,100);//定義線條開始坐標(biāo)
? ? canT.lineTo(200,100);//定義線條結(jié)束坐標(biāo)
? ? canT.lineTo(200,200);
? ? canT.lineTo(100,200);
? ? canT.closePath();
? ? canT.lineCap = 'square';
? ? canT.fillStyle = 'red';//設(shè)置要填充的顏色
? canT.fill();//填充?
? canT.stroke();// 畫線,默認(rèn)黑色
效果圖:

rect(): 矩形區(qū)域(x,y,w,h)
clearRect(x,y,width,height) 方法清空給定矩形內(nèi)的指
定像素。
canT.clearRect(0,0,150,160);
x: 要清除的矩形左上角的 x 坐標(biāo)
y:要清除的矩形左上角的 y 坐標(biāo)
width: 要清除的矩形的寬度
height: 要清除的矩形的高度

? ? ? // 畫矩形方法三:
? ? ? ? // cxt.beginPath();
? ? ? ? // cxt.rect(50,50,100,100);
? ? ? ? // cxt.fillStyle = 'red';
? ? ? ? // cxt.fill();
五.畫圓
arc(x,y,r,起始弧度,終止弧度,方向)
x/y: 圓心的坐標(biāo) 定義圓的位置
r:圓的半徑 定義圓的大小
弧度:Math.PI/180(一角度的弧度)
角度與弧度的轉(zhuǎn)換關(guān)系: 角度*Math.PI/180
方向:順時針(false 默認(rèn)值),逆時針(true)
canvas中畫圓起始位置為三點鐘方向 六點鐘方向為90度,九點鐘方向是+-180度,12點鐘方向為-90度
示意圖:

案例一:
圓
cxt.arc(100,100,100 ,0,360*Math.PI/180,true);
cxt.stroke();
效果圖:

案例二:
90度扇形
? ? ? ? cxt.moveTo(100,100);
? ? ? ? cxt.arc(100,100,100 ,0,90*Math.PI/180,false);
? ? ? ? cxt.closePath();
? ? ? ? cxt.stroke();
效果圖

? ? ? ? cxt.moveTo(100,100);
? ? ? ? cxt.arc(100,100,100 ,0,90*Math.PI/180,true);
? ? ? ? cxt.closePath();
? ? ? ? cxt.stroke();

案例三
移動的方塊
? ? num = 0;
? style = 100;
? setInterval(function(){
? cxt.clearRect(0,0,oc.width,oc.height);
? num ++; //改變位置
? style ++; //改變大小
? cxt.fillRect(num,num,style,style);
},100)


案例四:
畫扇形
120度? 設(shè)置描邊樣式,填充顏色樣式
cxt.moveTo(15,15,);
cxt.arc(150,150,150,0,120*Math.PI/180,false);
cxt.strokeStyle = '#f40';//設(shè)置描邊樣式
cxt.fillStyle = 'red';//填充顏色樣式
cxt.fill();//填充 填充顏色樣式
cxt.closePath();
cxt.stroke();

案例五:
canvasOnload
? ? var oc = document.getElementById('c1');
? ? var cxt = oc.getContext('2d');
? ? var num = 0;//定義變量
? ? var timer = setInterval(function(){
? ? cxt.clearRect(0,0,oc.width,oc.height);
? ? num+=10;//定義變化的角度 步頻
? ? cxt.beginPath();//開始新路徑
? ? cxt.lineWidth = '6';//線寬
? ? cxt.strokeStyle ='#ccc';
? ? ? ? ? ? ? ? ? ? ? ? //起始弧度? ? ? ? ? ? //終止弧度
? ? cxt.arc(100,100,50,-90*Math.PI/180,(num+-90)*Math.PI/180,false);
? ? cxt.stroke();
? ? if(num>360){
? ? ? ? //當(dāng)圓環(huán)閉合時,清除定時器
? ? ? ? clearInterval(timer);
? ? }
? ? },50)
效果圖:


變換(平移 旋轉(zhuǎn) 縮放)
translate(x,y):
平移 可以重新定義畫布的(0,0)位置
默認(rèn)畫布(0,0)位置在畫布左上角
參數(shù):
x/y:x/y軸的偏移量
? ctx.fillRect(0,0,200,150);//未平移前
? ctx.translate(200,150);
? ctx.fillRect(0,0,200,150);

rotate(rad);
旋轉(zhuǎn)當(dāng)前圖形?
旋轉(zhuǎn)的參考角度為畫布的(0,0)位置
角度:angle
弧度:radian
參數(shù):
deg:旋轉(zhuǎn)角度 弧度計
弧度= 角度*Math.PI/180
ctx.rotate(45*Math.PI/180);//旋轉(zhuǎn) 寫在繪制圖形前面
ctx.fillRect(0,0,100,50);

? ctx.fillRect(0,0,100,50);
? ctx.translate(200,150);//圖形的起始位置平移至(200,150)位置
? ctx.fillRect(0,0,100,50);

ctx.rotate(45*Math.PI/180);
ctx.fillRect(0,0,100,50);
ctx.translate(200,150);//圖形的起始位置平移至(200,150)位置
ctx.fillRect(0,0,100,50);

以物體中心旋轉(zhuǎn)
ctx.translate(50,25);//設(shè)位移量為寬高一半
ctx.rotate(45*Math.PI/180);
ctx.fillRect(-50,-25,100,50);//設(shè)填充點為寬高的-(1/2)

案例:
方塊旋轉(zhuǎn)
save(): 保存路徑
restore(): 恢復(fù)路徑
save()和restore(): 兩個配對使用,save方法用于臨時保存畫布的坐標(biāo)系統(tǒng)的狀態(tài);restore方法用來恢復(fù)save之后保存的狀態(tài)。可以簡單的理解為,save之后的一系列的操作,比如translate和rotate等,在restore后,都會被釋放恢復(fù)到原來的狀態(tài)。
var num =0;
ctx.translate(200,200);//定義畫布的起始(0,0)位置
var timer = setInterval(function(){
ctx.clearRect(-160,-160,oc.width,oc.height);//注意清除區(qū)域值
ctx.save();//保存路徑
num+=10;
ctx.rotate(num*Math.PI/180);
ctx.fillRect(-100,-100,200,200);
ctx.restore();//恢復(fù)路徑
},1000)


scale(x,y)放大
參數(shù):
x:代表水平放大的倍數(shù)
y:代表垂直放大的倍數(shù)
scale(1,1),默認(rèn)
scale(2,2)放大一倍
scale(0.5,0.5)縮小一半
案例
畫鐘表
第一步:畫出60個小格子代表分針/秒針刻度,每個刻度之間是6度
function toDrow(){
// 第一步:畫出60個小格子代表分針/秒針刻度,每個刻度之間是6度
// cxt.moveTo(200,200);
// cxt.arc(200,200,150,0,6*Math.PI/180,false);
// 整個鐘表一共360度,需要進(jìn)行60次,用循環(huán)
? ? for(var i = 0; i < 60; i ++){
? ? cxt.moveTo(200,200);
? ? cxt.arc(200,200,150,i*6*Math.PI/180,(i+1)*6*Math.PI/180,false);
? ? cxt.stroke();
? ? //此時 將出現(xiàn)一個圓盤上出現(xiàn)60個閉合的扇形角度為6度
? ? ? ? }
? ? ? ? }
toDrow();
效果圖

function toDrow(){
// 第一步:畫出60個小格子代表分針/秒針刻度,每個刻度之間是6度
? // cxt.moveTo(200,200);
? // cxt.arc(200,200,150,0,6*Math.PI/180,false);
? // 整個鐘表一共360度,需要進(jìn)行60次,用循環(huán)
? ? cxt.beginPath();
? ? for(var i = 0; i < 60; i ++){
? ? ? cxt.moveTo(200,200);
? ? cxt.arc(200,200,150,i*6*Math.PI/180,(i+1)*6*Math.PI/180,false);
? ? cxt.stroke();
? ? cxt.closePath();
//此時 將出現(xiàn)一個圓盤上出現(xiàn)60個閉合的扇形角度為6度
? ? }
//第二步:畫遮罩層
? // 用一個圓覆蓋到之前畫出分鐘/秒鐘刻度盤上,圓心相同,
//半徑小于原刻盤,制造出時中刻度的假象
? ? ? cxt.beginPath();
? ? ? cxt.fillStyle = '#fff';
? ? ? cxt.arc(200,200,140,0,360*Math.PI/180,false);
? ? ? cxt.fill();
? ? ? cxt.closePath();
}
效果圖:

function toDrow(){
// 第一步:畫出60個小格子代表分針/秒針刻度,每個刻度之間是6度
? // cxt.moveTo(200,200);
? // cxt.arc(200,200,150,0,6*Math.PI/180,false);
? // 整個鐘表一共360度,需要進(jìn)行60次,用循環(huán)
? ? cxt.beginPath();
? ? for(var i = 0; i < 60; i ++){
? ? ? cxt.moveTo(200,200);
? ? ? cxt.arc(200,200,150,i*6*Math.PI/180,(i+1)*6*Math.PI/180,false);
? ? ? cxt.stroke();
//此時 將出現(xiàn)一個圓盤上出現(xiàn)60個閉合的扇形角度為6度
? ? }
? ? cxt.beginPath();
//第二步:畫遮罩層
? // 用一個圓覆蓋到之前畫出分鐘/秒鐘刻度盤上,圓心相同,半徑小于原刻盤,
//制造出時中刻度的假象
? ? ? cxt.beginPath();
? ? ? cxt.fillStyle = '#fff';
? ? ? cxt.arc(200,200,140,0,360*Math.PI/180,false);
? ? ? cxt.fill();
? ? ? cxt.closePath();
//? ? 第三步:畫時針刻度
? ? // 同分鐘,整個表盤的分鐘刻度也是360度,分12個,每個刻度為30
? ? // 一共有12個30度
? ? cxt.beginPath();
? ? for(var i = 0; i? < 12; i ++){
? ? ? cxt.moveTo(200,200);
? ? ? cxt.lineWidth = 3;
? ? ? cxt.arc(200,200,150,i*30*Math.PI/180,(i+1)*30*Math.PI/180,false);
? ? ? cxt.stroke();
//此時 將出現(xiàn)一個圓盤上出現(xiàn)12個閉合的扇形角度為30度? 線寬為3
? ? ? ? }
? ? ? ? cxt.closePath();
? ? ? ? }
toDrow();

function toDrow(){
// 第一步:畫出60個小格子代表分針/秒針刻度,每個刻度之間是6度
? // cxt.moveTo(200,200);
? // cxt.arc(200,200,150,0,6*Math.PI/180,false);
? // 整個鐘表一共360度,需要進(jìn)行60次,用循環(huán)
? ? cxt.beginPath();
? ? for(var i = 0; i < 60; i ++){
? ? ? cxt.moveTo(200,200);
? ? ? cxt.arc(200,200,150,i*6*Math.PI/180,(i+1)*6*Math.PI/180,false);
? ? ? cxt.stroke();
//此時 將出現(xiàn)一個圓盤上出現(xiàn)60個閉合的扇形角度為6度
? ? }
? ? cxt.beginPath();
//第二步:畫遮罩層
? // 用一個圓覆蓋到之前畫出分鐘/秒鐘刻度盤上,圓心相同,半徑小于原刻盤,
//制造出時中刻度的假象
? ? ? cxt.beginPath();
? ? ? cxt.fillStyle = '#fff';
? ? ? cxt.arc(200,200,140,0,360*Math.PI/180,false);
? ? ? cxt.fill();
? ? ? cxt.closePath();
//? ? 第三步:畫時針刻度
? ? // 同分鐘,整個表盤的分鐘刻度也是360度,分12個,每個刻度為30
? ? // 一共有12個30度
? ? cxt.beginPath();
? ? for(var i = 0; i? < 12; i ++){
? ? ? cxt.moveTo(200,200);
? ? ? cxt.lineWidth = 3;
? ? ? cxt.arc(200,200,150,i*30*Math.PI/180,(i+1)*30*Math.PI/180,false);
? ? ? cxt.stroke();
//此時 將出現(xiàn)一個圓盤上出現(xiàn)12個閉合的扇形角度為30度? 線寬為3
? ? ? ? }
? ? ? ? cxt.closePath();
? ? ? ? }
// 第四步:畫遮罩層
? ? //? 用一個圓覆蓋到之前畫出分鐘/秒鐘刻度盤上,圓心相同,
? ? //? 半徑小于分鐘/秒鐘(原)遮罩層,制造出時中刻度的假象
? ? ? ? ? ? cxt.beginPath();
? ? ? ? ? ? cxt.fillStyle = '#fff';
? ? ? ? ? ? cxt.arc(200,200,130,0,360*Math.PI/180,false);
? ? ? ? ? ? cxt.fill();
? ? ? ? ? ? cxt.closePath();
? ? ? ? }
? ? ? ? toDrow();
效果圖:

? 第五步:畫時針分針秒針(行動軌跡)
? 圓心相同 半徑不同 ,起始弧度和終止弧度相等
起始弧度與終止弧度的值有時間軸來決定
function toDrow(){
// 第一步:畫出60個小格子代表分針/秒針刻度,每個刻度之間是6度
? // cxt.moveTo(200,200);
? // cxt.arc(200,200,150,0,6*Math.PI/180,false);
? // 整個鐘表一共360度,需要進(jìn)行60次,用循環(huán)
? ? cxt.beginPath();
? ? for(var i = 0; i < 60; i ++){
? ? ? cxt.moveTo(200,200);
? ? ? cxt.arc(200,200,150,i*6*Math.PI/180,(i+1)*6*Math.PI/180,false);
? ? ? cxt.stroke();
//此時 將出現(xiàn)一個圓盤上出現(xiàn)60個閉合的扇形角度為6度
? ? }
? ? cxt.beginPath();
//第二步:畫遮罩層
? // 用一個圓覆蓋到之前畫出分鐘/秒鐘刻度盤上,圓心相同,半徑小于原刻盤,
//制造出時中刻度的假象
? ? ? cxt.beginPath();
? ? ? cxt.fillStyle = '#fff';
? ? ? cxt.arc(200,200,140,0,360*Math.PI/180,false);
? ? ? cxt.fill();
? ? ? cxt.closePath();
//? ? 第三步:畫時針刻度
? ? // 同分鐘,整個表盤的分鐘刻度也是360度,分12個,每個刻度為30
? ? // 一共有12個30度
? ? cxt.beginPath();
? ? for(var i = 0; i? < 12; i ++){
? ? ? cxt.moveTo(200,200);
? ? ? cxt.lineWidth = 3;
? ? ? cxt.arc(200,200,150,i*30*Math.PI/180,(i+1)*30*Math.PI/180,false);
? ? ? cxt.stroke();
//此時 將出現(xiàn)一個圓盤上出現(xiàn)12個閉合的扇形角度為30度? 線寬為3
? ? ? ? }
? ? ? ? cxt.closePath();
? ? ? ? }
// 第四步:畫遮罩層
? ? //? 用一個圓覆蓋到之前畫出分鐘/秒鐘刻度盤上,圓心相同,
? ? //? 半徑小于分鐘/秒鐘(原)遮罩層,制造出時中刻度的假象
? ? ? ? ? ? cxt.beginPath();
? ? ? ? ? ? cxt.fillStyle = '#fff';
? ? ? ? ? ? cxt.arc(200,200,130,0,360*Math.PI/180,false);
? ? ? ? ? ? cxt.fill();
? ? ? ? ? ? cxt.closePath();
? ? ? ? ? ? // 第五步:畫時針分針秒針(行動軌跡)
? ? ? ? // 圓心相同 半徑不同 ,起始弧度和終止弧度相等
? ? ? ? // 起始弧度與終止弧度的值有時間軸來決定
? ? ? ? ? ? // cxt.moveTo(200,200);
? ? ? ? ? ? // cxt.arc(200,200,150*0.5,起始弧度,終止弧度,false);
? ? ? ? ? ? // cxt.stroke();
? ? ? ? ? ? // 時針:最短最粗,
? ? ? ? cxt.beginPath();
? ? ? ? cxt.moveTo(200,200);
? ? ? ? cxt.lineWidth =4;
? ? ? ? cxt.arc(200,200,150*0.5,1,1,false);
? ? ? ? cxt.stroke();
? ? ? ? cxt.closePath();
? ? ? ? //? ? 畫分針
? ? cxt.beginPath();
? ? cxt.moveTo(200,200);
? ? cxt.lineWidth =3;
? ? cxt.arc(200,200,150*0.7,3,3,false);
? ? cxt.stroke();
? ? cxt.closePath();
? ? ? ? }
? ? ? ? toDrow();
效果圖:

// 第六步:
設(shè)置在前邊
// 想要讓時分秒的顯示和真實時間一致
// a:分別時間的時分秒
// B:讓時分秒針的位置同一
// c:將函數(shù)放入定時器,每1000ms執(zhí)行一次
// 當(dāng)時間不為整點時,時針在兩個數(shù)之間,此時需要將時針的位置加上偏移量
var timer = new Date();
ar tH = timer.getHours();//獲取小時
var tM = timer.getMinutes();//獲取分鐘
var tS = timer.getSeconds();//獲取秒
// 時針轉(zhuǎn)弧度
// a: 每一個格代表30度,時鐘和canvas的起始弧度相差90度,
// b: 當(dāng)時間不為整點時需將偏移量加上
// eg:10:30分,時針在10-11正中間,一個格式2,判斷分鐘里有幾個2
var tHVal = (30*tH-90+tM/2)*Math.PI/180;
// 分針轉(zhuǎn)弧度
// 每一個格代表6度,時鐘和canvas的起始弧度相差90度,
var tMVal =(6*tM-90)*Math.PI/180;
// 秒針轉(zhuǎn)弧度
//? 每一個格代表6度,時鐘和canvas的起始弧度相差90度,
var tSVal =(6*tS-90)*Math.PI/180;
//? 第七步:
// 將時分秒的弧度值替換
function toDrow(){
// 第六步:
// 想要讓時分秒的顯示和真實時間一致
// a:分別時間的時分秒
// B:讓時分秒針的位置同一
// c:將函數(shù)放入定時器,每1000ms執(zhí)行一次
// 當(dāng)時間不為整點時,時針在兩個數(shù)之間,此時需要將時針的位置加上偏移量
? var timer = new Date();
? var tH = timer.getHours();//獲取小時
? var tM = timer.getMinutes();//獲取分鐘
? var tS = timer.getSeconds();//獲取秒
// 將時分秒轉(zhuǎn)換為弧度
// 時針轉(zhuǎn)弧度
// a: 每一個格代表30度,時鐘和canvas的起始弧度相差90度,
// b: 當(dāng)時間不為整點時需將偏移量加上
// eg:10:30分,時針在10-11正中間,一個格式2,判斷分鐘里有幾個2
? var tHVal = (30*tH-90+tM/2)*Math.PI/180;
// 分針轉(zhuǎn)弧度
? // 每一個格代表6度,時鐘和canvas的起始弧度相差90度,
? ? var tMVal =(6*tM-90)*Math.PI/180;
// 秒針轉(zhuǎn)弧度
//? 每一個格代表6度,時鐘和canvas的起始弧度相差90度,
? ? var tSVal =(6*tS-90)*Math.PI/180;
//? 第七步:
? // 將時分秒的弧度值替換
// 第一步:畫出60個小格子代表分針/秒針刻度,每個刻度之間是6度
? // cxt.moveTo(200,200);
? // cxt.arc(200,200,150,0,6*Math.PI/180,false);
? // 整個鐘表一共360度,需要進(jìn)行60次,用循環(huán)
? ? cxt.beginPath();
? ? for(var i = 0; i < 60; i ++){
? ? ? cxt.moveTo(200,200);
? ? ? cxt.arc(200,200,150,i*6*Math.PI/180,(i+1)*6*Math.PI/180,false);
? ? ? cxt.stroke();
//此時 將出現(xiàn)一個圓盤上出現(xiàn)60個閉合的扇形角度為6度
? ? }
? ? cxt.beginPath();
//第二步:畫遮罩層
? // 用一個圓覆蓋到之前畫出分鐘/秒鐘刻度盤上,圓心相同,半徑小于原刻盤,
//制造出時中刻度的假象
? ? ? cxt.beginPath();
? ? ? cxt.fillStyle = '#fff';
? ? ? cxt.arc(200,200,140,0,360*Math.PI/180,false);
? ? ? cxt.fill();
? ? ? cxt.closePath();
//? ? 第三步:畫時針刻度
? ? // 同分鐘,整個表盤的分鐘刻度也是360度,分12個,每個刻度為30
? ? // 一共有12個30度
? ? cxt.beginPath();
? ? for(var i = 0; i? < 12; i ++){
? ? ? cxt.moveTo(200,200);
? ? ? cxt.lineWidth = 3;
? ? ? cxt.arc(200,200,150,i*30*Math.PI/180,(i+1)*30*Math.PI/180,false);
? ? ? cxt.stroke();
//此時 將出現(xiàn)一個圓盤上出現(xiàn)12個閉合的扇形角度為30度? 線寬為3
? ? ? ? }
? ? ? ? cxt.closePath();
? ? ? ? }
// 第四步:畫遮罩層
? ? //? 用一個圓覆蓋到之前畫出分鐘/秒鐘刻度盤上,圓心相同,
? ? //? 半徑小于分鐘/秒鐘(原)遮罩層,制造出時中刻度的假象
? ? ? ? ? ? cxt.beginPath();
? ? ? ? ? ? cxt.fillStyle = '#fff';
? ? ? ? ? ? cxt.arc(200,200,130,0,360*Math.PI/180,false);
? ? ? ? ? ? cxt.fill();
? ? ? ? ? ? cxt.closePath();
? ? ? ? ? ? // 第五步:畫時針分針秒針(行動軌跡)
? ? ? ? // 圓心相同 半徑不同 ,起始弧度和終止弧度相等
? ? ? ? // 起始弧度與終止弧度的值有時間軸來決定
? ? ? ? ? ? // cxt.moveTo(200,200);
? ? ? ? ? ? // cxt.arc(200,200,150*0.5,起始弧度,終止弧度,false);
? ? ? ? ? ? // cxt.stroke();
? ? ? ? ? ? // 時針:最短最粗,
? ? ? ? cxt.beginPath();
? ? ? ? cxt.moveTo(200,200);
? ? ? ? cxt.lineWidth =4;
? ? ? ? cxt.arc(200,200,150*0.5,tHVal,tHVal,false);
? ? ? ? cxt.stroke();
? ? ? ? cxt.closePath();
? ? ? ? //? ? 畫分針
? ? cxt.beginPath();
? ? cxt.moveTo(200,200);
? ? cxt.lineWidth =3;
? ? cxt.arc(200,200,150*0.7,tMVal,tMVal,false);
? ? cxt.stroke();
? ? cxt.closePath();
? ? //? ? 畫秒針
? ? cxt.beginPath();
? ? cxt.moveTo(200,200);
? ? cxt.lineWidth =2;
? ? cxt.arc(200,200,150*0.7,tSVal,tSVal,false);
? ? cxt.stroke();
? ? cxt.closePath();
? ? ? ? }
? ? ? ? toDrow();
? ? ? ? //定時器
etInterval(toDrow,1000);
插入圖片
cxt.drawImage(obj,x,y)
參數(shù):
三個參數(shù)
1.obj:要插入的圖片對象
2.x/y:代表插入圖片在畫布上的位置(x,y)
語法:
cxt.drawImage(obj,x,y)
五個參數(shù)的是時候
cxt.drawImage(obj,x,y,w,h)
w/h:代表在畫布上定位圖片并設(shè)置照片的大小
不設(shè)置寬高,默認(rèn)為圖片自身寬高
九個參數(shù)代表
? ? ? cxt.drawImage(obj,sx,sy,sw,sh,x,y,w,h)
sx/sy: 要剪切圖片的位置
sw/sh:剪切的大小
x/y:在畫布的位置
w/h:圖片的大小
createPattern(obj,是否重復(fù)):設(shè)置背景
? repeat:默認(rèn)重復(fù)
? repeat-x:x軸重復(fù)
? repeat-y:y軸重復(fù)
? no-repeat:不重復(fù)
window.onload = function(){
? ? ? ? ? ? var oC = document.getElementById('c1');
? ? ? ? ? ? var cxt = oC.getContext('2d');
? ? ? ? ? ? //創(chuàng)建圖片對象
? ? ? ? ? ? var oImg = new Image();
? ? ? ? ? ? //圖片路徑
? ? ? ? ? ? oImg .src = 'img/life.jpg';
? ? ? ? ? ? //當(dāng)圖片加載完成以后執(zhí)行操作
? ? ? ? ? ? oImg.onload = function(){
? ? ? ? ? ? ? ? //圖片插入canvas畫布中
? ? ? ? ? ? ? ? cxt.drawImage(oImg,50,80)
? ? ? ? ? ? }
? ? ? ? }
效果

平鋪:
window.onload = function(){
? ? ? ? ? ? var oC = document.getElementById('c1');
? ? ? ? ? ? var cxt = oC.getContext('2d');
? ? ? ? ? ? //創(chuàng)建圖片對象
? ? ? ? ? ? var oImg = new Image();
? ? ? ? ? ? //圖片路徑
? ? ? ? ? ? oImg .src = 'img/life.jpg';
? ? ? ? ? ? //當(dāng)圖片加載完成以后執(zhí)行操作
? ? ? ? ? ? oImg.onload = function(){
? ? ? ? ? ? ? ? //圖片插入canvas畫布中
? ? ? ? ? ? ? ? cxt.drawImage(oImg,0,0);
? ? ? ? ? ? ? ? var bg = cxt.createPattern(oImg,'repeat');
? ? ? ? ? ? ? ? //createPattern(obj,是否重復(fù)):設(shè)置背景
? ? ? ? ? ? ? ? ? //repeat:默認(rèn)重復(fù)
? ? ? ? ? ? ? ? ? //repeat-x:x軸重復(fù)
? ? ? ? ? ? ? ? ? // repeat-y:y軸重復(fù)
? ? ? ? ? ? ? ? ? // no-repeat:不重復(fù)
? ? ? ? ? ? ? cxt.fillStyle = bg;
? ? ? ? ? ? ? cxt.fillRect(0,0,oC.width,oC.height);
? ? ? ? ? ? }
? ? ? ? }
效果:

剪裁:(剪裁圖片不能設(shè)置平鋪效果
window.onload = function(){
? ? ? ? ? ? var oC = document.getElementById('c1');
? ? ? ? ? ? var cxt = oC.getContext('2d');
? ? ? ? ? ? //創(chuàng)建圖片對象
? ? ? ? ? ? var oImg = new Image();
? ? ? ? ? ? //圖片路徑
? ? ? ? ? ? oImg .src = 'img/life.jpg';
? ? ? ? ? ? //當(dāng)圖片加載完成以后執(zhí)行操作
? ? ? ? ? ? oImg.onload = function(){
? ? ? ? ? ? ? ? //圖片插入canvas畫布中
? ? ? ? ? ? ? ? //cxt.drawImage(obj,sx,sy,sw,sh,x,y,w,h)
? ? ? ? ? ? ? ? //sx/sy: 要剪切圖片的位置
? ? ? ? ? ? ? ? //sw/sh:剪切的大小,這個區(qū)域的圖片舍棄
? ? ? ? ? ? ? ? //x/y:在畫布的位置
? ? ? ? ? ? ? ? // w/h:圖片的大小
? ? ? ? ? ? ? ? cxt.drawImage(oImg,30,50,100,200,200,100,200,200);
? ? ? ? ? ? }
? ? ? ? }
效果:

案例:
圖片旋轉(zhuǎn):
分析:
第一步:
向畫布插入圖片
var oImg = new Image();//調(diào)用方法
oImg.src = "img/life.jpg";//圖片路徑
//設(shè)置canvas畫布與圖片大小一致
? oImg.onload = function() {//圖片預(yù)加載,當(dāng)圖片加載完成再執(zhí)行canvas
? ? ? ? ? ? cxt.drawImage(oImg,0,0,500,300);
? ? ? ? }
第二步:
設(shè)置旋轉(zhuǎn)角度
window.onload = function(){
????????var aInput = document.getElementsByTagName
? ? ? ? ("input");
? ? ? ? var oC = document.getElementById("c1");
? ? ? ? var cxt = oC.getContext("2d");
????????var? i = 0;
? ? ? ? var iNow = 0;
? ? ? ? // 向畫布插入圖片
? ? ? ? var oImg = new Image();
? ? ? ? oImg.src = "img/life.jpg";
? ? ? ? oImg.onload = function() {
? ? ? ? ? ? cxt.drawImage(oImg,0,0,500,300);
? ? ? ? }
????????// switch? 語句開始
? ? ? ? aInput[0].onclick = function() {
? ? ? ? ? ? if(iNow==0) {
? ? ? ? ? ? ? ? iNow = 3;
? ? ? ? ? ? }
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? iNow--;
? ? ? ? ? ? }
? ? ? ? ? toRotate();
? ? ? ? }
? ? ? ? aInput[1].onclick = function() {
? ? ? ? ? ? // 執(zhí)行順時針旋轉(zhuǎn)圖片
? ? ? ? ? ? // 當(dāng)i= 1 第一次旋轉(zhuǎn) 旋轉(zhuǎn)90度
? ? ? ? ? ? if(iNow==3) {
? ? ? ? ? ? ? ? iNow = 0;
? ? ? ? ? ? }
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? iNow++;
? ? ? ? ? ? }
? ? ? ? ? toRotate();
? ? ? ? }
? ? ? ? function toRotate() {
? ? ? ? ? ? switch(iNow) {
? ? ? ? ? ? ? ? case 1:
? ? ? ? ? ? ? ? ? ? oC.width = oImg.height;
? ? ? ? ? ? ? ? ? ? oC.height = oImg.width;
? ? ? ? ? ? ? ? ? ? cxt.rotate(90*Math.PI/180);
? ? ? ? ? ? ? ? ? ? cxt.drawImage(oImg,0,-oImg.height);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case 2:
? ? ? ? ? ? ? ? ? ? oC.width = oImg.width;
? ? ? ? ? ? ? ? ? ? oC.height = oImg.height;
? ? ? ? ? ? ? ? ? ? cxt.rotate(180*Math.PI/180);
? ? ? ? ? ? ? ? ? ? cxt.drawImage(oImg,-oImg.width,-oImg.height);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case 3:
? ? ? ? ? ? ? ? ? ? oC.width = oImg.height;
? ? ? ? ? ? ? ? ? ? oC.height = oImg.width;
? ? ? ? ? ? ? ? ? ? cxt.rotate(270*Math.PI/180);
? ? ? ? ? ? ? ? ? ? cxt.drawImage(oImg,-oImg.width,0);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case 0:
? ? ? ? ? ? ? ? ? ? oC.width = oImg.width;
? ? ? ? ? ? ? ? ? ? oC.height = oImg.height;
? ? ? ? ? ? ? ? ? ? cxt.rotate(0*Math.PI/180);
? ? ? ? ? ? ? ? ? ? cxt.drawImage(oImg,0,0);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
漸變
A: 創(chuàng)建線性漸變
creatLinearGradient(x1,y1,x2,y2)
? 參數(shù)
? x1:起始坐標(biāo)x軸
? y1:起始坐標(biāo)y軸
? x2: 終止坐標(biāo)x軸
? y2:終止坐標(biāo)y軸
? 給漸變對象添加顏色 addColorStop()
? ? 接收兩個參數(shù)
? ? 第一個參數(shù) 規(guī)定漸變的位置
? ? 第二個參數(shù) 漸變的顏色
? ? 語法: addColorStop(0,'red');
// A實例
? ? ? ? //創(chuàng)建漸變對象
? ? ? ? var grad = cxt.createLinearGradient(100,100,300,300);
? ? ? ? // 給漸變對象添加顏色
? ? ? ? grad.addColorStop(0,'#f00');
? ? ? ? grad.addColorStop(0.3,'#e12');
? ? ? ? grad.addColorStop(1,'#f1e');
? ? ? ? // 將漸變對象賦值給fillStyle并創(chuàng)建一圖形
? ? ? ? cxt.fillStyle = grad;
? ? ? ? cxt.fillRect(0,0,oC.width,oC.height);
效果:

B:創(chuàng)建徑向漸變? createRadialGradient(x1,y1,r1,x2,y2,r2) x1/y1:起始位置坐標(biāo)
x2/y2:結(jié)束位置坐標(biāo)
r1/r2: 開始結(jié)束的半徑
? ? // 創(chuàng)建一個徑向漸變
? ? var? grad = cxt.createRadialGradient(200,200,50,200,200,100) ;
? ? // 給徑向漸變對象添加顏色
? ? grad.addColorStop(0,'purple');
? ? grad.addColorStop(1,'blue');
? ? // 把樣式賦值給fillStyle
? ? cxt.fillStyle = grad;
? ? // 創(chuàng)建一個圖形
? ? cxt.fillRect(0,0,oC.width,oC.height);

文本
cxt.strokeText('文本內(nèi)容',x,y);
參數(shù):
x,y:文本位置坐標(biāo)
cxt.fillText('明天',200,300);
var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
cxt.fillText('明天',200,300);
效果;

var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
cxt.fillStyle ='yellow';//字體顏色
cxt.fillText('明天',200,300);
效果:
var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
cxt.fillStyle ='yellow';
cxt.font = 'italic bold 100px? impact';//字體 傾斜加粗字號100px
cxt.fillText('明天',200,300);
效果:


var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
cxt.strokeText('你好',200,300);
效果:

var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
cxt.strokeStyle=‘orange';
cxt.strokeText('你好',200,300);
效果:

var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
cxt.strokeStyle=‘orange';
cxt.font = 'italic bold 100px? impact';//字體 傾斜加粗字號100px
cxt.strokeText('你好',200,300);
效果:

var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
cxt.strokeStyle='orange';
cxt.font = 'italic bold 100px? impact';//字體 傾斜加粗字號100px
cxt.strokeText('你好',100,100);
cxt.fillStyle ='yellow';
cxt.fillText('明天',200,300);
效果:

var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
var? grad = cxt.createLinearGradient(250,300,400,500);
grad.addColorStop(0,'#fc3');
? ? ? ? ? ? grad.addColorStop(0.3,'#12fc');
? ? ? ? ? ? grad.addColorStop(1,'#10fc');
? ? ? ? ? ? cxt.font = 'italic bold 100px? impact';
? ? ? ? ? ? cxt.fillStyle = grad;
? ? ? ? ? ? cxt.fillText('明天',200,300)
效果:

var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
cxt.strokeStyle='orange';
cxt.font = 'italic bold 100px? impact';//字體 傾斜加粗字號100px
var? grad = cxt.createRadialGradient(100,100,100,150,150,200);
// 給徑向漸變對象添加顏色
grad.addColorStop(0,'#fc3');
grad.addColorStop(0.3,'#12fc');
grad.addColorStop(1,'#10fc');
cxt.strokeText('你好',100,100);
cxt.fillText('明天',200,300);
var? grad = cxt.createRadialGradient(100,100,100,150,150,200);
// 給徑向漸變對象添加顏色
grad.addColorStop(0,'#fc3');
grad.addColorStop(0.3,'#12fc');
grad.addColorStop(1,'#10fc');
// 把樣式賦值給fillStyle
cxt.strokeStyle = grad;
cxt.strokeText('你好',100,100);
效果:

陰影
創(chuàng)建陰影
cxt.shadowOffsetX:陰影x軸偏移量 ,
可以為負(fù)值,正值向右,負(fù)值向左偏移
cxt.shadowOffsetY:陰影x軸偏移量 ,
可以為負(fù)值,正值向下,負(fù)值向上偏移
cxt.shadowBlur:陰影的模糊值,值越大,
模糊度越強(qiáng)
cxt.shadowColor:陰影的顏色
var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
cxt.shadowOffsetX ='20';//陰影x軸偏移量
cxt.shadowOffsetY = '10'//陰影x軸偏移量
cxt.shadowBlur = '10';//陰影的模糊值
cxt.shadowColor ='red';//陰影的顏色
cxt.fillRect(100,100,100,100);
效果:

var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
var? grad = cxt.createRadialGradient(100,100,100,150,150,200);
// 給徑向漸變對象添加顏色
grad.addColorStop(0,'#fc3');
grad.addColorStop(0.3,'#12fc');
grad.addColorStop(1,'#10fc');
cxt.shadowOffsetX ='20';
cxt.shadowOffsetY = '10'
cxt.shadowBlur = '10';
cxt.shadowColor ='red'
// 把樣式賦值給fillStyle
cxt.strokeStyle = grad;
cxt.strokeText('你好',100,100);

像素:
oCxt.getImageData(x,y,w,h);
返回一個圖像對象,這個對象包含了這個圖像的像素信息
參數(shù):
x/y:獲取像素點的坐標(biāo)位置
w/h:獲取圖像的寬高
createImageData(w,h)創(chuàng)建圖像
參數(shù):
w:創(chuàng)建圖像的寬
h:創(chuàng)建圖像的高?
putImageData(imgData,x,y,w,h)將像素放入畫布中、
參數(shù):創(chuàng)建的像素
x/y:像素坐標(biāo)
w/h:像素大小
練習(xí):創(chuàng)建一個100*100的圖像 ,紅色,255,0,,0,255
? var oC = document.getElementById('c1');
? var oCxt = oC.getContext('2d');
? var imgData = oCxt.createImageData(100,100);
? for(var? i =0; i<imgData.data.length;i++){
// 把每個像素的四個值都要賦值成紅色對應(yīng)的rgba
? ? ? ? //rgba? 紅綠藍(lán)透明度 每4個值代表一個像素
? ? ? ? imgData.data[4*i]='255';
? ? ? ? imgData.data[4*i+1]='0';
? ? ? ? imgData.data[4*i+2]='0';
? ? ? ? imgData.data[4*i+3]='255';
? ? ? ? }
? ? ? ? //放入畫布
? oCxt.putImageData(imgData,200,200)
效果:

measure:
? measureText();
? 語法:mearsureText('測量的文本').wdith;
? ? ? ? 測量文本的寬度/密度
? ? ? ? 把文字水平居中的方式
? ? ? ? x軸坐標(biāo)(畫布的寬- 字體的寬)/2
練習(xí):將‘往后余生’水平居中
var oC = document.getElementById('c1');
var cxt = oC.getContext('2d');
var str? = '往后余生';
cxt.font ='bold 100px impact';
var cX = (oC.width - cxt.measureText(str).width)/2;
cxt.fillText(str,cX,100);
效果:

至此,canvas的一些知識也介紹的差不多了,中間有一些案例供大家參考,說的有些啰嗦,適合初學(xué)者,希望對大家有一些幫助吧!