requestAnimationFrame は、Web のループ操作をタイミングするために使用されるインターフェイスです。フレームごとにページが描かれています。
この API を設定する目的は、さまざまな Web ページのアニメーション効果 (DOM アニメーション、Canvas アニメーション、SVG アニメーション、WebGL アニメーション) に統一された更新メカニズムを持たせることにより、システム リソースを節約し、システム パフォーマンスを向上させ、視覚効果を向上させることです。 。コード内でこの API を使用すると、アニメーションを実行したいことをブラウザーに伝え、ブラウザーに次のアニメーション フレームで Web ページの再描画をスケジュールさせます。 requestAnimationFrame の利点は、表示の更新メカニズムを最大限に活用し、システム リソースを節約できることです。ディスプレイには固定のリフレッシュ周波数 (60 Hz または 75 Hz) があり、1 秒あたり最大 60 回または 75 回しか再描画できないことを意味します。requestAnimationFrame の基本的な考え方は、このリフレッシュ周波数との同期を維持し、このリフレッシュ周波数を使用することです。ページを再描画します。さらに、この API を使用すると、ページがブラウザの現在のタブに表示されなくなると、ページの更新が自動的に停止されます。これにより、CPU、GPU、電力が節約されます。 ただし、注意すべき点が 1 つあります。requestAnimationFrame はメインスレッドで完了するということです。これは、メインスレッドが非常にビジーな場合、requestAnimationFrame のアニメーション効果が大幅に低下することを意味します。 requestAnimationFrameはコールバック関数をパラメータとして受け取ります。このコールバック関数は、ブラウザが再描画する前に呼び出されます。
requestID = window.requestAnimationFrame(callback);
window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; })();
function repeatOften() { // Do whatever requestAnimationFrame(repeatOften); } requestAnimationFrame(repeatOften);
window.cancelAnimationFrame(requestID);
integer 値です。
(2) キャンバスを準備します ブラウザがキャンバスをサポートしているかどうかを確認し、幅と高さをブラウザのウィンドウサイズに設定します。var canvas = document.getElementById("myCanvas"); if (!canvas.getContext) { return; } canvas.width = window.innerWidth; canvas.height = window.innerHeight;var ctx = canvas.getContext("2d");
function FireWork() { this.x = -1; this.y = -1; this.balls = []; }
createBalls: function () { for (var i = 0; i < 300; i++) { var angle = Math.random() * Math.PI * 2, radius = getRandom(50, 200); this.balls.push(new Ball(fwx, fwy, fwx + Math.cos(angle) * radius, fwy + Math.sin(angle) * radius)); } }
init: function () { this.x = getRandom(200, width - 200); this.y = getRandom(200, height - 200); fwx = this.x; fwy = this.y; this.createBalls(); drawCount = 0; currBallIndex = 0; }
index です。
FireWork全体は以下のように定義されています。function FireWork() { this.x = -1; this.y = -1; this.balls = []; } FireWork.prototype = { init: function () { this.x = getRandom(200, width - 200); this.y = getRandom(200, height - 200); fwx = this.x; fwy = this.y; this.createBalls(); drawCount = 0; currBallIndex = 0; }, run: function () { this.init(); }, createBalls: function () { for (var i = 0; i < 300; i++) { var angle = Math.random() * Math.PI * 2, radius = getRandom(50, 200); this.balls.push(new Ball(fwx, fwy, fwx + Math.cos(angle) * radius, fwy + Math.sin(angle) * radius)); } } }
function Ball(bx, by, ex, ey) { this.bx = bx;//起点X轴坐标 this.by = by;//起点Y轴坐标 this.ex = ex;//终点X轴坐标 this.ey = ey;//终点Y轴坐标}
Ball.prototype = { getSpan: function () { var xSpan = (this.ex - this.bx) / allDrawCount, ySpan = (this.ey - this.by) / allDrawCount; return { x: xSpan, y: ySpan }; }, currPosition: function () { var span = this.getSpan(), currX = -1, currY = -1; if (drawCount < allDrawCount) { currX = this.bx + span.x * (drawCount - 1); currY = this.by + span.y * (drawCount - 1); return { x: currX, y: currY }; } return null; }, nextPosition: function () { var span = this.getSpan(), currX = -1, currY = -1; if (drawCount < allDrawCount) { currX = this.bx + span.x * drawCount; currY = this.by + span.y * drawCount; return { x: currX, y: currY }; } return null; } }
var fwx = -1, //烟花位置X轴坐标 fwy = -1, //烟花位置Y轴坐标 currFW = null, //烟花实例 currBallIndex = -1, //当前正在绘制的小球索引 drawCount = 0, //绘制次数 allDrawCount = 40, //总共需要的绘制次数 width = canvas.width, //画布宽度 height = canvas.height; //画布高度
そして、いくつかのツールメソッドがあります。
function componentToHex(c) { var hex = c.toString(16); return hex.length == 1 ? "0" + hex : hex; }function rgbToHex(r, g, b) { return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); }function getRandom(minNum, maxNum) { var iChoices = maxNum - minNum + 1; return Math.floor(Math.random() * iChoices + minNum); }
最後に、requestAnimationFrame が呼び出す描画メソッドが 1 つ残っています。この描画方法は、現在の描画回数から爆発するボールの軌跡(始点と終点を含む線分)を取得し、最後に描画した軌跡を消去するというものです。
1つの花火のエフェクトを引いたら、次の花火を描きます。
function drawLine(span) { if (currFW && currBallIndex !== -1) { if (drawCount <= allDrawCount) { ctx.save(); drawCount++; for (var i = 0, j = currFW.balls.length; i < j; i++) { var currBall = currFW.balls[i], beginPoint = currBall.currPosition(), endPoint = currBall.nextPosition(); if (beginPoint && endPoint) { console.log(currBallIndex, drawCount, currBall, beginPoint, endPoint); ctx.beginPath(); ctx.moveTo(currBall.bx, currBall.by); ctx.lineTo(beginPoint.x, beginPoint.y); ctx.strokeStyle = "#000"; ctx.stroke(); ctx.beginPath(); ctx.moveTo(beginPoint.x, beginPoint.y); ctx.lineTo(endPoint.x, endPoint.y); var r = getRandom(0, 255); var g = getRandom(0, 255); var b = getRandom(0, 255); ctx.strokeStyle = rgbToHex(r, g, b); ctx.stroke(); } else { ctx.beginPath(); ctx.moveTo(currBall.bx, currBall.by); ctx.lineTo(currBall.ex, currBall.ey); ctx.strokeStyle = "#000"; ctx.stroke(); } } currBallIndex++; currBallIndex %= currFW.balls.length; ctx.restore(); } else { ctx.clearRect(0, 0, width, height); currFW = new FireWork(); currFW.run(); } } requestAnimationFrame(drawLine); }
currFW = new FireWork(); currFW.run(); requestAnimationFrame(drawLine);
1 (function () { 2 var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { 3 return window.setTimeout(callback, 1000 / 60); 4 }; 5 window.requestAnimationFrame = requestAnimationFrame; 6 })(); 7 8 var canvas = document.getElementById("myCanvas"); 9 if (!canvas.getContext) { 10 return; 11 } 12 canvas.width = window.innerWidth; 13 canvas.height = window.innerHeight; 14 15 var ctx = canvas.getContext("2d"); 16 17 var fwx = -1, 18 fwy = -1, 19 currFW = null, 20 currBallIndex = -1, 21 drawCount = 0, 22 allDrawCount = 40, 23 width = canvas.width, 24 height = canvas.height; 25 26 function componentToHex(c) { 27 var hex = c.toString(16); 28 return hex.length == 1 ? "0" + hex : hex; 29 } 30 31 function rgbToHex(r, g, b) { 32 return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); 33 } 34 35 function getRandom(minNum, maxNum) { 36 var iChoices = maxNum - minNum + 1; 37 return Math.floor(Math.random() * iChoices + minNum); 38 } 39 40 function drawLine(span) { 41 if (currFW && currBallIndex !== -1) { 42 if (drawCount <= allDrawCount) { 43 ctx.save(); 44 drawCount++; 45 for (var i = 0, j = currFW.balls.length; i < j; i++) { 46 var currBall = currFW.balls[i], 47 beginPoint = currBall.currPosition(), 48 endPoint = currBall.nextPosition(); 49 if (beginPoint && endPoint) { 50 console.log(currBallIndex, drawCount, currBall, beginPoint, endPoint); 51 ctx.beginPath(); 52 ctx.moveTo(currBall.bx, currBall.by); 53 ctx.lineTo(beginPoint.x, beginPoint.y); 54 ctx.strokeStyle = "#000"; 55 ctx.stroke(); 56 ctx.beginPath(); 57 ctx.moveTo(beginPoint.x, beginPoint.y); 58 ctx.lineTo(endPoint.x, endPoint.y); 59 var r = getRandom(0, 255); 60 var g = getRandom(0, 255); 61 var b = getRandom(0, 255); 62 ctx.strokeStyle = rgbToHex(r, g, b); 63 ctx.stroke(); 64 } else { 65 ctx.beginPath(); 66 ctx.moveTo(currBall.bx, currBall.by); 67 ctx.lineTo(currBall.ex, currBall.ey); 68 ctx.strokeStyle = "#000"; 69 ctx.stroke(); 70 } 71 } 72 currBallIndex++; 73 currBallIndex %= currFW.balls.length; 74 ctx.restore(); 75 } else { 76 ctx.clearRect(0, 0, width, height); 77 currFW = new FireWork(); 78 currFW.run(); 79 } 80 } 81 requestAnimationFrame(drawLine); 82 } 83 84 function FireWork() { 85 this.x = -1; 86 this.y = -1; 87 this.balls = []; 88 } 89 90 FireWork.prototype = { 91 init: function () { 92 this.x = getRandom(200, width - 200); 93 this.y = getRandom(200, height - 200); 94 fwx = this.x; 95 fwy = this.y; 96 this.createBalls(); 97 drawCount = 0; 98 currBallIndex = 0; 99 }, 100 run: function () { 101 this.init(); 102 }, 103 createBalls: function () { 104 for (var i = 0; i < 300; i++) { 105 var angle = Math.random() * Math.PI * 2, 106 radius = getRandom(50, 200); 107 this.balls.push(new Ball(fwx, fwy, fwx + Math.cos(angle) * radius, fwy + Math.sin(angle) * radius)); 108 } 109 } 110 } 111 112 function Ball(bx, by, ex, ey) { 113 this.bx = bx; 114 this.by = by; 115 this.ex = ex; 116 this.ey = ey; 117 } 118 119 Ball.prototype = { 120 getSpan: function () { 121 var xSpan = (this.ex - this.bx) / allDrawCount, 122 ySpan = (this.ey - this.by) / allDrawCount; 123 return { 124 x: xSpan, 125 y: ySpan 126 }; 127 }, 128 currPosition: function () { 129 var span = this.getSpan(), 130 currX = -1, 131 currY = -1; 132 if (drawCount < allDrawCount) { 133 currX = this.bx + span.x * (drawCount - 1); 134 currY = this.by + span.y * (drawCount - 1); 135 return { 136 x: currX, 137 y: currY 138 }; 139 } 140 return null; 141 }, 142 nextPosition: function () { 143 var span = this.getSpan(), 144 currX = -1, 145 currY = -1; 146 if (drawCount < allDrawCount) { 147 currX = this.bx + span.x * drawCount; 148 currY = this.by + span.y * drawCount; 149 return { 150 x: currX, 151 y: currY 152 }; 153 } 154 return null; 155 } 156 } 157 158 currFW = new FireWork(); 159 currFW.run(); 160 requestAnimationFrame(drawLine);
以上が花火効果を実現するための HTML5 Canvas の実践的なコード ケースの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。