HTML5+JS
Effekter skapas med vanlig JavaScript på ett HTML5 canvas-element. I det här avsnittet går vi igenom grunderna: rita former, rita med iteration och lägga till rörelse.
Rita former
Section titled “Rita former”För den här handledningen använder jag en generisk lightscript-mall:
<head> <meta description="Template"/> <meta publisher="WhirlwindFX" /></head>
<body style="margin: 0; padding: 0;"> <canvas id="exCanvas" width="320" height="200"></canvas></body>
<script> // Hämta canvas-elementet från DOM var c = document.getElementById("exCanvas"); var ctx = c.getContext("2d");
var width = 320; var height = 200; var hue = 0;
function update() { // Kod placeras här window.requestAnimationFrame(update); }
window.requestAnimationFrame(update);</script>Linjer
Section titled “Linjer”Oavsett om du använder en linje eller många förblir processen densamma.
- ctx.beginPath() startar din form
- ctx.moveTo(x, y) anger den första punkten
- ctx.lineTo(x, y) anger nästa punkt och en linje tillbaka till den första. Använd flera lineTo för att rita större former.
- Ange ctx.strokeStyle och/eller ctx.fillStyle (om formen är sluten)
- Använd ctx.stroke() för att rita linjerna och ctx.fill() för att fylla slutna former. Det är viktigt att notera att fram till det här steget är allt hypotetiskt – ingenting ritas förrän dessa kommandon körs.
Här är tre exempel med linjer:
function update() { // En linje 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();
// Fylld triangel 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);}
Det är viktigt att notera ritordningen här: den fyllda triangeln ritas sist, så den skulle täcka de två andra formerna om de befann sig på samma position. Dessutom ritas stroken i triangeln efter fyllningen. Om vi vände på dessa steg skulle den inre halvan av stroken täckas av den röda fyllningen.
Rektanglar
Section titled “Rektanglar”Rektanglar är enkla och användbara, särskilt för den genomsnittliga upplösningen på ett RGB-tangentbord. Processen liknar att rita linjer – ersätt bara moveTo- och lineTo-kommandona med rect(x, y, width, height).
function update() { // Grundläggande kvadrat ctx.beginPath(); ctx.rect(30, 30, 75, 75); ctx.strokeStyle = "blue"; ctx.stroke();
// Fylld rektangel ctx.beginPath(); ctx.rect(125, 30, 125, 100); ctx.fillStyle = "red"; ctx.strokeStyle = "blue"; ctx.fill(); ctx.stroke();
window.requestAnimationFrame(update); }
Bågar ritas genom att rotera en yttre punkt runt en central punkt och kan användas för att skapa hela cirklar. Bågkommandot är ctx.arc(x, y, radius, startvinkel, slutvinkel), där båda vinkelmåtten anges i radianer. Till skillnad från rektanglar ritas en båge med formens origo (x, y) i mitten av bågen.
function update() { // Halvcirkel ctx.beginPath(); ctx.arc(70, 100, 30, 0, Math.PI); ctx.strokeStyle = "blue"; ctx.stroke();
// 3/4-cirkel ctx.beginPath(); ctx.arc(140, 100, 30, 0, Math.PI * (3/2)); ctx.strokeStyle = "blue"; ctx.stroke();
// Hel cirkel 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 ritas bågar medurs som standard. Detta kan vändas med en slutvinkel som är mindre än startvinkeln, eller genom att lägga till “true” som ett sista argument till metoden ctx.arc().
Rita med iteration
Section titled “Rita med iteration”Att rita tre former för hand kan lätt ta tjugo rader kod, så om du behöver rita hundra former behöver vi ett mer effektivt tillvägagångssätt. Loopar i JavaScript är ett enkelt sätt att upprepa uppgifter och kan tillämpas på ritning också.
Här är ett exempel med en for-loop för att rita en rad schackrutor:
function update() {
for(let i = 0; i < 8; i++){
// 1. Skapa rektangelstig och rita stroken för var och en. ctx.beginPath(); ctx.rect(i * 20, 20, 20, 20); ctx.strokeStyle = "black"; ctx.stroke();
// 2. Om 'i' är jämnt är fillStyle svart. Annars är den vit. if(i % 2 == 0){ ctx.fillStyle = "black"; } else { ctx.fillStyle = "white"; } // 3. Fyll formen efter att ha angett fillStyle. ctx.fill(); }
window.requestAnimationFrame(update); }
Här är ett while-loop-exempel för att rita ett schackmönster. Jag ändrar ljusstyrkan på de svarta rutorna och hue hos de vita rutorna något i varje iteration med hjälp av mallbokstavar.
function update() {
var i = 0;
while(i < 16){
// 1. X- och Y-beräkningar med 'row' och 'column' // Den här operationen avrundar resultatet nedåt till närmaste heltal. För i = (0-3) är raden 0, för i = (4-7) är raden 1, och så vidare var iRow = Math.floor(i / 4); // Den här operationen hittar resten efter division, vilket begränsar kolumnen till intervallet (0-3). var iCol = i % 4; // Multiplicera med kvadratbredden för att hitta den här kvadratens x-origo var ix = iCol * 20; // Multiplicera med kvadrathöjden för att hitta den här kvadratens y-origo var iy = iRow * 20;
// 2. Stig och stroke ctx.beginPath(); ctx.rect(ix, iy, 20, 20); ctx.strokeStyle = "black"; ctx.stroke();
// 3. Om raden är jämn är varannan ruta fylld svart. Om udda, byt de svarta rutorna. Varje iteration lägger till en liten mängd av ljuskomponenten till det svarta, och hue till det vita. if(iRow % 2 == 0){ if(i % 2 == 0){ // 'Svart' ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)` } else { // 'Vit' ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`; } } else { if(i % 2 == 0){ // 'Vit' ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`; } else { // 'Svart' ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)` } }
ctx.fill(); i++; }
window.requestAnimationFrame(update); }
Lägga till rörelse
Section titled “Lägga till rörelse”Animationer på canvas begränsas bara av din fantasi och matematiska kunskap. Om du känner dig osäker med trigonometri eller geometri rekommenderar jag att du gör lite lättviktig forskning för att ta dina färdigheter till nästa nivå. I de kommande exemplen tar jag en stationär cirkel och kopplar varje möjlig variabel till en enkel oscillerande rörelse.
Guldstandarden för oscillation (regelbunden fram-och-tillbaka-rörelse) är att ta sin() eller cosinus() av en timer. Båda operationerna returnerar ett värde mellan -1 och 1 för VILKET värde som helst som skickas in, även om det bara räknar uppåt. Den enda skillnaden är att de är något ur synk – när cos är 0 är sin -1 eller 1, och vice versa. Vi kan använda detta till vår fördel i den här animationen –
function update() {
// Hitta aktuell tid i millisekunder, dela sedan för att sakta ned animationshastigheten let time = Date.now() / 100;
// Rita en bakgrund så att de gamla formerna inte finns kvar ctx.fillStyle = "white"; ctx.fillRect(0, 0, 320,200);
ctx.beginPath();
// ANVÄND ETT EXEMPEL ÅTGÅNGEN // 1:a exemplet - sida till sida, y är konstant ctx.arc(15 * Math.cos(time) + 160, 100, 30, 0, Math.PI * 2); // 2:a exemplet - upp och ned, x är konstant ctx.arc(160, 15 * Math.sin(time) + 100, 30, 0, Math.PI * 2); // 3:e exemplet - cirkel, x och y är variabla 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); }Sida till sida
Section titled “Sida till sida”
Upp och ned
Section titled “Upp och ned”
Hel cirkel
Section titled “Hel cirkel”
Vi har bara några fler attribut att förändra över tid – cirkelradie, fyllning och stroke. Jag lämnar bågens vinklar ifred för att hålla formen enkel eftersom resten kommer att bli ganska bländande.
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); }
Varje attribut på varje form vi har skapat hittills kan förändras över tid, och varje animation jag skapar är en kombination av ovanstående färdigheter. För mer detaljer om att skapa återanvändbara, effektiva animationer, kolla in vår sida Callbacks!