Heim  >  Artikel  >  Web-Frontend  >  Praktischer HTML5 Canvas-Codefall, um einen Feuerwerkseffekt zu erzielen

Praktischer HTML5 Canvas-Codefall, um einen Feuerwerkseffekt zu erzielen

黄舟
黄舟Original
2017-03-30 13:22:294138Durchsuche

1. Wirkung

Praktischer HTML5 Canvas-Codefall, um einen Feuerwerkseffekt zu erzielen

2. Code-Analyse

(1) requestAnimationFrame

requestAnimationFrame wird vom Browser für das Timing verwendet Eine Schnittstelle für Schleifenoperationen , ähnlich wie setTimeout, deren Hauptzweck darin besteht, die Webseite Frame für Frame neu zu zeichnen.

Der Zweck der Einrichtung dieser API besteht darin, verschiedenen Webseitenanimationseffekten (DOM-Animation, Canvas-Animation, SVG-Animation, WebGL-Animation) einen einheitlichen Aktualisierungsmechanismus zu ermöglichen, wodurch Systemressourcen gespart und die Systemleistung verbessert wird. und Verbesserung der visuellen Effekte. Durch die Verwendung dieser API im Code teilen Sie dem Browser mit, dass Sie eine Animation ausführen möchten, und lassen den Browser eine Neuzeichnung der Webseite im nächsten Animationsframe planen.

Der Vorteil von requestAnimationFrame besteht darin, den Aktualisierungsmechanismus der Anzeige vollständig zu nutzen und Systemressourcen zu sparen. Die Anzeige verfügt über eine feste Aktualisierungsfrequenz (60 Hz oder 75 Hz), was bedeutet, dass sie nur bis zu 60 oder 75 Mal pro Sekunde neu gezeichnet werden kann. Die Grundidee von requestAnimationFrame besteht darin, mit dieser Aktualisierungsfrequenz synchron zu bleiben und diese Aktualisierungsfrequenz zu verwenden um die Seite neu zu zeichnen. Darüber hinaus stoppt die Aktualisierung der Seite mithilfe dieser API automatisch, sobald sie sich nicht mehr im aktuellen Tab des Browsers befindet. Das spart CPU, GPU und Strom.

Aber eine Sache ist zu beachten: requestAnimationFrame wird im Hauptthread abgeschlossen. Dies bedeutet, dass der Animationseffekt von requestAnimationFrame stark reduziert wird, wenn der Hauptthread sehr ausgelastet ist.

requestAnimationFrame akzeptiert eine Rückruffunktion als Parameter. Diese Rückruffunktion wird aufgerufen, bevor der Browser neu zeichnet.

requestID = window.requestAnimationFrame(callback);

Derzeit unterstützen höhere Browserversionen (Firefox 23 / IE 10 / Chrome / Safari) diese Methode. Mit der folgenden Methode können Sie prüfen, ob der Browser diese API unterstützt. Wenn dies nicht unterstützt wird, simulieren Sie die Bereitstellungsmethode selbst.

window.requestAnimFrame = (function(){      
return  window.requestAnimationFrame       || 
              window.webkitRequestAnimationFrame || 
              window.mozRequestAnimationFrame    || 
              window.oRequestAnimationFrame      || 
              window.msRequestAnimationFrame     || 
              function( callback ){
                window.setTimeout(callback, 1000 / 60);
              };
})();

Der obige Code simuliert requestAnimationFrame 60 Mal pro Sekunde (ungefähr einmal alle 16,7 Millisekunden).

Wenn Sie requestAnimationFrame verwenden, rufen Sie es einfach wiederholt auf.

function repeatOften() {  // Do whatever  requestAnimationFrame(repeatOften);
}

requestAnimationFrame(repeatOften);

Neuzeichnen mit cancelAnimationFrame abbrechen.

window.cancelAnimationFrame(requestID);

Sein Parameter ist ein Ganzzahlwert, der von requestAnimationFrame zurückgegeben wird und die Aufgaben-ID darstellt.

(2) Canvas (Leinwand) vorbereiten

Bestimmen Sie, ob der Browser Canvas unterstützt, und stellen Sie Breite und Höhe auf die Größe des Browserfensters ein.

var canvas = document.getElementById("myCanvas");
if (!canvas.getContext) {    return;
}
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;var ctx = canvas.getContext("2d");

(3) Feuerwerksobjekt (Feuerwerk)

Der Feuerwerkseffekt kann einfach so betrachtet werden, als ob er einen Punkt umgibt und die Explosion viele kleine Kugeln erzeugt, die sich zu den Seiten ausbreiten. Daher wird ein Feuerwerksobjekt benötigt. Dieses Objekt erfasst hauptsächlich den Standort des Feuerwerks und die Informationen über die umliegenden Kugeln. Unser Feuerwerksobjekt ist also wie folgt definiert.

function FireWork() {    
this.x = -1;    
this.y = -1;    
this.balls = [];
}

Welche Methoden sollte dieses Objekt haben?

Erstelle zunächst die kleine Kugel, die explodiert.

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));
        }
    }

Hinweis: Hier ist fwx die X-Achsen-Koordinate der Feuerwerksposition, fwy ist die Y-Achsen-Koordinate der Feuerwerksposition, das Gleiche unten.

Die Lauflänge des Balls ist hier ein zufälliger Wert von 50 bis 200. Der Startpunkt der Flugbahn des Balls ist die Position des Feuerwerks und der Endpunkt ist ein zufälliger Punkt auf einem Kreis.

Dann muss das Feuerwerk initialisiert werden, hauptsächlich um die Position zu bestimmen und kleine Kugeln zu erzeugen.

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;
    }

Hinweis: Hier ist drawCount die Anzahl der Ziehungen und currBallIndex der aktuell gezogene Ball Index .

Das gesamte FireWork ist wie folgt definiert.

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));
        }
    }
}

(4) Durch Explosion erzeugtes Ballobjekt (Ball)

Der Ball muss die Position seines Start- und Endpunkts kennen, also ist er es wie folgt definiert.

function Ball(bx, by, ex, ey) {    this.bx = bx;//起点X轴坐标
    this.by = by;//起点Y轴坐标
    this.ex = ex;//终点X轴坐标
    this.ey = ey;//终点Y轴坐标}

Der Ball muss auch in der Lage sein, die aktuellen Koordinaten und die nächsten Zeichnungskoordinaten basierend auf der aktuellen Anzahl der Zeichnungen und der Gesamtzahl der Zeichnungen zu berechnen. Die gerade Linie, die diese beiden Koordinaten verbindet, ist der Inhalt Diesmal wird gezeichnet, also Die Definition lautet wie folgt.

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;
    }
}

(5) Globale Variablen und Tool-Methoden

var fwx = -1,                 //烟花位置X轴坐标
    fwy = -1,                 //烟花位置Y轴坐标
    currFW = null,            //烟花实例
    currBallIndex = -1,       //当前正在绘制的小球索引
    drawCount = 0,            //绘制次数
    allDrawCount = 40,        //总共需要的绘制次数
    width = canvas.width,     //画布宽度
    height = canvas.height;   //画布高度

und dann gibt es noch mehrere Tool-Methoden.

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);
}

(6) Zeichenmethode

Schließlich gibt es noch eine Zeichenmethode, die von requestAnimationFrame aufgerufen wird. Diese Zeichenmethode besteht darin, den Pfad des explodierenden Balls (ein Liniensegment einschließlich Startpunkt und Endpunkt) basierend auf der aktuellen Anzahl von Zeichnungen zu ermitteln und dann den zuletzt gezeichneten Pfad zu löschen.

Wenn der Effekt eines Feuerwerks gezeichnet ist, fahren Sie mit dem Zeichnen des nächsten Feuerwerks fort.

function drawLine(span) {    
if (currFW && currBallIndex !== -1) {        
if (drawCount <p>Die Farbe hier ist ein zufälliger Wert. </p><h2> (7) Beginnen Sie mit dem Zeichnen </h2><p>Der letzte Schritt besteht darin, mit dem Zeichnen zu beginnen. </p><pre class="brush:html;toolbar:false;">currFW = new FireWork();
currFW.run();
requestAnimationFrame(drawLine);

(8) Alle Codes.

Der gesamte Code lautet wie folgt, insgesamt 160 Zeilen.

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);

Willkommen zur Diskussion.

Das obige ist der detaillierte Inhalt vonPraktischer HTML5 Canvas-Codefall, um einen Feuerwerkseffekt zu erzielen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn