HTML5 學習總結(四)——canvas繪圖、WebGL、SVG
一、Canvas
canvas是HTML5中新增的一個HTML5標簽與操作canvas的javascript API,它可以實現在網頁中完成動態的2D與3D圖像技術。<canvas> 標記和 SVG以及 VML 之間的一個重要的不同是,<canvas> 有一個基於 JavaScript 的繪圖 API,而 SVG 和 VML 使用一個 XML 文檔來描述繪圖。SVG 繪圖很容易編輯與生成,但功能明顯要弱一些。
canvas可以完成動畫、游戲、圖表、圖像處理等原來需要Flash完成的一些功能。、
瀏覽器支持情況如下:
<canvas id="can" width="800" height="600">不支持Canvas</canvas>
以上代碼創建了一個寬度為800像素,高度為600像素的canvas。不建議使用CSS樣式指定寬度和高度。
canvas標簽中間的內容為替代顯示內容,當瀏覽器不支持canvas標簽時會顯示出來。
創建了canvas元素后,要在canvas元素上面繪制圖象,首先必須獲取canvas環境上下文:
canvas.getContext(畫布上繪制的類型)
畫布上繪制的類型:
2d: 表示2維
experimental-webgl: 表示試驗版3維
webgl:表示3維
Hello Wolrd示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas繪圖1</title> </head> <body> <canvas id="canvas1" width="800" height="600"></canvas> <script type="text/javascript"> //獲得畫布元素 var canvas1=document.getElementById("canvas1"); //獲得2維繪圖的上下文 var ctx = canvas1.getContext("2d"); //設置線寬 ctx.lineWidth=10; //設置線的顏色 ctx.strokeStyle="blue"; //將畫筆移動到00點 ctx.moveTo(0,0); //畫線到800,600的坐標 ctx.lineTo(800,600); //執行畫線 ctx.stroke(); </script> </body> </html>
運行效果:
在頁面上就顯示了一條直線,另存為后就是一張背景透明的png圖片。
練習:畫一個100X100的正方形在畫布正中央
1.2、畫線
context.moveTo(x,y)
把畫筆移動到x,y坐標,建立新的子路徑。
context.lineTo(x,y)
建立上一個點到x,y坐標的直線,如果沒有上一個點,則等同於moveTo(x,y),把(x,y)添加到子路徑中。
context.stroke()
描繪子路徑
//設置線寬 ctx.lineWidth = 10; //設置線的顏色 ctx.strokeStyle = "blue"; //將畫筆移到x0,y0處 context.moveTo(x0, y0); //從x0,y0到x1,y1畫一條線 ontext.lineTo(x1, y1); //從x1,y1到x2,y2畫條線 ontext.lineTo(x2, y2); //執行填充 ontext.fill(); //執行畫線 context.stroke();
結合javascript事件實現鼠標自由划線:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas繪圖1</title> </head> <body> <canvas id="canvas1" width="800" height="600"></canvas> <script type="text/javascript"> //獲得畫布元素 var canvas1=document.getElementById("canvas1"); //獲得2維繪圖的上下文 var ctx = canvas1.getContext("2d"); //設置線寬 ctx.lineWidth=10; //設置線的顏色 ctx.strokeStyle="blue"; canvas1.onmousedown = function(ev){ var ev = ev || event; ctx.moveTo(ev.clientX,ev.clientY); document.onmousemove = function(ev){ var ev = ev || event; // 划線到當前客戶端的x與y座標 ctx.lineTo(ev.clientX,ev.clientY); // 執行畫線 ctx.stroke(); }; document.onmouseup = function(){ document.onmousemove = document.onmouseup=null; } } </script> </body> </html>
運行效果:
1.2.1、路徑與closePath,beginPath,fill
canvas的環境上下文中總有唯一一個路徑,路徑包含多個子路徑,這些子路徑可以看成是一系列點的集合。
beginPath()
清空子路徑,一般用於開始路徑的創建。在幾次循環地創建路徑的過程中,每次開始創建時都要調用beginPath函數。
closePath()
如果當前子路徑是打開的,就關閉它。否則把子路徑中的最后一個點和路徑中的第一個點連接起來,形成閉合回路。
canvas繪圖有兩種模式,一種是fill,一種是stroke,fill是填充,stroke是描邊線,fillstyle,strokeStyle指定繪圖樣式
示例代碼:
<canvas id="canvas1" width="800" height="600"></canvas> <script type="text/javascript"> //獲得畫布元素 var canvas1=document.getElementById("canvas1"); //獲得2維繪圖的上下文 var ctx = canvas1.getContext("2d"); //設置線寬 ctx.lineWidth=10; //設置線的顏色 ctx.strokeStyle="blue"; ctx.moveTo(0,0); //移動畫筆到0,0點 ctx.lineTo(300,300); //畫線到300,300的位置 ctx.stroke(); //執行描邊 ctx.beginPath(); //清空子路徑,一般用於開始路徑的創建 ctx.strokeStyle = "red"; ctx.moveTo(300,300); ctx.lineTo(0,595); //畫線到0,300的位置 ctx.lineTo(595,595); //畫線到右下角 ctx.closePath(); //閉合 // ctx.stroke(); //執行描邊 ctx.fillStyle="lightgreen"; //設置填充顏色 ctx.fill(); //執行填充 </script>
運行效果:
練習:試着完成一個象棋或圍棋棋盤。

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas繪圖_象棋棋盤</title> </head> <body> <canvas id="canvas1" width="805" height="905">不支持Canvas</canvas> <script type="text/javascript"> //棋盤外框 var canvas1 = document.getElementById("canvas1"); var ctx = canvas1.getContext("2d"); ctx.lineWidth = 5; ctx.strokeStyle = "brown" // 以x,y為左上角,繪制寬度為width,高度為height的矩形。 ctx.strokeRect(3,3,800,900) //此方法用來畫棋盤線 function LineDrawing(mx, my, lx, ly) { ctx.beginPath(); ctx.moveTo(mx, my); ctx.lineTo(lx, ly); ctx.stroke(); } //棋盤列上半部分 ctx.lineWidth = 2; LineDrawing(100, 5, 100, 400); LineDrawing(200, 5, 200, 400); LineDrawing(300, 5, 300, 400); LineDrawing(400, 5, 400, 400); LineDrawing(500, 5, 500, 400); LineDrawing(600, 5, 600, 400); LineDrawing(700, 5, 700, 400); //棋盤列下半部分 LineDrawing(100, 500, 100, 900); LineDrawing(200, 500, 200, 900); LineDrawing(300, 500, 300, 900); LineDrawing(400, 500, 400, 900); LineDrawing(500, 500, 500, 900); LineDrawing(600, 500, 600, 900); LineDrawing(700, 500, 700, 900); //棋盤行 LineDrawing(5, 100, 800, 100); LineDrawing(5, 200, 800, 200); LineDrawing(5, 300, 800, 300); LineDrawing(5, 400, 800, 400); LineDrawing(5, 500, 800, 500); LineDrawing(5, 600, 800, 600); LineDrawing(5, 700, 800, 700); LineDrawing(5, 800, 800, 800); //斜線:上士線 LineDrawing(300, 5, 500, 200); //反斜線:上士線 LineDrawing(500, 5, 300, 200); //斜線:下士線 LineDrawing(300, 900, 500, 700); //反斜線:下士線 LineDrawing(500, 900, 300, 700); //炮:中心點一(100,200) //左上 LineDrawing(90, 170, 90, 190); LineDrawing(90, 190, 70, 190); //右上 LineDrawing(110, 170, 110, 190); LineDrawing(110, 190, 130, 190); //左下 LineDrawing(90, 230, 90, 210); LineDrawing(90, 210, 70, 210); //右下 LineDrawing(110, 230, 110, 210); LineDrawing(110, 210, 130, 210); //炮:中心點二(700,200) //左上 LineDrawing(690, 170, 690, 190); LineDrawing(690, 190, 670, 190); //右上 LineDrawing(710, 170, 710, 190); LineDrawing(710, 190, 730, 190); //左下 LineDrawing(690, 230, 690, 210); LineDrawing(690, 210, 670, 210); //右下 LineDrawing(710, 230, 710, 210); LineDrawing(710, 210, 730, 210); // //炮:中心點三(100,200) // //左上 // LineDrawing(90, 670, 90, 690); // LineDrawing(90, 690, 70, 690); // //右上 // LineDrawing(110, 670, 110, 690); // LineDrawing(110, 690, 130, 690); // //左下 // LineDrawing(90, 730, 90, 710); // LineDrawing(90, 710, 70, 710); // //右下 // LineDrawing(110, 730, 110, 710); // LineDrawing(110, 710, 130, 710); // //炮:中心點四(700,200) // //左上 // LineDrawing(690, 670, 690, 690); // LineDrawing(690, 690, 670, 690); // //右上 // LineDrawing(710, 670, 710, 690); // LineDrawing(710, 690, 730, 690); // //左下 // LineDrawing(690, 730, 690, 710); // LineDrawing(690, 710, 670, 710); // //右下 // LineDrawing(710, 730, 710, 710); // LineDrawing(710, 710, 730, 710); //中心點三(0,300) //右上 LineDrawing(20, 270, 20, 290); LineDrawing(20, 290, 40, 290); //右下 LineDrawing(20, 330, 20, 310); LineDrawing(20, 310, 40, 310); //中心點四(200,300) //左上 LineDrawing(190, 270, 190, 290); LineDrawing(190, 290, 170, 290); //右上 LineDrawing(210, 270, 210, 290); LineDrawing(210, 290, 230, 290); //左下 LineDrawing(190, 330, 190, 310); LineDrawing(190, 310, 170, 310); //右下 LineDrawing(210, 330, 210, 310); LineDrawing(210, 310, 230, 310); //中心點五(400,300) //左上 LineDrawing(390, 270, 390, 290); LineDrawing(390, 290, 370, 290); //右上 LineDrawing(410, 270, 410, 290); LineDrawing(410, 290, 430, 290); //左下 LineDrawing(390, 330, 390, 310); LineDrawing(390, 310, 370, 310); //右下 LineDrawing(410, 330, 410, 310); LineDrawing(410, 310, 430, 310); //中心點六(600,300) //左上 LineDrawing(590, 270, 590, 290); LineDrawing(590, 290, 570, 290); //右上 LineDrawing(610, 270, 610, 290); LineDrawing(610, 290, 630, 290); //左下 LineDrawing(590, 330, 590, 310); LineDrawing(590, 310, 570, 310); //右下 LineDrawing(610, 330, 610, 310); LineDrawing(610, 310, 630, 310); //中心點七(800,300) //左上 LineDrawing(790, 270, 790, 290); LineDrawing(790, 290, 770, 290); //左下 LineDrawing(790, 330, 790, 310); LineDrawing(790, 310, 770, 310); //中心點八——對應中心點七(800,600) //左上 LineDrawing(790, 570, 790, 590); LineDrawing(790, 590, 770, 590); //左下 LineDrawing(790, 630, 790, 610); LineDrawing(790, 610, 770, 610); //中心點九——對應中心點六(600,600) //左上 LineDrawing(590, 570, 590, 590); LineDrawing(590, 590, 570, 590); //右上 LineDrawing(610, 570, 610, 590); LineDrawing(610, 590, 630, 590); //左下 LineDrawing(590, 630, 590, 610); LineDrawing(590, 610, 570, 610); //右下 LineDrawing(610, 630, 610, 610); LineDrawing(610, 610, 630, 610); //中心點十——對應中心點五(400,600) //左上 LineDrawing(390, 570, 390, 590); LineDrawing(390, 590, 370, 590); //右上 LineDrawing(410, 570, 410, 590); LineDrawing(410, 590, 430, 590); //左下 LineDrawing(390, 630, 390, 610); LineDrawing(390, 610, 370, 610); //右下 LineDrawing(410, 630, 410, 610); LineDrawing(410, 610, 430, 610); //中心點十一——對應中心點四(200,600) //左上 LineDrawing(190, 570, 190, 590); LineDrawing(190, 590, 170, 590); //右上 LineDrawing(210, 570, 210, 590); LineDrawing(210, 590, 230, 590); //左下 LineDrawing(190, 630, 190, 610); LineDrawing(190, 610, 170, 610); //右下 LineDrawing(210, 630, 210, 610); LineDrawing(210, 610, 230, 610); //中心點十二——對應中心點三(0,600) //右上 LineDrawing(20, 570, 20, 590); LineDrawing(20, 590, 40, 590); //右下 LineDrawing(20, 630, 20, 610); LineDrawing(20, 610, 40, 610); //中心點十三——對應中心點二(700,500) //左上 LineDrawing(690, 670, 690, 690); LineDrawing(690, 690, 670, 690); //右上 LineDrawing(710, 670, 710, 690); LineDrawing(710, 690, 730, 690); //左下 LineDrawing(690, 730, 690, 710); LineDrawing(690, 710, 670, 710); //右下 LineDrawing(710, 730, 710, 710); LineDrawing(710, 710, 730, 710); //中心點十四——對應中心點一(100,500) //左上 LineDrawing(90, 670, 90, 690); LineDrawing(90, 690, 70, 690); //右上 LineDrawing(110, 670, 110, 690); LineDrawing(110, 690, 130, 690); //左下 LineDrawing(90, 730, 90, 710); LineDrawing(90, 710, 70, 710); //右下 LineDrawing(110, 730, 110, 710); LineDrawing(110, 710, 130, 710); //字體填充:楚河 漢界 //設置線寬 ctx.lineWidth = 1; //繪制文字 ctx.font = "60px microsoft yahei"; ctx.save();//保存點 //將坐標中心作為起啟點 ctx.translate(canvas1.width / 2, canvas1.height / 2); var radian = Math.PI / 2; // 弧度制 ctx.rotate(radian); // 旋轉畫布繪制刻度 //填充 ctx.fillText("楚", -30, -270); ctx.fillText("河", -30, -150); ctx.restore();//恢復到保存點 ctx.save(); //將坐標中心作為起啟點 ctx.translate(canvas1.width / 2, canvas1.height / 2); var radian = Math.PI / -2; ctx.rotate(radian); ctx.fillText("漢", -30, -270); ctx.fillText("界", -30, -150); ctx.restore(); </script> </body> </html>
從上面的代碼可以看出存在很多不足的地方,比如:代碼冗余,繪制棋盤的方法也不是很好,雖然功能是實現了,但作為一名寫程序的程序員我們要追求完美,不是嗎?,所以我又分析了一下我寫的代碼,發現有很多可以改進的地方比如:繪制棋盤的方法可以用循環來做相對好一些,下面是我的第二次代碼改進。

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas繪圖_象棋棋盤</title> </head> <body> <canvas id="canvas1" width="805" height="905">不支持Canvas</canvas> <script type="text/javascript"> //棋盤外框 var canvas1 = document.getElementById("canvas1"); var ctx = canvas1.getContext("2d"); ctx.lineWidth = 5; ctx.strokeStyle = "brown" // 以x,y為左上角,繪制寬度為width,高度為height的矩形。 ctx.strokeRect(3,3,800,900) //此方法用來畫棋盤線 function LineDrawing(mx, my, lx, ly) { ctx.beginPath(); ctx.moveTo(mx, my); ctx.lineTo(lx, ly); ctx.stroke(); } //棋盤行 function row() { for (var i = 100; i <= 800; i += 100) { ctx.beginPath(); ctx.moveTo(5, i); ctx.lineTo(800, i); ctx.stroke(); } } row(); // 棋盤列 function cols() { for (var i = 100; i <= 700; i += 100) { ctx.beginPath(); ctx.moveTo(i, 5); ctx.lineTo(i, 900); ctx.stroke(); } } cols(); // 清除以x,y為左上角,寬度為width,高度為height的矩形區域。 ctx.clearRect(5, 402, 795,95) //斜線 LineDrawing(300, 5, 500, 200); LineDrawing(300, 705, 500, 900); //反斜線 LineDrawing(500, 5, 300, 200); LineDrawing(500, 705, 300, 900); // 中心點,如(100, 200) function center(x,y){ //左上 LineDrawing(x-10,y-30,x-10,y-10); LineDrawing(x-10,y-10,x-30,y-10); //右上 LineDrawing(x+10,y-30,x+10,y-10); LineDrawing(x+10,y-10,x+30,y-10); //左下 LineDrawing(x-10,y+30,x-10,y+10); LineDrawing(x-10,y+10,x-30,y+10); //右下 LineDrawing(x+10,y+30,x+10,y+10); LineDrawing(x+10,y+10,x+30,y+10); } //中心點一(100,200) center(100, 200); //中心點二(700,200) center(700, 200); //中心點三(5,300) center(5, 300); //中心點四(200,300) center(200, 300); //中心點五(400,300) center(400, 300); //中心點六(600,300) center(600, 300); //中心點七(800,300) center(800, 300); //中心點八(800,600) center(800, 600); //中心點九(600,600) center(600, 600); //中心點十(400,600) center(400, 600); //中心點十一(200,600) center(200, 600); //中心點十二(5,600) center(5, 600); //中心點十三(700,700) center(700, 700); //中心點十四(100,700) center(100, 700); </script> </body> </html>
經過一番改進,代碼從原來的245行代碼減少到了125行,代碼冗余和方法使用的問題解決了,那么是不是完事了呢?我再次檢查了一下我寫的代碼,發現還是有改進的地方,就是JavaScript腳本寫的比較亂,定義的方法變量都暴露都直接暴露在window下有可能與別的js沖突,可以進行簡單封裝,下面是我的第三次代碼改進。

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas繪圖_象棋棋盤</title> </head> <body> <canvas id="canvas1" width="805" height="905">不支持Canvas</canvas> <script type="text/javascript"> var object = { LineDrawing:function(mx,my,lx,ly) { //此方法用來畫棋盤線 this.ctx.beginPath(); this.ctx.moveTo(mx, my); this.ctx.lineTo(lx, ly); this.ctx.stroke(); }, row:function() { //棋盤行 for (var i = 100; i <= 800; i += 100) { this.ctx.beginPath(); this.ctx.moveTo(5, i); this.ctx.lineTo(800, i); this.ctx.stroke(); } }, cols:function() { // 棋盤列 for (var i = 100; i <= 700; i += 100) { this.ctx.beginPath(); this.ctx.moveTo(i, 5); this.ctx.lineTo(i, 900); this.ctx.stroke(); } }, xiexian:function() { //斜線 this.LineDrawing(300, 5, 500, 200); this.LineDrawing(300, 705, 500, 900); //反斜線 this.LineDrawing(500, 5, 300, 200); this.LineDrawing(500, 705, 300, 900); }, center:function(x,y) { //左上 this.LineDrawing(x-10,y-30,x-10,y-10); this.LineDrawing(x-10,y-10,x-30,y-10); //右上 this.LineDrawing(x+10,y-30,x+10,y-10); this.LineDrawing(x+10,y-10,x+30,y-10); //左下 this.LineDrawing(x-10,y+30,x-10,y+10); this.LineDrawing(x-10,y+10,x-30,y+10); //右下 this.LineDrawing(x+10,y+30,x+10,y+10); this. LineDrawing(x+10,y+10,x+30,y+10); }, drawFont:function() { //清除指定的矩形區域:x,y矩形的起點,width矩形的寬度,height矩形的高度 this.ctx.clearRect(5, 402, 795, 95); this.ctx.lineWidth = 1; // 繪制文字 this.ctx.font = "60px microsoft yahei"; this.ctx.save(); //保存點 //將坐標中心作為起啟點 this.ctx.translate(canvas1.width / 2, canvas1.height / 2); var radian = Math.PI / 2; // 弧度制 Math.PI=π this.ctx.rotate(radian); // 旋轉畫布繪制刻度 //填充 this.ctx.fillText("楚",-30,-270); this.ctx.fillText("河",-30,-150); this.ctx.restore(); //恢復到保存點 this.ctx.save(); //將坐標中心作為起啟點 this.ctx.translate(canvas1.width / 2, canvas1.height / 2); var radian = Math.PI / -2; this.ctx.rotate(radian); this.ctx.fillText("漢", -30, -270); this.ctx.fillText("界", -30, -150); this.ctx.restore(); }, init:function() { //棋盤外框 var canvas1 = document.getElementById("canvas1"); this.ctx = canvas1.getContext("2d"); this.ctx.lineWidth = 5; this.ctx.strokeStyle = "brown" // 以x,y為左上角,繪制寬度為width,高度為height的矩形。 this.ctx.strokeRect(3,3,800,900); this.row(); this.cols(); this.xiexian(); this.drawFont(); //中心點一(100,200) this.center(100, 200); //中心點二(700,200) this.center(700, 200); //中心點三(5,300) this.center(5, 300); //中心點四(200,300) this.center(200, 300); //中心點五(400,300) this.center(400, 300); //中心點六(600,300) this.center(600, 300); //中心點七(800,300) this.center(800, 300); //中心點八(800,600) this.center(800, 600); //中心點九(600,600) this.center(600, 600); //中心點十(400,600) this.center(400, 600); //中心點十一(200,600) this.center(200, 600); //中心點十二(5,600) this.center(5, 600); //中心點十三(700,700) this.center(700, 700); //中心點十四(100,700) this.center(100, 700); } } object.init(); </script> </body> </html>
將子畫上。

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas繪圖_象棋棋盤</title> </head> <body> <canvas id="canvas1" width="805" height="905">不支持Canvas</canvas> <img src="../img/blue-ju.gif" id="ju" hidden="hidden" /> <img src="../img/blue-ma.gif" id="ma" hidden="hidden" /> <img src="../img/blue-xiang.gif" id="xiang" hidden="hidden" /> <img src="../img/blue-shi.gif" id="shi" hidden="hidden" /> <img src="../img/blue-jiang.gif" id="jiang" hidden="hidden" /> <img src="../img/blue-pao.gif" id="pao" hidden="hidden" /> <img src="../img/blue-bing.gif" id="bing" hidden="hidden" /> <img src="../img/red-ju.gif" id="r_ju" hidden="hidden" /> <img src="../img/red-ma.gif" id="r_ma" hidden="hidden" /> <img src="../img/red-xiang.gif" id="r_xiang" hidden="hidden" /> <img src="../img/red-shi.gif" id="r_shi" hidden="hidden" /> <img src="../img/red-jiang.gif" id="r_jiang" hidden="hidden" /> <img src="../img/red-pao.gif" id="r_pao" hidden="hidden" /> <img src="../img/red-bing.gif" id="r_bing" hidden="hidden" /> <script type="text/javascript"> var object = { LineDrawing:function(mx,my,lx,ly) { //此方法用來畫棋盤線 this.ctx.beginPath(); this.ctx.moveTo(mx, my); this.ctx.lineTo(lx, ly); this.ctx.stroke(); }, row:function() { //棋盤行 for (var i = 100; i <= 800; i += 100) { this.ctx.beginPath(); this.ctx.moveTo(5, i); this.ctx.lineTo(800, i); this.ctx.stroke(); } }, cols:function() { // 棋盤列 for (var i = 100; i <= 700; i += 100) { this.ctx.beginPath(); this.ctx.moveTo(i, 5); this.ctx.lineTo(i, 900); this.ctx.stroke(); } }, xiexian:function() { //斜線 this.LineDrawing(300, 5, 500, 200); this.LineDrawing(300, 705, 500, 900); //反斜線 this.LineDrawing(500, 5, 300, 200); this.LineDrawing(500, 705, 300, 900); }, //注意:現在的原點中心為(100,100),所以下面的所有坐標在原來的基礎上加(x+100,y+100); center:function(x,y) { x += 100; y += 100; //左上 this.LineDrawing(x-10,y-30,x-10,y-10); this.LineDrawing(x-10,y-10,x-30,y-10); //右上 this.LineDrawing(x+10,y-30,x+10,y-10); this.LineDrawing(x+10,y-10,x+30,y-10); //左下 this.LineDrawing(x-10,y+30,x-10,y+10); this.LineDrawing(x-10,y+10,x-30,y+10); //右下 this.LineDrawing(x+10,y+30,x+10,y+10); this. LineDrawing(x+10,y+10,x+30,y+10); }, drawFont:function() { //清除指定的矩形區域:x,y矩形的起點,width矩形的寬度,height矩形的高度 this.ctx.clearRect(5, 402, 795, 95); this.ctx.lineWidth = 1; // 繪制文字 this.ctx.font = "60px microsoft yahei"; this.ctx.save(); //保存點 //將坐標中心作為起啟點 this.ctx.translate(canvas1.width / 2, canvas1.height / 2); var radian = Math.PI / 2; // 弧度制 Math.PI=π this.ctx.rotate(radian); // 旋轉畫布繪制刻度 //填充 this.ctx.fillText("楚",-30,-270); this.ctx.fillText("河",-30,-150); this.ctx.restore(); //恢復到保存點 this.ctx.save(); //將坐標中心作為起啟點 this.ctx.translate(canvas1.width / 2, canvas1.height / 2); var radian = Math.PI / -2; this.ctx.rotate(radian); this.ctx.fillText("漢", -30, -270); this.ctx.fillText("界", -30, -150); this.ctx.restore(); }, init:function() { //棋盤外框 var canvas1 = document.getElementById("canvas1"); this.ctx = canvas1.getContext("2d"); this.ctx.lineWidth = 5; this.ctx.strokeStyle = "brown" // 以x,y為左上角,繪制寬度為width,高度為height的矩形。 this.ctx.strokeRect(3,3,800,900); this.row(); this.cols(); this.xiexian(); this.drawFont(); //中心點一(100,200) this.center(100, 200); //中心點二(700,200) this.center(700, 200); //中心點三(5,300) this.center(5, 300); //中心點四(200,300) this.center(200, 300); //中心點五(400,300) this.center(400, 300); //中心點六(600,300) this.center(600, 300); //中心點七(800,300) this.center(800, 300); //中心點八(800,600) this.center(800, 600); //中心點九(600,600) this.center(600, 600); //中心點十(400,600) this.center(400, 600); //中心點十一(200,600) this.center(200, 600); //中心點十二(5,600) this.center(5, 600); //中心點十三(700,700) this.center(700, 700); //中心點十四(100,700) this.center(100, 700); //必須當頁面中的圖片資源加載成功,再畫棋子 window.onload=function() { //棋子圖片 var ju = document.getElementById("ju"); var ma = document.getElementById("ma"); var xiang = document.getElementById("xiang"); var shi = document.getElementById("shi"); var jiang = document.getElementById("jiang"); var bing = document.getElementById("bing"); var pao = document.getElementById("pao"); var r_ju = document.getElementById("r_ju"); var r_ma = document.getElementById("r_ma"); var r_xiang = document.getElementById("r_xiang"); var r_shi = document.getElementById("r_shi"); var r_jiang = document.getElementById("r_jiang"); var r_bing = document.getElementById("r_bing"); var r_pao = document.getElementById("r_pao"); //將棋子圖像繪制到畫布上 object.ctx.drawImage(ju, 50, 50, 100, 100); object.ctx.drawImage(ma, 150, 50, 100, 100); object.ctx.drawImage(xiang, 250, 50, 100, 100); object.ctx.drawImage(shi, 350, 50, 100, 100); object.ctx.drawImage(jiang, 450, 50, 100, 100); object.ctx.drawImage(shi, 550, 50, 100, 100); object.ctx.drawImage(xiang, 650, 50, 100, 100); object.ctx.drawImage(ma, 750, 50, 100, 100); object.ctx.drawImage(ju, 850, 50, 100, 100); object.ctx.drawImage(pao, 150, 250, 100, 100); object.ctx.drawImage(pao, 750, 250, 100, 100); object.ctx.drawImage(bing, 50, 350, 100, 100); object.ctx.drawImage(bing, 250, 350, 100, 100); object.ctx.drawImage(bing, 450, 350, 100, 100); object.ctx.drawImage(bing, 650, 350, 100, 100); object.ctx.drawImage(bing, 850, 350, 100, 100); object.ctx.drawImage(r_ju, 50, 950, 100, 100); object.ctx.drawImage(r_ma, 150, 950, 100, 100); object.ctx.drawImage(r_xiang, 250, 950, 100, 100); object.ctx.drawImage(r_shi, 350, 950, 100, 100); object.ctx.drawImage(r_jiang, 450, 950, 100, 100); object.ctx.drawImage(r_shi, 550, 950, 100, 100); object.ctx.drawImage(r_xiang, 650, 950, 100, 100); object.ctx.drawImage(r_ma, 750, 950, 100, 100); object.ctx.drawImage(r_ju, 850, 950, 100, 100); object.ctx.drawImage(r_pao, 150, 750, 100, 100); object.ctx.drawImage(r_pao, 750, 750, 100, 100); object.ctx.drawImage(r_bing, 50, 650, 100, 100); object.ctx.drawImage(r_bing, 250, 650, 100, 100); object.ctx.drawImage(r_bing, 450, 650, 100, 100); object.ctx.drawImage(r_bing, 650, 650, 100, 100); object.ctx.drawImage(r_bing, 850, 650, 100, 100); } } } object.init(); </script> </body> </html>
1.3、繪制矩形
context.strokeRect(x,y,width,height)
以x,y為左上角,繪制寬度為width,高度為height的矩形。
context.fillRect(x,y,width,height)
以x,y為左上角,填充寬度為width,高度為height的矩形。
context.clearRect(x,y,width,height)
清除以x,y為左上角,寬度為width,高度為height的矩形區域。
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>繪制矩形</title> </head> <body> <canvas id="canvas1" width="600" height="600"></canvas> <script type="text/javascript"> //獲得畫布元素 var canvas1 = document.getElementById("canvas1"); //獲得2維繪圖的上下文 var ctx = canvas1.getContext("2d"); //設置線寬 ctx.lineWidth = 10; //設置線的顏色 ctx.strokeStyle ="dodgerblue"; //畫一個空心的矩形, ctx.strokeRect(0,0,600,600); //畫一個實心矩形 ctx.fillStyle="aquamarine"; ctx.fillRect(200,200,200,200); //清除指定的矩形區域 ctx.clearRect(250,250,100,100); </script> </body> </html>
運行效果:
1.4、繪制圓弧
context.arc(x,y,radius,startAngle,endAngle,anticlockwise)
arc方法用來繪制一段圓弧路徑,以(x,y)圓心位置radius為半徑、startAngle為起始弧度、endAngle為終止弧度來,而在畫圓弧時的旋轉方向則由最后一個參數 anticlockwise 來指定,如果為 true 就是逆時針,false 則為順時針,Math.PI * 2 剛好為一周。
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>繪制圓弧</title> </head> <body> <canvas id="canvas1" width="600" height="600"></canvas> <script type="text/javascript"> //獲得畫布元素 var canvas1 = document.getElementById("canvas1"); //獲得2維繪圖的上下文 var ctx = canvas1.getContext("2d"); //設置線寬 ctx.lineWidth = 10; //設置線的顏色 ctx.strokeStyle ="dodgerblue"; //畫一段圓弧,300,300是圓心,200是半徑,0是超始角度,Math.PI是結束角度,是否逆時鍾 ctx.arc(300,300,200,0,Math.PI,false); //閉合 ctx.closePath(); ctx.stroke(); ctx.beginPath(); ctx.fillStyle="aquamarine"; ctx.arc(300,300,100,0,Math.PI*2,false); ctx.fill(); </script> </body> </html>
運行效果:
練習:
a、模擬鍾表的時,分,秒
1、首先時鍾嘛,肯定要獲取本地客戶端的時間;
2、時鍾有 3 個指針,我們可以通過添加動畫的方式讓它們圍繞中心點轉動;
3、通過獲取到的 hour、minute 和 second 值分別計算 時針、分針和秒針的角度值;
b、模擬水波,一個黑色的屏幕,多個從中心隨機產生彩色的圈不斷的放大,接觸到屏幕結束。
1.5、繪制圖像
context.drawImage(image,x,y)
把image圖像繪制到畫布上x,y坐標位置。
context.drawImage(image,x,y,w,h)
把image圖像繪制到畫布上x,y坐標位置,圖像的寬度是w,高度是h。
context.drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)
截取image圖像以sx,sy為左上角坐標,寬度為sw,高度為sh的一塊矩形區域繪制到畫布上以dx,dy坐標位置,圖像寬度是dw,高度是dh。
其中image可以是htmlImageElement元素,htmlcanvasElement元素,htmlVideoElement元素
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>繪制圖像</title> </head> <body> <canvas id="canvas1" width="600" height="600"></canvas> <img src="img/apple.png" id="apple" hidden="hidden" /> <script type="text/javascript"> //必須當頁面中的圖片資源加載成功 window.onload = function() { //獲得畫布元素 var canvas1 = document.getElementById("canvas1"); //獲得2維繪圖的上下文 var ctx = canvas1.getContext("2d"); //設置線寬 ctx.lineWidth = 10; //設置線的顏色 ctx.strokeStyle = "dodgerblue"; ctx.moveTo(0,0); ctx.strokeRect(0,0,600,600); //圖片 var apple = document.getElementById("apple"); //將圖像繪制到畫布的,圖片的左上角 ctx.drawImage(apple, 300-52, 300-63); } </script> </body> </html>
運行效果:
1.6、繪制文字
context.fillText(text,x,y,[maxWidth])
在canvas上填充文字,text表示需要繪制的文字,x,y分別表示繪制在canvas上的橫,縱坐標,最后一個參數可選,表示顯示文字的最大寬度,防止文字顯示溢出。
context.strokeText(text,x,y,[maxWidth])
在canvas上描邊文字,參數的意義同fillText
使用context.font屬性設置字體
context.font='italic bolder 48px 黑體';
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>繪制文字</title> </head> <body> <canvas id="canvas1" width="600" height="600"></canvas> <img src="img/apple.png" id="apple" hidden="hidden" /> <script type="text/javascript"> //必須當頁面中的圖片資源加載成功 window.onload = function() { //獲得畫布元素 var canvas1 = document.getElementById("canvas1"); //獲得2維繪圖的上下文 var ctx = canvas1.getContext("2d"); //設置線寬 ctx.lineWidth = 1; //設置線的顏色 ctx.strokeStyle = "dodgerblue"; ctx.moveTo(0,0); ctx.strokeRect(0,0,600,600); //繪制文字 //描邊 ctx.font="50px microsoft yahei"; ctx.strokeText("Hello Zhangguo",20,100); //填充 ctx.fillStyle= ctx.fillText("Hello Zhangguo",20,200); } </script> </body> </html>
運行結果:
1.7、隨機顏色與簡單動畫
主要結合隨機方法與定時器、時鍾實現簡單的動畫。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>隨機顏色與簡單動畫</title> </head> <body> <canvas id="canvas1" width="1000" height="650"></canvas> <img src="img/apple.png" id="apple" hidden="hidden" /> <script type="text/javascript"> var magicCircle = { randomColor: function() { return "#" + parseInt(Math.random() * 16777216).toString(16); }, getNum: function(min, max) { return parseInt(Math.random() * (max - min)) + min; }, r: 10, run: function() { //獲得畫布元素 this.canvas1 = document.getElementById("canvas1"); //獲得2維繪圖的上下文 this.ctx = this.canvas1.getContext("2d"); //運行 setInterval(this.draw, 100); this.bindEvent(); }, draw: function() { magicCircle.ctx.beginPath(); magicCircle.ctx.lineWidth = magicCircle.getNum(1,10); magicCircle.ctx.strokeStyle = magicCircle.randomColor(); magicCircle.ctx.arc(magicCircle.getNum(1,1000), magicCircle.getNum(1,600), magicCircle.r, 0, Math.PI * 2); magicCircle.ctx.stroke(); magicCircle.r += 10; if(magicCircle.r > 300) magicCircle.r = 10; }, bindEvent:function() { this.canvas1.onmousemove=function(e){ magicCircle.ctx.lineWidth = magicCircle.getNum(1,10); magicCircle.ctx.strokeStyle = magicCircle.randomColor(); magicCircle.ctx.arc(e.clientX, e.clientY, magicCircle.r, 0, Math.PI * 2); magicCircle.ctx.stroke(); magicCircle.r += 10; if(magicCircle.r > 300) magicCircle.r = 10; } } }; magicCircle.run(); </script> </body> </html>
運行效果:
二、WebGL
WebGL(全寫Web Graphics Library)是一種3D繪圖標准,這種繪圖技術標准允許把JavaScript和OpenGL ES 2.0結合在一起,通過增加OpenGL ES 2.0的一個JavaScript綁定,WebGL可以為HTML5 Canvas提供硬件3D加速渲染,這樣Web開發人員就可以借助系統顯卡來在瀏覽器里更流暢地展示3D場景和模型了,還能創建復雜的導航和數據視覺化。顯然,WebGL技術標准免去了開發網頁專用渲染插件的麻煩,可被用於創建具有復雜3D結構的網站頁面,甚至可以用來設計3D網頁游戲等等。
WebGL完美地解決了現有的Web交互式三維動畫的兩個問題:
第一,它通過HTML腳本本身實現Web交互式三維動畫的制作,無需任何瀏覽器插件支持;
第二,它利用底層的圖形硬件加速功能進行的圖形渲染,是通過統一的、標准的、跨平台的OpenGL接口實現的。
通俗說WebGL中canvas繪圖中的3D版本。因為原生的WebGL很復雜,我們經常會使用一些三方的庫,如three.js等,這些庫多數用於HTML5游戲開發。
Three.js的示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Three.js</title> </head> <body> <script src="js/three.min.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); var geometry = new THREE.CubeGeometry(1, 1, 1); var material = new THREE.MeshBasicMaterial({ color: 0x0000ff }); var cube = new THREE.Mesh(geometry, material); scene.add(cube); camera.position.z = 5; function render() { requestAnimationFrame(render); cube.rotation.x += 0.1; cube.rotation.y += 0.1; renderer.render(scene, camera); } render(); </script> </body> </html>
three.js示例運行結果:
2.1、HTML5游戲開發
隨着HTML5的發展與硬件性能的提升HTML5游戲開發越來越受到游戲開發者的重視,因為WebGL存在一定的復雜度,所有產生了許多優秀的開源HTML5游戲引擎,下面是github上開源免費的HTML5游戲引擎:
Name | Updated Time | Watch | Star | Fork | Commits | Contributors |
---|---|---|---|---|---|---|
Three.js | 2016/3/28 | 1590 | 24041 | 7768 | 14825 | 588 |
Phaser | 2016/2/18 | 837 | 11782 | 4095 | 4423 | 206 |
Pixi.js | 2016/3/17 | 656 | 10063 | 1942 | 2860 | 161 |
egret | 2016/3/30 | 215 | 1275 | 303 | 4268 | 25 |
enchantjs | 2016/1/4 | 185 | 1445 | 301 | 1683 | 27 |
crafty | 2016/3/21 | 134 | 2050 | 473 | 1807 | 106 |
turbulenz | 2015/11/23 | 271 | 2544 | 406 | 1737 | 13 |
cocos2d-js | 2016/3/30 | 162 | 1207 | 469 | 4559 | 45 |
playcanvas | 2016/3/30 | 164 | 1784 | 368 | 5142 | 16 |
melonjs | 2016/3/30 | 13 | 1579 | 371 | 3907 | 40 |
quintus | 2016/2/3 | 136 | 1023 | 412 | 256 | 33 |
Hilo | 2016/2/3 | 173 | 2449 | 340 | 20 | 2 |
2.2.1、Cocos2D-HTML5
開源,免費的HTML5 2D游戲開發框架,Cocos2D擁有幾個主要版本,包括Cocos2D-iPhone、Cocos2D-X,以及被社區普遍看好的Cocos2D-HTML5和JavaScriptbindings for Cocos2D-X。CocoStudio工具集是開源游戲引擎。特點:與Cocos2d的API類似,容易上手、中文文檔齊全,資料豐富、基於MIT協議的開源引擎。它由國內Cocos2d-x核心團隊主導開發和維護,行業領袖、HTML5大力推動者Google為這個項目提供支持。
github:https://github.com/cocos2d/cocos2d-html5
HelloWorld示例:
<!DOCTYPE html> <html> <head> <title>Hello Cocos2d-JS</title> </head> <body> <canvas id="gameCanvas" width="800" height="450"></canvas> <script type="text/javascript" src="cocos2d-js-v3.12-lite.js" charset="UTF-8"></script> <script type="text/javascript"> window.onload = function(){ cc.game.onStart = function(){ //load resources cc.LoaderScene.preload(["HelloWorld.png"], function () { var MyScene = cc.Scene.extend({ onEnter:function () { this._super(); var size = cc.director.getWinSize(); var sprite = cc.Sprite.create("HelloWorld.png"); sprite.setPosition(size.width / 2, size.height / 2); sprite.setScale(0.8); this.addChild(sprite, 0); var label = cc.LabelTTF.create("Hello World", "Arial", 40); label.setPosition(size.width / 2, size.height / 2); this.addChild(label, 1); } }); cc.director.runScene(new MyScene()); }, this); }; cc.game.run("gameCanvas"); }; </script> </body> </html>
運行結果:
2.2.2、Egret(白鷺引擎)
是一個基於TypeScript語言開發的HTML5游戲引擎,圍住神經貓就是用這個框架開發的。
特點:
a)、基於TypeScript及JavaScript技術,支持Flash到Egret高效轉換,引擎、工具、運行時完整工作流
b)、跨平台:HTML5,iOS,Android,Windows Phone
c)、全中文文檔:文檔與開發者社區齊全
d)、開源免費,BSD開源協議、任意定制及擴展
三、SVG
SVG可縮放矢量圖形(Scalable Vector Graphics)是基於可擴展標記語言(XML),用於描述二維矢量圖形的一種圖形格式。SVG是W3C("World Wide Web ConSortium" 即 " 國際互聯網標准組織")在2000年8月制定的一種新的二維矢量圖形格式,也是規范中的網絡矢量圖形標准。SVG嚴格遵從XML語法,並用文本格式的描述性語言來描述圖像內容,因此是一種和圖像分辨率無關的矢量圖形格式。SVG 於 2003 年 1 月 14 日成為 W3C 推薦標准。
特點:
1.任意放縮
用戶可以任意縮放圖像顯示,而不會破壞圖像的清晰度、細節等。
2.文本獨立
SVG圖像中的文字獨立於圖像,文字保留可編輯和可搜尋的狀態。也不會再有字體的限制,用戶系統即使沒有安裝某一字體,也會看到和他們制作時完全相同的畫面。
3.較小文件
總體來講,SVG文件比那些GIF和JPEG格式的文件要小很多,因而下載也很快。
4.超強顯示效果
SVG圖像在屏幕上總是邊緣清晰,它的清晰度適合任何屏幕分辨率和打印分辨率。
5.超級顏色控制
SVG圖像提供一個1600萬種顏色的調色板,支持ICC顏色描述文件標准、RGB、線X填充、漸變和蒙版。
6.交互X和智能化。SVG面臨的主要問題一個是如何和已經占有重要市場份額的矢量圖形格式Flash競爭的問題,另一個問題就是SVG的本地運行環境下的廠家支持程度。
瀏覽器支持:
Internet Explorer9,火狐,谷歌Chrome,Opera和Safari都支持SVG。
IE8和早期版本都需要一個插件 - 如Adobe SVG瀏覽器,這是免費提供的。
3.1、SVG Hello Wrold
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>SVG Hello World</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <circle cx="100" cy="100" r="30" stroke="blue" stroke-width="2" fill="red" /> </svg> </body> </html>
運行結果:
svg是一個新增加標簽,xmlns是命名空間,version是svg的版本,circle標簽就是對svg要展示的圖像進行描述,cx與cy表示位置,r表示半徑,stroke是描邊樣式,stroke-width就線寬,fill是填充樣式。瀏覽器兼容性很好:
3.2、多種引入SVG的方法
SVG 文件可通過以下標簽嵌入 HTML 文檔:<embed>、<object> 或者 <iframe>。
SVG的代碼可以直接嵌入到HTML頁面中,或您可以直接鏈接到SVG文件
引入方式如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>引入SVG的方法</title> <style type="text/css"> body{ background:url(me.svg); } </style> </head> <body> <h2>embed</h2> <embed src="me.svg" type="image/svg+xml" width="108" height="108" /> 優勢:所有主要瀏覽器都支持,並允許使用腳本 缺點:不推薦在HTML4和XHTML中使用(但在HTML5允許) <h2>object</h2> <object data="me.svg" type="image/svg+xml" width="108" height="108"></object> 優勢:所有主要瀏覽器都支持,並支持HTML4,XHTML和HTML5標准 缺點:不允許使用腳本。 <h2>iframe</h2> <iframe src="me.svg" frameborder="0" width="108" height="108"></iframe> 優勢:所有主要瀏覽器都支持,並允許使用腳本 缺點:不推薦在HTML4和XHTML中使用(但在HTML5允許) <h2>直接嵌入</h2> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="108" height="108"> <circle cx="54" cy="54" r="50" stroke="blue" stroke-width="2" fill="blue" /> </svg> 在Firefox、Internet Explorer9、谷歌Chrome和Safari中,你可以直接在HTML嵌入SVG代碼。 注意:SVG不能直接嵌入到Opera。 <h2>image</h2> <img src="me.svg" width="108" height="108" /> </body> </html>
運行結果:
3.3、畫直線
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Line</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500"> <line x1="0" y1="0" x2="500" y2="500" style="stroke:rgb(0,0,255);stroke-width:3" /> </svg> </body> </html>
參數:
x1 屬性在 x 軸定義線條的開始
y1 屬性在 y 軸定義線條的開始
x2 屬性在 x 軸定義線條的結束
y2 屬性在 y 軸定義線條的結束
運行結果:
3.4、畫橢圓
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>橢圓</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" hidden="500"> <ellipse cx="300" cy="80" rx="100" ry="50" style="fill:yellow;stroke:dodgerblue;stroke-width:5" /> </svg> </body> </html>
參數:
CX屬性定義的橢圓中心的x坐標
CY屬性定義的橢圓中心的y坐標
RX屬性定義的水平半徑
RY屬性定義的垂直半徑
運行結果:
3.5、文本與矩形
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>文本與矩形</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="800" height="500"> <text x="0" y="50" fill="blue" style="font-size:30px; font-family: 'microsoft yahei';">My Teacher Zhangguo</text> <rect x="40" y="60" width="260" height="260" style="fill:blue;stroke:pink;stroke-width:5; fill-opacity:0.1;stroke-opacity:0.9" /> </svg> </body> </html>
運行結果:
3.6、向下兼容與圖標
IE8並不直接兼容SVG,如果需要顯示則可以使用插件,如果不使用插件也有向下兼容的辦法。
示例代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>向下兼容與圖標</title> </head> <body> <svg width="78" height="78"> <image xlink:href="money.svg" width="78" height="78" src="money.png"></image> </svg> </body> </html>
運行結果:
參數:
image本身就是svg中引入外部圖像的元素,剛好在ie8下又能被解析。