canvas学习笔记(下篇) -- canvas入门教程--保存状态/变形/旋转/缩放/矩阵变换/综合案例(星空/时钟/小球)...
【下篇】 --?建議學習時間4小時 ?課程共(上中下)三篇
此筆記是我初次接觸canvas的時候的學習筆記,這次特意整理為博客供大家入門學習,幾乎涵蓋了canvas所有的基礎知識,并且有眾多練習案例,建議大家學習10~15個小時,里面的案例請挨個敲一遍,這樣才能轉化為自己的知識。
技術要求:有html/css/js基礎。
?
保存狀態
?
save()restore()
save 和 restore 方法是用來保存和恢復 canvas 狀態的,都沒有參數。Canvas 的狀態就是當前畫面應用的所有樣式和變形的一個快照。
簡單示例:
var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");//線條鏈接處樣式ctx.fillStyle = "darkblue";ctx.lineWidth = 1;ctx.fillRect(0,0,150,150);ctx.save(); //第一次保存 保存了 fillStyle "darkblue" ctx.fillStyle = "#09f";ctx.fillRect(15,15,120,120);ctx.save(); //第二次保存 保存了 fillStyle "#09f"ctx.fillStyle = "#fff";ctx.fillRect(30,30,90,90);ctx.restore(); //恢復到第二次保存的狀態ctx.fillRect(45,45,60,60);ctx.restore(); //恢復到第一次保存的狀態ctx.fillRect(60,60,30,30);結果如下圖:后兩次 restore之后依次恢復到前面 save的顏色狀態
?
畫布變形
?
偏移
ctx.translate(disX,disY)? ,將繪圖上下文向x和y方向移動一個距離,然后再作畫 (真實的畫布并沒有移動)
示例:
var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");/* 移動位置 */ctx.fillRect(0,0,50,50);ctx.translate(100,100); //將畫布x,y方向分別移動 100px ctx.fillStyle = "#09f";ctx.fillRect(0,0,50,50);這里我們可以看到,雖然繪制都是使用 fillRect(0,0,5.,50),但第二次繪制的時候上下文已經偏移了 100像素,所以落到畫布上的時候就偏移了100像素
?
旋轉?
rotate(angle)
這個方法只接受一個參數:旋轉的角度(angle),它是順時針方向的,以弧度為單位的值。
示例:
?
?
var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");ctx.translate(100,100);for(var i=1; i<6; i++){ctx.save();ctx.fillStyle = 'rgba('+ 51*i +','+ (255-51*i) +',255,1)';for(var j=0; j<i*6; j++){ctx.rotate(Math.PI*2/(i*6)); ctx.beginPath();ctx.arc(0,i*12.5,5,0,Math.PI*2,true);ctx.fill();}ctx.restore()}?
縮放
scale(x, y)
scale?方法接受兩個參數。x,y 分別是橫軸和縱軸的縮放因子,它們都必須是正值。值比 1.0 小表示縮小,比 1.0 大則表示放大,值為 1.0 時什么效果都沒有。
示例:
var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");ctx.translate(100,100);ctx.save();ctx.translate(200,80);drawSpirograph(ctx,22,30,30);ctx.restore();ctx.scale(0.75,1);drawSpirograph(ctx,22,6,5);function drawSpirograph(ctx,R,r,O){var x1 = R-O;var y1 = 0;var i = 1;ctx.beginPath();ctx.moveTo(x1,y1);do {if (i>20000) break;var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72))var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72)) ctx.lineTo(x2,y2);x1 = x2;y1 = y2;i++;} while (x2 != R-O && y2 != 0 );ctx.stroke();}?
?矩陣變換
transform(m11, m12, m21, m22, dx, dy)
這個方法是將當前的變形矩陣乘上一個基于自身參數的矩陣,在這里我們用下面的矩陣:
m11? m21? dx
m12? m22? dy
0? ? ? ?0? ? ? ?1
這個函數的參數各自代表如下:
m11:水平方向的縮放
m12:水平方向的偏移
m21:豎直方向的偏移
m22:豎直方向的縮放
dx:水平方向的移動
dy:豎直方向的移動
?
示例:
var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");ctx.translate(100,100);var sin = Math.sin(Math.PI/6);var cos = Math.cos(Math.PI/6);var c = 0;for(var i=0; i<=12; i++){c = Math.floor(255/12*i);ctx.fillStyle = "rgb("+c+","+c+","+c+")";ctx.fillRect(0,0,100,10);ctx.transform(cos,sin,-sin,cos,0,0);}ctx.setTransform(1,0,0,1,100,100);ctx.fillStyle = "rgba(255,128,255,0.5)";ctx.fillRect(0,0,100,50);?
綜合案例
?
案例1:星空
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title><style>*{margin: 0;padding: 0}canvas{border: 1px solid #a4e2f9;margin: 10px;}</style> </head> <body><canvas height="300" width="600" id="myCanvas"></canvas><script>var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");//線條鏈接處樣式 ctx.strokeStyle = "#09f";ctx.lineWidth = 1;ctx.fillRect(0,0,450,450);ctx.translate(150,150);ctx.beginPath();ctx.arc(0,0,140,0,Math.PI*2,true);ctx.clip(); //這個表示裁剪,只有路徑區域中的部分才可見。var lingrad = ctx.createLinearGradient(0,-175,0,250);lingrad.addColorStop(0,"#232256");lingrad.addColorStop(1,"#143778");//繪制漸變背景 ctx.fillStyle = lingrad;ctx.fillRect(-175,-175,350,350);//繪制星星for(var j=1; j<100; j++){ctx.save();ctx.fillStyle = "#fff";ctx.translate(140-Math.floor(Math.random()*280),140-Math.floor(Math.random()*280));drawStar(ctx, Math.floor(Math.random()*8)+2);ctx.restore();}//繪制星星的方法function drawStar(ctx,r){ctx.save();ctx.beginPath();ctx.moveTo(r,0);for(var i=0; i<9; i++){ctx.rotate(Math.PI/5);if(i%2 == 0){ctx.lineTo((r/0.525731)*0.200811,0); }else{ctx.lineTo(r,0);}}ctx.closePath();ctx.fill();ctx.restore();}</script> </body> </html>?
?案例2:時鐘
?
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title><style>*{margin: 0;padding: 0}canvas{border: 1px solid #a4e2f9;margin: 30px auto;display: block}</style> </head> <body><canvas height="300" width="600" id="myCanvas"></canvas><script>function clock(){var now = new Date();var ctx = document.getElementById('myCanvas').getContext('2d');ctx.save();ctx.clearRect(0,0,150,150);ctx.translate(75,75);ctx.scale(0.4,0.4);ctx.rotate(-Math.PI/2); ctx.strokeStyle = "black";ctx.fillStyle = "white";ctx. lineWidth = 8;ctx.lineCap = "round";//時 ctx.save();for(var i=0; i<12; i++){ctx.beginPath();ctx.rotate(Math.PI/6); ctx.moveTo(100,0);ctx.lineTo(120,0);ctx.stroke();}ctx.restore();//分 ctx.save();ctx.lineWidth = 5;for(var i=0; i<60; i++){if(i%5 != 0){ctx.beginPath();ctx.moveTo(117,0);ctx.lineTo(120,0);ctx.stroke();}ctx.rotate(Math.PI/30); }ctx.restore();var sec = now.getSeconds();var min = now.getMinutes();var hr = now.getHours();hr = hr >= 12 ? hr-12 : hr;ctx.fillStyle = "black";//時針 ctx.save();ctx.rotate( hr*(Math.PI/6)+(Math.PI/360)*min+(Math.PI/21600)*sec ); ctx.lineWidth = 14;ctx.beginPath();ctx.moveTo(-20,0);ctx.lineTo(80,0);ctx.stroke();ctx.restore();//分針 ctx.save();ctx.rotate( (Math.PI/30)*min+(Math.PI/1800)*sec );ctx.lineWidth = 10;ctx.beginPath();ctx.moveTo(-20,0);ctx.lineTo(112,0);ctx.stroke();ctx.restore();//秒針 ctx.save();ctx.rotate( (Math.PI/30)*sec ); ctx.strokeStyle = "#D40000";ctx.fillStyle = "#D40000";ctx.lineWidth = 6;ctx.beginPath();ctx.moveTo(-30,0);ctx.lineTo(83,0);ctx.stroke();ctx.beginPath();ctx.arc(0,0,10,0,Math.PI*2,true);ctx.fill();ctx.beginPath();ctx.arc(95,0,10,0,Math.PI*2,true);ctx.stroke();ctx.restore();//外圈 ctx.beginPath();ctx.lineWidth = 14;ctx.strokeStyle = '#325FA2';ctx.arc(0,0,142,0,Math.PI*2,true);ctx.stroke();ctx. restore();window.requestAnimationFrame(clock);}window.requestAnimationFrame(clock);</script> </body> </html>?
?
?案例3:運動的小球
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title><style>*{margin: 0;padding: 0}canvas{border: 1px solid #a4e2f9;}</style> </head> <body><canvas height="300" width="600" id="myCanvas"></canvas><script>var canvas = document.getElementById('myCanvas');var ctx = canvas.getContext('2d');var raf;//小球對象var ball = {x: 100,y: 100,vx: 5,vy: 1,radius: 25,color: '#1895c3',draw: function() {ctx.beginPath();ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2, true);ctx.closePath();ctx.fillStyle = this.color;ctx.fill();}};//清除畫布function clear() {ctx.fillStyle = 'rgba(255,255,255,0.3)';ctx.fillRect(0,0,canvas.width,canvas.height);}//小球運動及繪制的方法function draw() {clear();ball.x += ball.vx;ball.y += ball.vy;if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {ball.vy = -ball.vy;}if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {ball.vx = -ball.vx;}ball.draw();raf = window.requestAnimationFrame(draw);}//鼠標移動的時候 讓小球跟著鼠標走 canvas.addEventListener('mousemove', function(e){clear();ball.x = e.clientX;ball.y = e.clientY;ball.draw();});//鼠標移入停止動畫 canvas.addEventListener("mouseenter",function(e){window.cancelAnimationFrame(raf);});//鼠標移出繼續動畫 canvas.addEventListener("mouseout",function(e){raf = window.requestAnimationFrame(draw);});//開始第一幀動畫 draw();</script> </body> </html>?
?
?
?
?
今天就講到這里,canvas基礎部分就結束了,后續會找時間更新一些canvas比較炫酷的綜合案例,請期待。
?
?
關注公眾號,博客更新即可收到推送
?
轉載于:https://www.cnblogs.com/chengduxiaoc/p/7651340.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的canvas学习笔记(下篇) -- canvas入门教程--保存状态/变形/旋转/缩放/矩阵变换/综合案例(星空/时钟/小球)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: web访问 FastDFS 方法思路
- 下一篇: 解决git提交时报“there are