Maison >interface Web >Tutoriel H5 >Cas de code pratique HTML5 Canvas pour obtenir un effet de feu d'artifice
requestAnimationFrame est utilisé par le navigateur pour le timing Une interface pour les opérations de bouclage, similaire à setTimeout, son objectif principal est de redessiner la page Web image par image.
Le but de la configuration de cette API est de permettre à divers effets d'animation de pages Web (animation DOM, animation Canvas, animation SVG, animation WebGL) d'avoir un mécanisme de rafraîchissement unifié, économisant ainsi les ressources système, améliorant les performances du système, et améliorer les effets visuels. Utiliser cette API dans le code consiste à indiquer au navigateur que vous souhaitez exécuter une animation et à laisser le navigateur planifier un redessinage de page Web dans l'image d'animation suivante.
L'avantage de requestAnimationFrame est d'utiliser pleinement le mécanisme de rafraîchissement de l'affichage et d'économiser les ressources système. L'affichage a une fréquence de rafraîchissement fixe (60 Hz ou 75 Hz), ce qui signifie qu'il ne peut être redessiné que jusqu'à 60 ou 75 fois par seconde. L'idée de base de requestAnimationFrame est de rester synchronisé avec cette fréquence de rafraîchissement et d'utiliser cette fréquence de rafraîchissement. pour redessiner la page. De plus, en utilisant cette API, la page cessera automatiquement de s'actualiser une fois qu'elle ne sera plus dans l'onglet actuel du navigateur. Cela permet d'économiser du CPU, du GPU et de l'énergie.
Mais une chose à noter est que requestAnimationFrame est terminé sur le thread principal. Cela signifie que si le thread principal est très occupé, l'effet d'animation de requestAnimationFrame sera considérablement réduit.
requestAnimationFrame prend une fonction de rappel comme paramètre. Cette fonction de rappel sera appelée avant que le navigateur ne soit redessiné.
requestID = window.requestAnimationFrame(callback);
Actuellement, les navigateurs de versions supérieures (Firefox 23 / IE 10 / Chrome / Safari) prennent en charge cette méthode. Vous pouvez utiliser la méthode suivante pour vérifier si le navigateur prend en charge cette API. Si elle n'est pas prise en charge, simulez vous-même la méthode de déploiement.
window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; })();
Le code ci-dessus simule requestAnimationFrame 60 fois par seconde (environ une fois toutes les 16,7 millisecondes).
Lorsque vous utilisez requestAnimationFrame, appelez-le simplement à plusieurs reprises.
function repeatOften() { // Do whatever requestAnimationFrame(repeatOften); } requestAnimationFrame(repeatOften);
Annulez le redessinage à l'aide de CancelAnimationFrame.
window.cancelAnimationFrame(requestID);
Son paramètre est une valeur entière renvoyée par requestAnimationFrame représentant l'ID de la tâche.
Déterminez si le navigateur prend en charge le canevas et définissez la largeur et la hauteur en fonction de la taille de la fenêtre du navigateur.
var canvas = document.getElementById("myCanvas"); if (!canvas.getContext) { return; } canvas.width = window.innerWidth; canvas.height = window.innerHeight;var ctx = canvas.getContext("2d");
L'effet de feu d'artifice peut être simplement considéré comme entourant un point, et l'explosion produit de nombreuses petites boules qui se propagent sur les côtés. Par conséquent, un objet de feu d'artifice est nécessaire. Cet objet enregistre principalement l'emplacement du feu d'artifice et les informations sur les boules environnantes. Notre objet feu d'artifice est donc défini comme suit.
function FireWork() { this.x = -1; this.y = -1; this.balls = []; }
Quelles méthodes cet objet doit-il avoir ?
Tout d'abord, créez la petite boule qui explose.
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)); } }
Remarque : ici fwx est la coordonnée sur l'axe X de la position du feu d'artifice, fwy est la coordonnée sur l'axe Y de la position du feu d'artifice, la même ci-dessous.
La longueur de course de la balle est ici une valeur aléatoire de 50 à 200. Le point de départ de la trajectoire de la balle est la position du feu d'artifice et le point final est un point aléatoire sur un cercle.
Ensuite, il faut initialiser le feu d'artifice, principalement pour déterminer la position et générer des petites boules.
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; }
Remarque : ici drawCount est le nombre de tirages, et currBallIndex est la balle actuellement tirée index .
L'ensemble de FireWork est défini comme suit.
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)); } } }
La balle a besoin de connaître l'emplacement de son point de départ et de son point d'arrivée, elle est donc défini comme suit.
function Ball(bx, by, ex, ey) { this.bx = bx;//起点X轴坐标 this.by = by;//起点Y轴坐标 this.ex = ex;//终点X轴坐标 this.ey = ey;//终点Y轴坐标}
La balle doit également être capable de calculer les coordonnées actuelles et les coordonnées du prochain dessin en fonction du nombre actuel de dessins et du nombre total de dessins. La ligne droite reliant ces deux coordonnées est le contenu de. être dessiné cette fois, donc la définition est la suivante.
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; //画布高度
et puis il existe plusieurs méthodes d'outils.
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); }
Enfin, il existe une méthode de dessin appelée par requestAnimationFrame. Cette méthode de dessin consiste à obtenir le chemin de la balle qui explose (un segment de ligne comprenant le point de départ et le point final) en fonction du nombre actuel de dessins, puis à effacer le dernier chemin tracé.
Lorsque l'effet d'un feu d'artifice est dessiné, procédez au tirage du feu d'artifice suivant.
function drawLine(span) { if (currFW && currBallIndex !== -1) { if (drawCount <p>La couleur ici est une valeur aléatoire. </p><h2> (7) Commencez à dessiner </h2><p>La dernière étape consiste à commencer à dessiner. </p><pre class="brush:html;toolbar:false;">currFW = new FireWork(); currFW.run(); requestAnimationFrame(drawLine);
L'intégralité du code est le suivant, 160 lignes au total.
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);
Bienvenue pour en discuter.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!