HTML5+JS
Effekter oprettes med ren JavaScript på et HTML5-canvas-element. I dette afsnit gennemgår vi det grundlæggende: tegning af figurer, tegning med iteration og tilføjelse af bevægelse.
Tegning af figurer
Sektion kaldt “Tegning af figurer”I denne vejledning bruger jeg en generisk lightscript-skabelon:
<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>Linjer
Sektion kaldt “Linjer”Uanset om du bruger én linje eller mange, er processen den samme.
- ctx.beginPath() starter din figur
- ctx.moveTo(x, y) sætter det første punkt
- ctx.lineTo(x, y) sætter det næste punkt og en linje tilbage til det første. Brug flere lineTo’er til at tegne større figurer.
- Angiv ctx.strokeStyle og/eller ctx.fillStyle (hvis figuren er lukket)
- Brug ctx.stroke() til at tegne linjerne og ctx.fill() til at udfylde lukkede figurer. Det er vigtigt at bemærke, at alt indtil dette punkt er hypotetisk – intet tegnes, før disse kommandoer udføres.
Her er tre eksempler med linjer:
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);}
Læg mærke til tegnerækkefølgen her: den udfyldte trekant tegnes sidst, så den ville dække de to andre figurer, hvis de var på samme position. Desuden tegnes trekantens streg efter udfyldningen. Hvis vi byttede om på disse trin, ville den indre halvdel af stregen blive dækket af den røde udfyldning.
Rektangler
Sektion kaldt “Rektangler”Rektangler er enkle og nyttige, især til den gennemsnitlige opløsning på et RGB-tastatur. Processen ligner tegning af linjer – erstat blot kommandoerne moveTo og lineTo med 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); }
Buer tegnes ved at rotere et ydre punkt omkring et centralt punkt og kan bruges til at lave hele cirkler. Kommandoen for buer er ctx.arc(x, y, radius, start angle, end angle), hvor begge vinkler angives i radianer. I modsætning til rektangler tegnes en bue med figurens origo (x, y) i midten af buen.
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); }
Som du kan se, tegnes buer som standard med uret. Det kan vendes om med en slutvinkel, der er mindre end startvinklen, eller ved at tilføje “true” som sidste argument til metoden ctx.arc().
Tegning med iteration
Sektion kaldt “Tegning med iteration”At tegne tre figurer i hånden kan nemt kræve tyve linjer kode, så hvis du skal tegne hundrede figurer, har vi brug for en mere effektiv tilgang. Løkker i JavaScript er en enkel måde at gentage opgaver på, og de kan også bruges til tegning.
Her er et eksempel, der bruger en for-løkke til at tegne en række ternede firkanter:
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); }
Her er et eksempel med en while-løkke, der tegner et ternet gitter. Jeg ændrer lysheden af de sorte firkanter og farvetonen af de hvide firkanter en smule i hver iteration ved hjælp af template literals.
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); }
Tilføjelse af bevægelse
Sektion kaldt “Tilføjelse af bevægelse”Animationer på canvas’et er kun begrænset af din fantasi og din matematiske viden. Hvis du føler dig usikker på trigonometri eller geometri, anbefaler jeg at læse lidt op på det for at løfte dine færdigheder til næste niveau. I de næste eksempler tager jeg en stillestående cirkel og knytter alle mulige variabler til en simpel svingende bevægelse.
Den gyldne standard for oscillation (regelmæssig frem-og-tilbage-bevægelse) er at tage sin() eller cosine() af en timer. Begge operationer returnerer en værdi mellem -1 og 1 for ENHVER indsat værdi, selv hvis den blot tæller opad. Den eneste forskel på de to er, at de er lidt ude af takt – når cos er 0, er sin -1 eller 1, og omvendt. Det kan vi udnytte i denne animation –
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); }Side til side
Sektion kaldt “Side til side”
Op og ned
Sektion kaldt “Op og ned”
Hel cirkel
Sektion kaldt “Hel cirkel”
Vi har kun nogle få egenskaber mere at ændre over tid – cirklens radius, udfyldning og streg. Jeg lader buevinklerne være i fred for nu for at holde figuren enkel, for resten bliver ret prangende.
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); }
Alle egenskaber ved alle de figurer, vi har lavet indtil nu, kan ændres over tid, og hver animation, jeg laver, er en kombination af ovenstående færdigheder. For flere detaljer om at skabe genanvendelige, effektive animationer kan du se vores side om Callbacks!