Canvas from Scratch Transformaties en verlopen

In dit artikel laat ik je door transformaties in het canvas lopen, evenals schaduwen en hellingen. Transformaties zijn een uiterst waardevolle set methoden waarmee je creatief kunt worden met de manier waarop je objecten op het canvas tekent. Laten we aan de slag na de sprong!


Opzetten

Je gaat dezelfde HTML-sjabloon gebruiken van de vorige artikelen, dus open je favoriete editor en plak de volgende code in:

   Canvas helemaal opnieuw          

Hier hebben we niets meer dan een eenvoudige HTML-pagina met een canvas element en een JavaScript dat wordt uitgevoerd nadat de DOM is geladen. Niks gek.


Vertalingen in actie

Vertalen verschuift in wezen het volledige coördinatensysteem.

Een van de eenvoudigste transformaties in canvas is vertalen. Hiermee kunt u het beginpunt van de 2D-renderingcontext verplaatsen; de positie (0, 0) op het canvas. Ik zal je laten zien wat dit betekent.

Plaats eerst een vierkant in canvas op de positie (0, 0):

ctx.fillRect (0, 0, 100, 100);

Het tekent zichzelf aan de linkerbovenrand van het canvas. Nog steeds - niets bijzonders hier.

Probeer nu de 2D-renderingcontext te vertalen en een ander vierkant in dezelfde positie te tekenen:

ctx.save (); ctx.translate (100, 100); ctx.fillStyle = "rgb (0, 0, 255)"; ctx.fillRect (0, 0, 100, 100); ctx.restore ();

Wat denk je dat er gaat gebeuren? Heb een gouden ster als je geraden hebt dat het nieuwe vierkant op de positie (100, 100) getekend zal worden. Geen speeltijd voor degenen die het verkeerd hebben geraden. Sorry!

Dus wat gebeurde er toen? Wat betreft de code voor het tekenen van het tweede vierkant, trok u het op dezelfde plaats als het eerste vierkant. De reden hiervoor is dat je in feite het volledige coördinatensysteem van het canvas hebt verschoven zodat de positie (0, 0) nu op de plaats is (100, 100).

Is het nu iets logischer? Ik hoop het. Het kan enige tijd duren voordat je je hoofd omdraait, maar het is een eenvoudig concept als je het eenmaal begrijpt.

Je zou deze transformatie waarschijnlijk niet te veel alleen gebruiken, omdat je simpelweg het tweede vierkant bij (100, 100) kunt tekenen om hetzelfde effect te krijgen. De schoonheid van vertalen, echter, is dat je het kunt combineren met andere transformaties om een ​​aantal leuke dingen te doen.

Laten we een kijkje nemen naar de volgende transformatie in de lijst.


Uw afbeeldingen schalen

Zoals je waarschijnlijk al geraden hebt, is de schaal transformatie wordt gebruikt voor het wijzigen van de grootte. Meer specifiek wordt de schaaltransformatie gebruikt om de 2D-renderingcontext te schalen.

Verwijder de code waaraan u hebt gewerkt met de vertalen voorbeeld en voeg de volgende code toe:

ctx.fillRect (100, 100, 100, 100);

Hiermee wordt een standaardvierkant getekend op de positie (100, 100), met een breedte en hoogte van 100 pixels. Dus hoe kunnen we dit schalen?

Eigenschappen in schaal zijn vermenigvuldigers voor de x- en y-dimensies.

De schaal transformatie wordt op een vergelijkbare manier gebruikt vertalen, in dat het wordt genoemd voordat je de objecten tekent waarop je wilt dat het wordt toegepast. Het is belangrijk om erop te wijzen dat de eigenschappen in schaal zijn multipliers voor de X en Y dimensies. Dit betekent dat een schaal van (1, 1) vermenigvuldigt de grootte van de 2D-renderingcontext met één, waardoor deze dezelfde grootte behoudt als voorheen. EEN schaal van (5, 5) vermenigvuldigt de grootte van de 2D-renderingcontext met vijf, waardoor het vijf keer groter is dan het eerder was. Eenvoudig.

In jouw geval wil je de grootte van het vierkant verdubbelen, dus je past een schaal van (2, 2):

ctx.save (); ctx.scale (2, 2); ctx.fillRect (100, 100, 100, 100); ctx.restore ();

Wat resulteert in een vierkant dat twee keer zo groot is:

Merk echter op hoe het vierkant nu in een andere positie wordt getekend dan dat het werd getekend voordat u het toepaste schaal. De reden hiervoor is dat schaal vermenigvuldigt de grootte van alles in de 2e rendering-context, inclusief coördinaten. In uw geval wordt de positie (100, 100) nu (200, 200); de coördinaten zijn tweemaal zo groot als ze zouden zijn zonder te worden geschaald.

Om dit te omzeilen, kunnen we een vertalen Hiermee wordt de oorsprong van de 2D-renderingcontext verplaatst naar de positie waarin u het vierkant wilt tekenen. Als je dan solliciteert schaal en teken het vierkant op positie (0, 0), zijn positie zal niet worden verschoven:

ctx.save (); ctx.translate (100, 100); ctx.scale (2, 2); ctx.fillRect (0, 0, 100, 100); ctx.restore ();

Dit resulteert in een vierkant dat twee keer zo groot is als het origineel, maar dat op dezelfde positie wordt getekend als het origineel:

Het is zich bewust van deze kleine eigenaardigheden in transformaties die echt helpen bij het gebruik ervan. De meest voorkomende problemen met transformaties lijken het gevolg te zijn van het niet volledig begrijpen van hoe ze werken.


Roterende elementen

Tot dusverre waren alle transformaties waarmee je te maken kreeg tamelijk oninteressant. Gelukkig is de draaien transformatie is hier om de dag te redden, en het is gemakkelijk mijn favoriet van het stel.

Ik ben er zeker van draaien behoeft geen introductie, dus laten we meteen naar binnen springen en een vierkant van 45 graden draaien (onthoud dat graden in radialen moeten zijn):

ctx.save (); ctx.rotate (Math.PI / 4); // Roteer 45 graden (in radialen) ctx.fillRect (100, 100, 100, 100); ctx.restore ();

Welke positie een vierkant op (100, 100) en draait? woah, wacht even! Dit ziet er niet goed uit:

Zie je wat er is gebeurd? Het vierkant lijkt te proberen te ontsnappen uit het browservenster, in plaats van ter plekke te draaien (100, 100). Dit is zo omdat draaien, zoals alle transformaties, heeft invloed op de gehele 2D-renderingcontext en niet op objecten afzonderlijk.

Hier is een illustratie van wat er met het coördinatensysteem gebeurt als je een 45 graden uitvoert draaien:

Merk op hoe het hele coördinatensysteem 45 graden is geroteerd vanaf het punt van oorsprong (0, 0)? Dit is de reden waarom het vierkant eruitzag alsof het uit het browservenster ontsnapte, eenvoudig omdat de positie (100, 100) op de rand van de browser was gedraaid..

De eenvoudige manier om dit probleem te omzeilen is om te combineren draaien met vertalen, zoals zo:

ctx.save (); ctx.translate (150, 150); // Vertalen naar het midden van vierkante ctx.rotate (Math.PI / 4); // Roteer 45 graden ctx.fillRect (-50, -50, 100, 100); // Centreer op het rotatiepunt ctx.restore ();

Het uitvoeren van de vertalen verplaatst het oorsprongspunt van de 2D-renderingcontext (0, 0) naar wat het centrale punt van het vierkant zou moeten zijn (150, 150). Dit betekent dat elke rotatie nu gebaseerd is op de positie (150, 150). Als je dan een vierkant trekt met een negatief X en Y positie, gelijk aan de helft van de breedte en de hoogte van het vierkant, zult u uiteindelijk een vierkant tekenen dat lijkt alsof het rond zijn middelpunt is geroteerd:

De draaien transformatie is waarschijnlijk de moeilijkste van allemaal om volledig te begrijpen. Het is belangrijk om te onthouden dat transformaties worden uitgevoerd op de volledige 2D-renderingcontext en, als u een vorm rond het centrale punt wilt roteren, moet u draaien met vertalen.

Laten we verder gaan met iets dat visueel indrukwekkender is.


Schaduwen toevoegen

Het toevoegen van schaduwen aan objecten is heerlijk eenvoudig.

Canvas wordt geleverd met een paar eigenschappen voor het bewerken van het uiterlijk van de objecten die erop worden getekend, en met een set van deze eigenschappen kunt u schaduwen toevoegen.

Het toevoegen van schaduwen aan objecten is heerlijk eenvoudig. Het vereist eenvoudig de schaduwkleur eigenschap die moet worden ingesteld in de 2D-renderingcontext naar een kleur die niet transparant zwart is, en een van de shadowBlur, shadowOffsetX, of shadowOffsetY eigenschappen die moeten worden ingesteld op een andere waarde dan 0.

Probeer de volgende code:

ctx.save (); ctx.shadowBlur = 15; ctx.shadowColor = "rgb (0, 0, 0)"; ctx.fillRect (100, 100, 100, 100); ctx.restore ();

Dit geeft de schaduw een vervaging van vijftien pixels en stelt de kleur in op effen zwart:

Vrij standaarddingen tot nu toe.

Als u de shadowBlur tot 0, verander de schaduwkleur tot een lichtgrijs, en geef een positief shadowOffsetX en shadowOffsetY:

ctx.save (); ctx.shadowBlur = 0; ctx.shadowOffsetX = 6; ctx.shadowOffsetY = 6; ctx.shadowColor = "rgba (125, 125, 125, 0.5)"; // Transparant grijs ctx.fillRect (300, 100, 100, 100); ctx.restore ();

Je krijgt een solide schaduw die iets rechts naast het object staat dat getekend is:

Zo koel als schaduwen zijn, kunnen ze een beetje een bronzwijn zijn.

Het is belangrijk om te onthouden dat schaduwen invloed hebben op alles dat wordt getekend nadat ze zijn gedefinieerd, dus het is handig om de. Te gebruiken opslaan en herstellen methoden om te voorkomen dat u de schaduweigenschappen opnieuw moet instellen nadat u ze hebt gebruikt.

Houd er rekening mee dat de prestaties kunnen afnemen wanneer u een schaduw op veel en veel objecten tegelijkertijd toepast. In sommige gevallen is het misschien de moeite waard om een ​​PNG-afbeelding met een schaduw te gebruiken in plaats van een object handmatig te tekenen en een dynamische schaduw toe te passen met behulp van code. We bespreken hoe u afbeeldingen met canvas gebruikt in de volgende aflevering van deze serie.


Gradiënten maken

U kunt twee soorten verlopen in canvas maken - lineair en radiaal.

De laatste functies die ik in deze zelfstudie met u wil bespreken, zijn verlopen. Er zijn twee soorten verlopen in canvas, de eerste zijn lineaire (rechte) verlopen. U kunt een lineair verloop maken met behulp van de createLinearGradient methode (verrassend genoeg), die er als volgt uitziet in pseudo-code:

ctx.createLinearGradient (startX, startY, endX, endY);

De eerste reeks van twee argumenten zijn de X en Y positie van het begin van het verloop, en de tweede reeks argumenten zijn de X en Y positie van het einde van het verloop. Het is ook belangrijk om erop te wijzen dat een verloop in canvas eigenlijk een soort kleurwaarde is, dus u past ze toe op de fillStyle en strokeStyle eigenschappen.

Hier is een voorbeeld van het maken van een lineair verloop dat van de bovenkant van het canvas loopt, helemaal naar de onderkant:

var gradient = ctx.createLinearGradient (0, 0, 0, canvas.hoogte); gradient.addColorStop (0, "rgb (255, 255, 255)"); gradient.addColorStop (1, "rgb (0, 0, 0)"); ctx.save (); ctx.fillStyle = verloop; ctx.fillRect (0, 0, canvas.width, canvas.height); ctx.restore ();

Merk op hoe u het verloop toewijst aan een variabele en gebruik die variabele om het te gebruiken addColorStop methode. Met deze methode kunt u de kleur instellen op bepaalde punten langs het verloop. De positie 0 zou bijvoorbeeld het begin van de verloop (de eerste X en Y positie), en 1 zou het einde van de gradiënt (de tweede) voorstellen X en Y positie). U kunt ook decimale punten gebruiken tussen 0 en 1 om een ​​kleur toe te wijzen op een ander punt langs het verloop, zoals 0,5 halverwege.

Door de gradiëntvariabele toe te passen op de fillStyle eigenschap, eindig je met een mooie verloop die van wit gaat (op positie 0 bovenaan het canvas), naar zwart (op positie 1 onderaan het canvas):

Maar je hoeft niet altijd lineaire gradiënten te gebruiken; u kunt ook radiale verlopen maken!

Radiale verlopen worden gemaakt met de createRadialGradient methode, die er als volgt uitziet in pseudo-code:

ctx.createRadialGradient (startX, startY, startRadius, endX, endY, endRadius);

De eerste set van drie argumenten zijn de X en Y positie en de straal van de cirkel aan het begin van de helling, met de laatste drie argumenten die de X en Y positie en de straal van de cirkel aan het einde van het verloop.

Klinkt verwarrend, toch? Het is een beetje, dus laten we er in springen en een radiaal verloop maken om te zien wat er gebeurt:

var gradient = ctx.createRadialGradient (350, 350, 0, 50, 50, 100); gradient.addColorStop (0, "rgb (0, 0, 0)"); gradient.addColorStop (1, "rgb (125, 125, 125)"); ctx.save (); ctx.fillStyle = verloop; ctx.fillRect (0, 0, canvas.width, canvas.height); ctx.restore ();

U hebt een radiaal verloop gemaakt met een startpunt op (350, 350) met een straal van 0 en een eindpunt op (50, 50) met een straal van 100. Kunt u raden hoe dit eruit zal zien? 20 punten als je geraden had dat het er zo uitziet:

Als je zoiets als mij bent, is dat niet wat ik verwachtte te zien. Ik heb eerder radiale verlopen gebruikt in toepassingen zoals Adobe Photoshop en ze zien er niks van! Dus waarom ziet het er dan zo uit? Wel, dat is hoe het is om er vreemd uit te zien.

Bekijk dit diagram dat precies beschrijft hoe een radiale gradiënt in canvas werkt:

Interessant, is het niet? Je kunt in principe een kegelvorm maken, maar wat als je een goed radiaal verloop wilt maken zoals in Photoshop? Gelukkig is het eenvoudig.

Het maken van een juiste radiale gradiënt vereist alleen dat u de twee cirkels van het verloop op exact hetzelfde plaatst X en Y positie, zorg ervoor dat een van de verloopcirkels groter is dan de andere:

var canvasCentreX = canvas.width / 2; var canvasCentreY = canvas.height / 2; var gradient = ctx.createRadialGradient (canvasCentreX, canvasCentreY, 250, canvasCentreX, canvasCentreY, 0); gradient.addColorStop (0, "rgb (0, 0, 0)"); gradient.addColorStop (1, "rgb (125, 125, 125)"); ctx.save (); ctx.fillStyle = verloop; ctx.fillRect (0, 0, canvas.width, canvas.height); ctx.restore ();

De bovenstaande code maakt een radiaal verloop dat zich in het midden van het canvas bevindt. Een van de cirkels in het verloop heeft een straal van 0, terwijl de andere een straal van 250 heeft. Het resultaat is een traditionele radiale gradiënt die van het midden van het canvas naar buiten loopt, zoals:

Dat ziet er beter uit! Ik was oprecht verbaasd toen ik zag hoe radiale gradiënten werden geïmplementeerd in canvas. Ik wed dat er veel mensen op struikelen als ze die kegelvorm zien. Ach ja, je weet nu tenminste hoe je de juiste kunt maken.

Het is de moeite waard om erop te wijzen dat gradiënten in canvas ook behoorlijk intensieve bewerkingen zijn. Als u het volledige canvas in een verloop wilt bedekken, zou ik eerst overwegen om een ​​CSS3-verloopachtergrond toe te passen op het canvaselement zelf.


Afsluiten

In dit artikel hebben we bekeken hoe basistransformaties op het canvas kunnen worden uitgevoerd, inclusief vertalingen, schalen en rotatie. Je hebt ook geleerd hoe je schaduwen toevoegt aan objecten en hoe je hellingen maakt. Het klinkt niet als veel, maar met name transformaties vormen de ruggengraat van enkele van de coolste dingen die je op canvas kunt bereiken.

In de volgende vermelding in "Canvas from Scratch" breken we af van tekenobjecten en bekijken we hoe we afbeeldingen en video in het canvas kunnen manipuleren. Dit is waar dingen echt interessant worden! Blijf kijken!