canvas的用法

包括:
介紹。
基礎入門。(兼容性。獲取canvas上下文。繪製直線/描邊,填充內容。繪製表格。)
canvas是基於狀態的繪圖。
繪製矩形。
繪製圓形。
繪製文本。
繪製圖片。
陰影。
漸變。
繪製背景圖。
變換。



介紹:
HTML5的新標籤<canvas></canvas>

canvas標籤經過JavaScript在網頁上繪製圖像,自己不具有繪圖功能。
canvas擁有多種繪製路徑,矩形,圓形,字符以及添加圖像的方法。

canvas能夠作遊戲,圖表,廣告等等。

基礎入門。
設置canvas的寬和高是經過canvas標籤的屬性來設置,不要用css設置。 css

<canvas id="canvas" width="400" height="400"></canvas>


還能夠在JS中經過屬性指定。 html

var canvas = document.getElementById('canvas');  //獲取canvas標籤
canvas.width=400;
canvas.height=400;



兼容性。
當瀏覽器不支持canvas時,在canvas標籤內編寫提示文字。
web

<canvas>你的瀏覽器不支持canvas,請更換瀏覽器後再試。</canvas>


(當瀏覽器支持canvas時,canvas會執行相關JS代碼)

獲取canvas上下文。
canvas上下文就是繪製工具的集合。

寫在canvas標籤後,或者window.onload = function(){}
json

var canvas = document.getElementById('canvas');  //獲取canvas標籤
var ctx= canvas.getContext('2d');  //獲取canvas的上下文  3D=>'webgl'



獲得canvas上下文後就能夠開始繪製了。
canvas的座標系和瀏覽器的座標系一致。都是左上角爲(0,0)。

繪製直線/描邊,填充內容。 canvas

ctx.moveTo(100,100);  //畫筆移動到(100,100)
ctx.lineTo(200,100);  //畫一條直線到(200,100)
ctx.lineTo(100,200);  //畫一條直線到(100,200)
//到此爲止,只繪製了路徑,還沒描線。

ctx.stroke();  //描線。




將路徑閉合。 瀏覽器

ctx.moveTo(100,100);  //畫筆移動到(100,100)
ctx.lineTo(200,100);  //畫一條直線到(200,100)
ctx.lineTo(100,200);  //畫一條直線到(100,200)

ctx.lineTo(100,100);  //畫一條直線到(100,100)

ctx.stroke();  //描線。



還可使用ctx.closePath()來閉合路徑。 dom

ctx.moveTo(100,100);  //畫筆移動到(100,100)
//必需要寫moveTo(),不然畫筆沒有位置。
//沒有寫moveTo()直接寫lineTo()的話,畫筆的位置直接到lineTo()的位置,至關於moveTo()

ctx.lineTo(200,100);  //畫一條直線到(200,100)
ctx.lineTo(100,200);  //畫一條直線到(100,200)

ctx.closePath()  //閉合路徑

ctx.stroke();  //描線。


都是同樣的效果:


修改描邊的樣式。在stroke()描邊以前設置描邊樣式。 工具

ctx.lineWidth = 4;  //線寬
ctx.strokeStyle = 'red';  //顏色




填充內容。默認是黑色。修改填充的樣式。 動畫

ctx.fill();
ctx.fillStyle = 'blue';  //顏色




問題:填充後,爲何描邊變細?
答案:描邊是2像素在裏面2像素在外邊。填充後,裏面的2像素被遮蓋住了。


繪製表格。 webgl

var rectH = 10;  //行高
var rectW = 10;  //列寬
//繪製橫線:
for(var i = 0;i< canvas.width / rectH;i++){
	ctx.moveTo(0,i*rectH);
	ctx.lineTo(canvas.width,i*rectH);
	//繪製豎線
	for(var j = 0;j<canvas.height / rectW;j++){
		ctx.moveTo(j*rectW,0);
		ctx.lineTo(j*rectW,canvas.height);
	}
}
ctx.lineWidth = 0.5;
ctx.strokeStyle = '#ccc';
ctx.stroke();



在這基礎上就能夠繪製折線圖了。

繪製箭頭的思路:

繪製數據的思路:

var x0 = 100,y0 = 500;
var maxHeight = 300;
var arrowWidth = 10;// 箭頭寬度

// 繪製x軸
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.moveTo(x0, y0);
ctx.lineTo(500, 500);

// 箭頭
ctx.lineTo(500-arrowWidth, 500-arrowWidth);
ctx.moveTo(500, 500);
ctx.lineTo(500-arrowWidth, 500+arrowWidth);
ctx.stroke();

//繪製y軸
ctx.beginPath();
ctx.strokeStyle = "purple";
ctx.moveTo(x0, y0);
ctx.lineTo(100, 100);

// 箭頭
ctx.lineTo(100-arrowWidth, 100+arrowWidth);
ctx.moveTo(100, 100);
ctx.lineTo(100+arrowWidth, 100+arrowWidth);
ctx.stroke();

// 繪製線段
var data = [.4 ,.5 ,.8 ,.7];
var pointWidth = 400 / (data.length + 1);
ctx.beginPath();
ctx.strokeStyle = "red";
for(var i=0;i<data.length;i++){
	var x =x0 +(i + 1) * pointWidth;
	var y =y0 - data[i] * maxHeight;
	ctx.lineTo(x, y);
}
ctx.stroke();






canvas是基於狀態的繪圖。
好比繪製兩條不一樣顏色的直線。

ctx.strokeStyle = 'red';
ctx.lineWidth=5;

//第一條線
ctx.moveTo(100,100);
ctx.lineTo(300,100);
ctx.stroke();

//第二條線
ctx.strokeStyle = 'blue';
ctx.moveTo(100,200);
ctx.lineTo(300,200);
ctx.stroke();





問題:兩條線顏色爲何同樣?
解決方法:canvas是基於狀態的繪圖。設置ctx.beginPath()便可。

//第二條線
ctx.beginPath();

ctx.strokeStyle = 'blue';
ctx.moveTo(100,200);
ctx.lineTo(300,200);
ctx.stroke();





beginPath()至關於開啓新狀態。

繪製第一條線的時候也能夠beginPath(),默認一開始就有狀態。
繪製第二條線的新狀態,能夠繼承以前的狀態的樣式,可是當前的狀態設置的全部樣式,只能做用於當前的狀態。

繪製矩形。
繪製矩形:ctx.rect(x,y,w,h);  //左上角座標(x,y),w寬,h高。

ctx.rect(50,50,50,50);
ctx.stroke();

ctx.strokeRect(120,120,50,50);  //和上面寫法的效果一致。

ctx.fillRect(190,190,50,50);  //若是是fill(填充),會自動閉合路徑。





清除矩形:至關於橡皮擦。
ctx.clearRect(x,y,w,h);

ctx.clearRect(195,195,30,30);





繪製圓形。

ctx.arc(x,y,r,startAngle,endAngle,counterclockwise); 
//圓心座標(x,y),半徑r,開始弧度,結束弧度,順時針/逆時針(默認順時針如圖)





換算公式:rad = deg*Math.PI/180;

繪製0-30°的圓弧。

ctx.arc(100,100,100,0,30*Math.PI/180,false);





加上closePath()會閉合路徑。



若是要鏈接到圓心點。先moveTo(圓心點)便可。

ctx.moveTo(100,100)
ctx.arc(100,100,100,0,30*Math.PI/180,false);
ctx.closePath();
ctx.stroke();





繪製餅狀圖的其中一個扇形。

ctx.moveTo(200,200);
ctx.fillStyle = 'red'
ctx.arc(200,200,100,-90*Math.PI/180,-30*Math.PI/180,false);
ctx.fill()





假設有這樣一個JSON數據。

var data =[{
"value":.2,
"color":"red",
"title":"應屆生"
},{
"value":.3,
"color":"blue",
"title":"社會招生"
},{
"value":.4,
"color":"green",
"title":"推薦"
},{
"value":.1,
"color":"yellow",
"title":"公開課"
}];



將數據變成餅狀圖。
value表明佔比。從-90°開始繪製。

//先畫扇形。
var tempAngle = -90;  //從-90度開始
var x0 = 150,y0 = 150,radius = 100;  //圓心和半徑
for(var i=0;i<data.length;i++){
	ctx.beginPath();
	ctx.moveTo(x0,y0);  //圓心
	var angle = data[i].value*360;  //當前扇形的角度
	ctx.fillStyle = data[i].color;

	var startAngle = tempAngle * Math.PI/180;  //開始角度
	var endAngle = (tempAngle + angle) * Math.PI/180;  //結束角度

	ctx.arc(x0,y0,radius,startAngle,endAngle)
	ctx.fill();

	tempAngle+=angle;
}





繪製文本。
ctx.strokeText('hello',450,400); //文字,座標
ctx.fillText('hello',150,100);

ctx.moveTo(300,300);
ctx.fillStyle = 'purple';
ctx.font = '20px 微軟雅黑';
ctx.textBaseline = "bottom";  //基線
ctx.textAlign = "left";
// ctx.strokeText('hello',450,400);  //空心文字
ctx.fillText('hello',100,300);  //實體填充文字




行高行距的概念:


對齊方式:


餅狀圖的文字。假設,在角度的一半繪製一條直線出來,寫上XX%,思路如圖。



繪製完餅狀圖後,fill前。繪製文字。

// 繪製文字
	var txt = data[i].value * 100 +'%';
	var x,y;
	var textAngle = tempAngle + 1/2 *angle;
	x=x0+Math.cos(textAngle * Math.PI / 180) * (radius + 20);
	y=y0+Math.sin(textAngle * Math.PI / 180) * (radius + 20);

// 左側文字太長會越過餅狀圖。
	if(textAngle>90&&textAngle<270){
		ctx.textAlign = "end"
	}

	ctx.fillText(txt,x,y);



文字會超過:

文字不會超過:

ctx.measureText()  //measure測量;返回文本的寬度




繪製圖片:

ctx.drawImage(img,x,y);  //img是圖片的DOM對象。  繪製的座標。


// 建立圖片的dom對象
var img = new Image();
img.src='img.jpg';  //只要設置了src屬性,當前img對象當即去加載圖片。

img.onload = function(){
	// 圖片加載完成後,繪製圖片
	ctx.drawImage(img,100,100);
}



以上的img和如下的方法得到的img是同樣的,都是dom對象。

var img2 = document.getElementById('imagedemo');





惡搞✧(≖ ◡ ≖✿)

for(var i=0;i<10;i++){
	ctx.drawImage(img,100+i*10,100+i*10);
}





還能夠設置寬高,不設置的時候是圖片的默認寬高。

ctx.drawImage(img,x,y,w,h);  //w,h,寬高。


ctx.drawImage(img,100,100,50,50);



被拉伸:


若是要保持寬高比,則 原來的高度 / 原來的寬度 = 繪製的高度 / 繪製的寬度 。
假設已知繪製的寬度,則繪製的高度爲 原來的高度*繪製的寬度/原來的寬度。

var ow = img.width;
var oh = img.height;
ctx.drawImage(img,100,100,200,200*oh/ow);





繪製圖片裁剪區域。

ctx.drawImage(img,sx,sy,sw,sh,x,y,w,h)  //截取的座標。截取的寬高。繪製的座標。繪製的寬高。



好比:網上找的一張圖:截取出第一我的物:

ctx.drawImage(img,195,26,276,377,100,100,200,300);




逐幀動畫/序列幀動畫:定時器。


先作第一行的動做。

var frameIndex = 0; //幀數
setInterval(function(){
	// 清除以前的內容
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	// 若是經過代碼從新設置canvas畫布的寬高,canvas畫布裏的全部內容都被清空。(不建議使用)
	//canvas.width = canvas.width;
	ctx.drawImage(
		img,
		frameIndex*53.25,  //截取的座標
		0,  //截取的座標
		53.25,  //截取的寬
		92.75,  //截取的高
		200,  //繪製的座標
		200,  //繪製的座標
		53.25*2,  //繪製的寬
		92.75*2  //繪製的高
		)
	frameIndex++;
	frameIndex%=4;  //取餘  4%4=0
},1000/10);  //1秒10幀。





添加四個方向的按鈕。

<button id="btn-left">left</button>
<button id="btn-right">right</button>
<button id="btn-top">top</button>
<button id="btn-down">down</button>

 

var btnLeft = document.getElementById('btn-left')
var btnRight = document.getElementById('btn-right')
var btnTop = document.getElementById('btn-top')
var btnDown = document.getElementById('btn-down')




在繪製圖片前(new Image()前)。設置方向。至關於圖片的第一行。表明向下走。

var dirIndex = 0;


而後將截取的y座標改成dirIndex*92.75,綁定相關的按鈕事件。

btnLeft.onclick = function(){
	dirIndex =1 ;  //第2行
}
btnRight.onclick = function(){
	dirIndex =2 ;  //第3行
}
btnTop.onclick = function(){
	dirIndex =3 ;  //第4行
}
btnDown.onclick = function(){
	dirIndex =0 ;  //第1行
}



點擊效果:



陰影

// 設置陰影
ctx.fillStyle = 'red';
ctx.shadowColor = 'teal';  //顏色
ctx.shadowBlur = 10;  //模糊 ( 大於1 )
ctx.shadowOffsetX = 10;  //偏移
ctx.shadowOffsetY = 10;
ctx.fillRect(100,100,100,100);




漸變

// 線性漸變
var grd = ctx.createLinearGradient(0, 0, 170, 0);
grd.addColorStop(0,"black");
grd.addColorStop(0.5,"red");
grd.addColorStop(1,'white');
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 300, 300);



// 圓形漸變
var rlg = ctx.createRadialGradient(300, 300, 10, 300, 300, 200);
rlg.addColorStop(0,"white");
rlg.addColorStop(0.5,"red");
rlg.addColorStop(1,'black');
ctx.fillStyle = rlg;
ctx.fillRect(100, 100, 400, 400);




繪製背景圖

var pat = ctx.createPattern(img,repeat);  //img是DOM對象
ctx.rect(0, 0, 150, 100);
ctx.fillStyle = pat;
ctx.fill();



變換

ctx.scale(Scale Width, Scale Height);  //縮放當前繪圖  1爲100%
ctx.translate(X, Y);  //位移畫布
ctx.rotate(Rotate Angle);  //旋轉當前繪圖
ctx.save();  //保存當前環境的狀態
ctx.restore();  //返回以前保存過的路徑狀態和屬性
ctx.globalAlpha = "Value between 0 & 1";  //繪製環境的透明度



例子:

// 狀態1
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 100, 100);

ctx.save();  //保存狀態
ctx.translate(200, 200);  //把當前畫布移動到200,200的位置
ctx.rotate(30* Math.PI / 180);  //旋轉
ctx.scale(2, 2);  //縮放
ctx.globalAlpha = ".3";  //透明度

ctx.moveTo(0, 0);
ctx.lineTo(400, 0);
ctx.moveTo(0, 0);
ctx.lineTo(0, 400);
ctx.stroke();
ctx.fillRect(10, 10, 40, 40);
ctx.restore();  //返回以前保存過的路徑狀態和屬性

ctx.fillRect(400, 400, 100, 100);


相關文章
相關標籤/搜索