HTML5+JS
Effekte werden mit vanilla JavaScript auf einem HTML5-canvas-Element erstellt. In diesem Abschnitt werden wir die Grundlagen behandeln: Formen zeichnen, mit Iteration zeichnen und Bewegung hinzufügen.
Formen zeichnen
Abschnitt betitelt „Formen zeichnen“Für dieses Tutorial verwende ich eine generische Lightscript-Vorlage:
<head> <meta description="Template"/> <meta publisher="WhirlwindFX" /></head>
<body style="margin: 0; padding: 0;"> <canvas id="exCanvas" width="320" height="200"></canvas></body>
<script> // Get the canvas element from the DOM var c = document.getElementById("exCanvas"); var ctx = c.getContext("2d");
var width = 320; var height = 200; var hue = 0;
function update() { // Code goes here window.requestAnimationFrame(update); }
window.requestAnimationFrame(update);</script>Ob eine oder viele Linien, der Prozess bleibt derselbe.
- ctx.beginPath() startet deine Form
- ctx.moveTo(x, y) setzt den ersten Punkt
- ctx.lineTo(x, y) setzt den nächsten Punkt und eine Linie zurück zum ersten. Verwende mehrere lineTos, um größere Formen zu zeichnen.
- Setze ctx.strokeStyle und/oder ctx.fillStyle (wenn die Form geschlossen ist)
- Verwende ctx.stroke(), um die Linien zu zeichnen, und ctx.fill(), um alle geschlossenen Formen zu füllen. Es ist wichtig zu beachten, dass bis zu diesem Punkt alles hypothetisch ist - nichts wird gezeichnet, bis diese Befehle ausgeführt werden.
Hier sind drei Beispiele mit Linien:
function update() { // One Line ctx.beginPath(); ctx.moveTo(30, 30); ctx.lineTo(30, 170); ctx.strokeStyle = "blue"; ctx.stroke();
// L ctx.beginPath(); ctx.moveTo(80, 30); ctx.lineTo(80, 100); ctx.lineTo(120, 100); ctx.strokeStyle = "blue"; ctx.stroke();
// Filled Triangle ctx.beginPath(); ctx.moveTo(130, 30); ctx.lineTo(130, 100); ctx.lineTo(170, 100); ctx.lineTo(130, 30); ctx.fillStyle = "red"; ctx.strokeStyle = "blue"; ctx.fill(); ctx.stroke();
window.requestAnimationFrame(update);}
Es ist wichtig, die Zeichenreihenfolge hier zu beachten: Das gefüllte Dreieck wird zuletzt gezeichnet und würde die anderen beiden Formen verdecken, wenn sie an derselben Position wären. Außerdem wird der Strich im Dreieck nach der Füllung gezeichnet. Wenn wir diese Schritte umkehrten, würde die innere Hälfte des Strichs von der roten Füllung verdeckt.
Rechtecke
Abschnitt betitelt „Rechtecke“Rechtecke sind einfach und nützlich, besonders für die durchschnittliche Auflösung einer RGB-Tastatur. Der Prozess ist ähnlich wie beim Zeichnen von Linien - ersetze einfach die moveTo- und lineTo-Befehle durch rect(x, y, width, height).
function update() { // Basic Square ctx.beginPath(); ctx.rect(30, 30, 75, 75); ctx.strokeStyle = "blue"; ctx.stroke();
// Filled Rectangle ctx.beginPath(); ctx.rect(125, 30, 125, 100); ctx.fillStyle = "red"; ctx.strokeStyle = "blue"; ctx.fill(); ctx.stroke();
window.requestAnimationFrame(update); }
Bögen werden durch Drehen eines äußeren Punktes um einen Mittelpunkt gezeichnet und können zur Erstellung vollständiger Kreise verwendet werden. Der Bogenbefehl ist ctx.arc(x, y, radius, Startwinkel, Endwinkel), wobei beide Winkelmaße in Bogenmass angegeben werden. Im Gegensatz zu Rechtecken wird ein Bogen mit dem Ursprung (x, y) in der Mitte des Bogens gezeichnet.
function update() { // Half-circle ctx.beginPath(); ctx.arc(70, 100, 30, 0, Math.PI); ctx.strokeStyle = "blue"; ctx.stroke();
// 3/4 circle ctx.beginPath(); ctx.arc(140, 100, 30, 0, Math.PI * (3/2)); ctx.strokeStyle = "blue"; ctx.stroke();
// Full circle ctx.beginPath(); ctx.arc(210, 100, 30, 0, Math.PI * 2); ctx.strokeStyle = "blue"; ctx.stroke(); ctx.fillStyle = "red"; ctx.fill();
window.requestAnimationFrame(update); }
Wie du sehen kannst, werden Bögen standardmäßig im Uhrzeigersinn gezeichnet. Dies kann mit einem Endwinkel umgekehrt werden, der kleiner als der Startwinkel ist, oder indem “true” als letztes Argument zur ctx.arc()-Methode hinzugefügt wird.
Mit Iteration zeichnen
Abschnitt betitelt „Mit Iteration zeichnen“Drei Formen von Hand zu zeichnen kann leicht zwanzig Codezeilen kosten. Wenn du also hundert Formen zeichnen musst, brauchen wir einen effizienteren Ansatz. Schleifen in JavaScript sind eine einfache Möglichkeit, Aufgaben zu wiederholen, und sie können auch auf das Zeichnen angewendet werden.
Hier ist ein Beispiel mit einer for-Schleife, um eine Reihe von Schachfeldern zu zeichnen:
function update() {
for(let i = 0; i < 8; i++){
// 1. Create rectangle path and draw the stroke for each. ctx.beginPath(); ctx.rect(i * 20, 20, 20, 20); ctx.strokeStyle = "black"; ctx.stroke();
// 2. If 'i' is even, the fillStyle is black. Otherwise it's white. if(i % 2 == 0){ ctx.fillStyle = "black"; } else { ctx.fillStyle = "white"; } // 3. Fill the shape after setting the fillStyle. ctx.fill(); }
window.requestAnimationFrame(update); }
Hier ist ein while-Schleife-Beispiel, um ein Schachbrettmuster zu zeichnen. Ich werde die Helligkeit der schwarzen Felder und den Farbton der weißen Felder in jeder Iteration mit Template-Literals leicht ändern.
function update() {
var i = 0;
while(i < 16){
// 1. X and Y calculations with 'row' and 'column' // This operation rounds the result down to the nearest integer. For i = (0-3) the row will be 0, for i = (4-7) the row will be 1, and so on var iRow = Math.floor(i / 4); // This operation finds the remainder after division, limiting column to the (0-3) range. var iCol = i % 4; // Multiply by the square width to find this square's x-origin var ix = iCol * 20; // Multiply by the square height to find this square's y-origin var iy = iRow * 20;
// 2. Path and stroke ctx.beginPath(); ctx.rect(ix, iy, 20, 20); ctx.strokeStyle = "black"; ctx.stroke();
// 3. If the row is even, every other square is filled black. If odd, switch the black squares. Each iteration adds a small amount of the lightness component to the black, and hue to the white. if(iRow % 2 == 0){ if(i % 2 == 0){ // 'Black' ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)` } else { // 'White' ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`; } } else { if(i % 2 == 0){ // 'White' ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`; } else { // 'Black' ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)` } }
ctx.fill(); i++; }
window.requestAnimationFrame(update); }
Bewegung hinzufügen
Abschnitt betitelt „Bewegung hinzufügen“Animationen im canvas sind nur durch deine Vorstellungskraft und dein mathematisches Wissen begrenzt. Wenn du dich mit Trigonometrie oder Geometrie unsicher fühlst, empfehle ich dir, etwas zu recherchieren, um deine Fähigkeiten auf die nächste Ebene zu bringen. In den nächsten Beispielen nehme ich einen stationären Kreis und weise jeder möglichen Variablen eine einfache Schwingungsbewegung zu.
Der Goldstandard für Schwingungen (regelmäßige Vor-und-Zurück-Bewegung) ist, sin() oder cosinus() eines Timers zu nehmen. Jede Operation gibt einen Wert zwischen -1 und 1 für JEDEN übergebenen Wert zurück, auch wenn er nur hochzählt. Der einzige Unterschied zwischen den beiden ist, dass sie leicht versetzt sind - wenn cos 0 ist, ist sin -1 oder 1 und umgekehrt. Wir können dies zu unserem Vorteil in dieser Animation nutzen:
function update() {
// Find current time in milliseconds, then divide to slow down the animation speed let time = Date.now() / 100;
// Draw a background so the old shapes don't stick around ctx.fillStyle = "white"; ctx.fillRect(0, 0, 320,200);
ctx.beginPath();
//USE ONE EXAMPLE AT A TIME // 1st example - side to side, y is constant ctx.arc(15 * Math.cos(time) + 160, 100, 30, 0, Math.PI * 2); // 2nd example - up and down, x is constant ctx.arc(160, 15 * Math.sin(time) + 100, 30, 0, Math.PI * 2); // 3rd example - circle, x and y are variable ctx.arc(15 * Math.cos(time) + 160, 15 * Math.sin(time) + 100, 30, 0, Math.PI * 2);
ctx.fillStyle = "black"; ctx.fill();
window.requestAnimationFrame(update); }Von Seite zu Seite
Abschnitt betitelt „Von Seite zu Seite“
Auf und ab
Abschnitt betitelt „Auf und ab“
Voller Kreis
Abschnitt betitelt „Voller Kreis“
Wir haben noch ein paar weitere Attribute, die wir im Laufe der Zeit ändern können - Kreisradius, Füllung und Strich. Ich lasse die Bogenwinkel für jetzt unverändert, um die Form einfach zu halten, da der Rest ziemlich auffällig sein wird.
function update() {
let time = Date.now() / 100;
ctx.fillStyle = "white"; ctx.fillRect(0, 0, 320,200);
ctx.beginPath(); ctx.arc(15 * Math.cos(time) + 160, 15 * Math.sin(time) + 100, 30 + 15 * Math.sin(time), 0, Math.PI * 2);
ctx.fillStyle = `hsl(${180 + 180 * Math.cos(time)}, 100%, 50%)`; ctx.fill();
ctx.strokeStyle = `hsl(${180 + 180 * Math.sin(time)}, 100%, 50%)`; ctx.stroke();
window.requestAnimationFrame(update); }
Jedes Attribut jeder Form, die wir bisher erstellt haben, kann im Laufe der Zeit verändert werden, und jede Animation, die ich erstelle, ist eine Kombination der oben genannten Fähigkeiten. Für mehr Details zum Erstellen wiederverwendbarer, effizienter Animationen, schau auf unserer Callbacks-Seite vorbei!