一、基本介紹
1,canvas是畫布,可以描畫線條,圖片等,現代的瀏覽器大部分都支持。
canvas的width,height默認為300*150,要指定畫布大小,不能用css樣式的widh,height。只能在html標簽中指定,或是用js對canvas對象設置。
<canvas id="wfPicture" width=300px; height=300px;> </canvas>
2,canvas的Path描畫
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <style> #wfPicture{ border: 1px solid; } </style> <script> function drawWorkflowPicture(){ var canvas = document.getElementById("wfPicture"); console.log("canvas:",canvas); var ctx = canvas.getContext("2d"); // 保存平移前的狀態 ctx.save(); // 平移到 100, 100 ctx.translate(100, 100); // 創建樹冠 createCanopyPath(ctx); // 描畫當前路徑 ctx.stroke(); // 恢復狀態到平移前 ctx.restore(); } function createCanopyPath(ctx){ ctx.beginPath(); // 畫一個樹冠底部為50px,每層高30px,共3層的樹冠 // 樹冠的頂點 ctx.moveTo(0,0); // 左邊的點 ctx.lineTo(-15, 30); ctx.lineTo(-5, 30); ctx.lineTo(-20, 60); ctx.lineTo(-10, 60); ctx.lineTo(-25, 90); // 右邊的點 ctx.lineTo(25, 90); ctx.lineTo(10, 60); ctx.lineTo(20, 60); ctx.lineTo(5, 30); ctx.lineTo(15, 30); ctx.closePath(); } window.addEventListener("load", function(){ drawWorkflowPicture(); }); </script> </head> <body> <canvas id="wfPicture" width=300px; height=300px;> </canvas> </body> </html>

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <style> #wfPicture{ border: 1px solid; } </style> <script> function drawWorkflowPicture(){ var canvas = document.getElementById("wfPicture"); console.log("canvas:",canvas); var ctx = canvas.getContext("2d"); // 保存平移前的狀態 ctx.save(); // 平移到 100, 100 ctx.translate(100, 100); // 創建樹冠 createCanopyPath(ctx); //線條寬度 ctx.lineWidth=4; //結合點平滑效果 "bevel|round|miter"; bevel:斜角 miter:尖角(默認) ctx.lineJoin="round"; // 線條樣式棕色 ctx.strokeStyle="#663300"; // 描畫當前路徑 ctx.stroke(); // 用綠色填充閉合路徑 ctx.fillStyle="#339900"; ctx.fill(); // 填充色恢復成棕色 ctx.fillStyle="#663300"; // 填充樹干 ctx.fillRect(-5,90,10,50); // 恢復狀態到平移前 ctx.restore(); // 保存狀態,繪制曲線 ctx.save(); ctx.translate(0, 350); // 畫路徑前,這一句話必須有 ctx.beginPath(); //小路左下的起點 ctx.moveTo(-10, 0); // 100,20 為第一條曲線的控制點。270, -200為終點 ctx.quadraticCurveTo(100, 20, 270, -200); // 400, -340 為第二條曲線的控制點。 //上一條曲線的270, -200為第二條曲線的起點,510, -270為終點 ctx.quadraticCurveTo(400, -340, 510, -270); ctx.strokeStyle="#663300"; ctx.lineWidth=20; ctx.stroke(); // 恢復狀態到平移前 ctx.restore(); //用背景圖替換掉樹干的顏色 var backImg = new Image(); backImg.src="trunk.jpg";// // 保證圖片加載完后,再描畫 backImg.onload=function(){ //這里是異步調用,里面的坐標最好用絕對坐標,不要translate // 不然里面和外面的代碼會互相干擾 ctx.drawImage(backImg,95,190,10,50); }; } function createCanopyPath(ctx){ ctx.beginPath(); // 畫一個樹冠底部為50px,每層高30px,共3層的樹冠 // 樹冠的頂點 ctx.moveTo(0,0); // 左邊的點 ctx.lineTo(-15, 30); ctx.lineTo(-5, 30); ctx.lineTo(-20, 60); ctx.lineTo(-10, 60); ctx.lineTo(-25, 90); // 右邊的點 ctx.lineTo(25, 90); ctx.lineTo(10, 60); ctx.lineTo(20, 60); ctx.lineTo(5, 30); ctx.lineTo(15, 30); ctx.closePath(); } window.addEventListener("load", function(){ drawWorkflowPicture(); }); </script> </head> <body> <canvas id="wfPicture" width=500px; height=500px;> </canvas> </body> </html>

3,文字描畫
1)空心文字
<!DOCTYPE html> <html> <body> <canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"> Your browser does not support the HTML5 canvas tag.</canvas> <script type="text/javascript"> var c=document.getElementById("myCanvas"); var ctx=c.getContext("2d"); ctx.font="30px Verdana"; // Create gradient var gradient=ctx.createLinearGradient(0,0,c.width,0); gradient.addColorStop("0","magenta"); gradient.addColorStop("0.5","blue"); gradient.addColorStop("1.0","red"); // Fill with gradient ctx.strokeStyle=gradient; ctx.strokeText("w3school.com.cn",10,50); ctx.font="30px 微軟雅黑"; ctx.strokeStyle="#000"; ctx.strokeText("w3school.com.cn",10,80); </script> </body> </html>

4,填充
1)直接填充矩形
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="red";
ctx.fillRect(0,0,300,150);
ctx.clearRect(20,20,100,50);

2)填充閉合的path
// 描畫當前路徑
ctx.stroke();
// 用綠色填充閉合路徑
ctx.fillStyle="#339900";
ctx.fill();

5,旋轉
圖片旋轉一定要等圖片加載完成才可以。
//旋轉圖片
var backImg2 = new Image();
backImg2.src="road2.jpg";//
backImg2.onload=function(){
//這里是異步調用,里面的坐標最好用絕對坐標,不要translate
// 不然里面和外面的代碼會互相干擾,下面漸變色的顏色,暫時注釋
ctx.save();
ctx.translate(0,0);
ctx.rotate(0.57);
ctx.drawImage(backImg2, 0,0,100,100);
ctx.restore();
};
6,支持對像素的操作
canvas上的每個像素都可以取得和設定值,這提供了極大的靈活性。
主要通過getImageData,putImageData,createImageData來完成。
function copy()
{
var imgData=ctx.getImageData(10,10,50,50);
ctx.putImageData(imgData,10,70);
}
var c=document.getElementById("myCanvas"); var ctx=c.getContext("2d"); var imgData=ctx.createImageData(100,100); for (var i=0;i<imgData.data.length;i+=4) { imgData.data[i+0]=255; imgData.data[i+1]=0; imgData.data[i+2]=0; imgData.data[i+3]=255; } ctx.putImageData(imgData,10,10);
二、一個綜合的例子
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <style> #wfPicture{ border: 1px solid; } </style> <script> function drawWorkflowPicture(){ var canvas = document.getElementById("wfPicture"); console.log("canvas:",canvas); var ctx = canvas.getContext("2d"); // 畫第一棵樹 ctx.save();// 保存平移前的狀態 ctx.translate(100, 100);// 平移到 100, 100 drawTree(ctx);//畫樹 ctx.restore();// 恢復狀態到平移前 // 畫第一棵樹 ctx.save();// 保存平移前的狀態 ctx.translate(250, 250);// 平移到 100, 100 ctx.scale(2,2); drawTree(ctx);//畫樹 ctx.restore();// 恢復狀態到平移前 //用圖片畫小路 var backImg = new Image(); backImg.src="road.jpg";// // 保證圖片加載完后,再描畫 backImg.onload=function(){ //這里是異步調用,里面的坐標最好用絕對坐標,不要translate // 不然里面和外面的代碼會互相干擾,下面漸變色的顏色,暫時注釋 ctx.save(); ctx.translate(0, 350); drawRoad(ctx, backImg); ctx.restore(); }; // 添加文字標題 ctx.save(); ctx.font="60px impact"; ctx.fillStyle="#996600"; ctx.textAlign="center"; // 添加文字陰影 ctx.shadowColor="rgba(0,0,0,0.2)"; ctx.shadowOffsetX=15; ctx.shadowOffsetY=-10; ctx.shadowBlur=2; ctx.fillText("Happy Trees!", 200, 60); ctx.restore(); } // 畫樹 function drawTree(ctx){ ctx.save(); // 畫樹的陰影 // 下面這一步是因為我畫樹是以樹頂端作為原點0,0來畫的,有偏移,必須這樣矯正。!doctype // 正確的做法,還是應該以樹根作為基准點,這樣樹的傾斜才會以根部為基礎。 ctx.translate(Math.tan(0.5) * 140 * 0.6 -4, 140 * 0.4); ctx.transform(1,0,-0.5,1,0,0); ctx.scale(1,0.6); ctx.fillStyle="rgba(0,0,0,0.2)"; ctx.fillRect(-5,90,10,50); ctx.fill(); createCanopyPath(ctx); ctx.fill(); ctx.restore(); // 創建樹干用漸變色 var trunkGradient = ctx.createLinearGradient(-5, 90, 5, 90); trunkGradient.addColorStop(0, '#663300'); trunkGradient.addColorStop(0.4, '#996600'); //樹干最右邊,顏色最深 trunkGradient.addColorStop(1, '#552200'); ctx.fillStyle=trunkGradient; ctx.fillRect(-5,90,10,50); //創建垂直漸變,用作樹冠在樹干上的投影 var canopyShadow = ctx.createLinearGradient(-5, 90, -5, 140); canopyShadow.addColorStop(0, 'rgba(0,0,0,0.5)');//黑色半透明 canopyShadow.addColorStop(0.2, 'rgba(0,0,0,0.0)');//全透明 ctx.fillStyle=canopyShadow; ctx.fillRect(-5,90,10,50); // 創建樹冠 createCanopyPath(ctx); //線條寬度 ctx.lineWidth=4; //結合點平滑效果 "bevel|round|miter"; bevel:斜角 miter:尖角(默認) ctx.lineJoin="round"; // 線條樣式棕色 ctx.strokeStyle="#663300"; // 描畫當前路徑 ctx.stroke(); // 用綠色填充閉合路徑 ctx.fillStyle="#339900"; ctx.fill(); // 畫樹的陰影 // 下面這一步是因為我畫樹是以樹頂端作為原點0,0來畫的,有偏移,必須這樣矯正。!doctype // 正確的做法,還是應該以樹根作為基准點,這樣樹的傾斜才會以根部為基礎。 // ctx.translate(Math.tan(0.5) * 140 * 0.6, 140 * 0.4); // ctx.transform(1,0,-0.5,1,0,0); // ctx.scale(1,0.6); // ctx.fillStyle="rgba(0,0,0,0.2)"; // ctx.fillRect(-5,90,10,50); // ctx.fill(); // // createCanopyPath(ctx); // ctx.fill(); } // 畫樹冠 function createCanopyPath(ctx){ ctx.beginPath(); // 畫一個樹冠底部為50px,每層高30px,共3層的樹冠 // 樹冠的頂點 ctx.moveTo(0,0); // 左邊的點 ctx.lineTo(-15, 30); ctx.lineTo(-5, 30); ctx.lineTo(-20, 60); ctx.lineTo(-10, 60); ctx.lineTo(-25, 90); // 右邊的點 ctx.lineTo(25, 90); ctx.lineTo(10, 60); ctx.lineTo(20, 60); ctx.lineTo(5, 30); ctx.lineTo(15, 30); ctx.closePath(); } function drawRoad(ctx, backImg){ // 畫路徑前,這一句話必須有 ctx.beginPath(); //小路左下的起點 ctx.moveTo(-10, 0); // 100,20 為第一條曲線的控制點。270, -200為終點 ctx.quadraticCurveTo(100, 20, 270, -200); // 400, -340 為第二條曲線的控制點。 //上一條曲線的270, -200為第二條曲線的起點,510, -270為終點 ctx.quadraticCurveTo(400, -340, 510, -270); ctx.strokeStyle= ctx.createPattern(backImg, 'repeat'); // "#663300"; ctx.lineWidth=20; ctx.stroke(); } window.addEventListener("load", function(){ drawWorkflowPicture(); }); </script> </head> <body> <canvas id="wfPicture" width=400px; height=600;> </canvas> </body> </html>

