日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

canvas学习笔记(下篇) -- canvas入门教程--保存状态/变形/旋转/缩放/矩阵变换/综合案例(星空/时钟/小球)...

發布時間:2025/6/17 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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入门教程--保存状态/变形/旋转/缩放/矩阵变换/综合案例(星空/时钟/小球)...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。