Canvas from Scratch geavanceerde tekening

In het vorige artikel in deze serie hebt u kennisgemaakt met het canvas-element en de basis voor het tekenen ervan. In dit artikel ga ik enkele van de meer geavanceerde tekenfunctionaliteit demonstreren.


Opzetten

We gebruiken dezelfde HTML-sjabloon uit het vorige artikel; dus open je favoriete editor en plak in de volgende code:

    Canvas helemaal opnieuw          

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


Cirkels tekenen

In het laatste artikel heb ik je laten zien hoe je basisvormen en paden tekent; in deze sectie laat ik je zien hoe je een stap verder kunt gaan en cirkels kunt tekenen. Het is niet zo eenvoudig als je zou denken, maar het is nog steeds helemaal niet moeilijk.

Er is geen methode op canvas waarmee je een cirkel kunt tekenen met een enkele coderegel, zoals hoe fillRect werkt voor rechthoeken. In plaats daarvan moet je cirkels tekenen met een pad met de boog methode; een cirkel is slechts een boog van 360 graden. De reden hiervoor is dat cirkels eigenlijk heel complexe vormen zijn, en de boog methode zorgt voor allerlei controle over de manier waarop u ze tekent. U wilt bijvoorbeeld alleen een halve cirkel tekenen. De boog methode kunt u dat doen. Je zou zelfs het boog methode met standaard rechte paden om pizzapunten en kwartcirkels te tekenen.

Ik zal uitleggen hoe het boog methode werkt kort, maar laten we voor nu een cirkel tekenen door de volgende code onder de code toe te voegen ctx variabele:

 cxt.beginPath (); ctx.arc (100, 100, 50, 0, Math.PI * 2, false); ctx.closePath (); ctx.fill ();

Hiermee teken je een cirkel die iets uit de linkerbovenhoek van het canvas is geplaatst:

Ziet er eenvoudig uit, toch? En dat is het, maar laten we eens kijken wat er aan de hand is.

De boog methode heeft in totaal zes argumenten:

  • De eerste is de X positie van het oorsprongspunt (het middelpunt van de cirkel).
  • De tweede is de Y positie van het oorsprongspunt.
  • De derde is de straal van de cirkel.
  • De vierde is de starthoek van de cirkel.
  • De vijfde is de eindhoek van de cirkel.
  • En de zesde is de richting om de boog te tekenen (true is tegen de klok in en false is met de klok mee)

Geschreven in pseudocode, boog zou er als volgt uitzien:

 boog (x, y, radius, startAngle, endAngle, linksom);

De eerste drie argumenten spreken voor zich, net als de vorige, maar hoe zit het met de begin- en eindhoek? Laat het me uitleggen.

Zoals ik eerder al zei, zijn cirkels slechts 360 graden bogen. In canvas wordt een boog gedefinieerd als een gebogen lijn die begint op een afstand van een oorsprongspunt dat de afstand van de straal is. De gebogen lijn begint in de hoek die wordt gedefinieerd als het beginhoekargument (de vierde), en gaat verder over de omtrek van een denkbeeldige cirkel totdat deze de hoek bereikt die is gedefinieerd als het eindhoekargument (de vijfde). Klinkt eenvoudig, toch??

Misschien helpt een illustratie de situatie te verklaren:

Het ziet er misschien gek uit, maar het is logisch als je er eenmaal je hoofd omheen kunt krijgen.

Hoeken op canvas

Op dit punt is het waarschijnlijk het vermelden waard dat de hoeken in canvas in radialen zijn, niet in graden. Dit betekent dat de hoeken gaan van 0 tot pi vermenigvuldigd met twee. Hoeken in canvas beginnen ook vanaf de rechterkant, zoals te zien is in de volgende afbeelding:

Als je echt niet van radialen houdt, kun je gemakkelijk graden omzetten in radialen met de volgende JavaScript-formule:

 var graden = 270; var radians = degrees * (Math.PI / 180);

Deze formule is doodeenvoudig en het is uiterst waardevol als je in graden wilt handelen.


B? Zier Paths

Bogen zijn leuk en allemaal, maar ze zijn behoorlijk beperkend voor het soort bochten dat kan worden gemaakt met canvas. Voor alles wat complexer is, wil je beginnen met kijken naar de B? Zier-curve-methoden quadraticCurveTo, en bezierCurveTo. Met deze methoden kunt u gebogen paden maken met een straal die niet centraal staat in de curve en ook paden maken die meerdere curven hebben.

B? Zier-paden gebruiken controlepunten om te definiëren hoe en waar de curven moeten worden getekend. Bijvoorbeeld, quadraticCurveTo heeft één controlepunt, terwijl bezierCurveTo heeft twee. Bekijk de volgende illustratie om te zien hoe de controlepunten van invloed zijn op de manier waarop een curve wordt getekend:

Als u eerder een vectorgebaseerde tekenprogramma zoals Adobe Illustrator hebt gebruikt, bent u al vertrouwd met dit soort curven.

Laten we erin springen en een kwadratisch B? Zier-pad maken. Vervang de boogcode door het volgende:

 ctx.lineWidth = 8; ctx.beginPath (); ctx.moveTo (50, 150); ctx.quadraticCurveTo (250, 50, 450, 150); ctx.stroke ();

Hiermee wordt een gebogen pad getekend dat lijkt op het pad links van de afbeelding hierboven:

De quadraticCurveTo methode neemt vier argumenten:

  • De eerste is de X positie van het besturingspunt.
  • De tweede is de Y positie van het besturingspunt.
  • De derde is de X positie van het einde van het pad.
  • En de vierde is de Y positie van het einde van het pad.

Geschreven in pseudocode, quadraticCurveTo zou er als volgt uitzien:

 quadraticCurveTo (cpx, cpy, x, y);

De startpositie van de curve is waar het pad momenteel ligt. In de bovenstaande code hebt u bijvoorbeeld het begin van het pad verplaatst door het moveTo methode.

Laten we een niveau hoger gaan en een kubieke B? Zier-pad maken. Vervang de vorige code door het volgende:

 ctx.lineWidth = 8; ctx.beginPath (); ctx.moveTo (50, 150); ctx.bezierCurveTo (150, 50, 350, 250, 450, 150); ctx.stroke ();

Dit tekent een gebogen pad dat lijkt op het pad rechts van de afbeelding hierboven:

De bezierCurveTo methode neemt zes argumenten:

  • De eerste is de X positie van het eerste bedieningspunt.
  • De tweede is de Y positie van het eerste bedieningspunt.
  • De derde is de X positie van het tweede bedieningspunt.
  • De vierde is de Y positie van het tweede bedieningspunt.
  • De vijfde is de X positie van het einde van het pad.
  • En de zesde is de Y positie van het einde van het pad.

Geschreven is pseudocode, bezierCurveTo zou er als volgt uitzien:

 bezierCurveTo (cp1x, cp1y, cp2x, cp2y, x, y);

Op hun eigen B? Zier paden zijn niet super geweldig, maar in combinatie met normale paden, of wanneer meerdere keren gebruikt, kunnen de resultaten behoorlijk diep zijn. Hiermee kunt u allerlei gecompliceerde en gekke vormen in canvas maken!

Misschien wilt u de Ai-> Canvas-plug-in voor Adobe Illustrator bekijken waarmee u uw fantasievectortekening als canvascode kunt exporteren. Het is best netjes en het bespaart je veel tijd!


Tekeningstatus

In het vorige artikel in deze reeks heb ik uitgelegd hoe je de stijl van vulling en lijn van het canvas kunt wijzigen en hoe je de lijndikte kunt wijzigen. Een van de problemen waar u rekening mee moet houden bij het wijzigen van deze eigenschappen, is dat u de kleuren en lijndikte handmatig opnieuw moet instellen als u de kleur of breedte wilt die u oorspronkelijk had. Gelukkig is er zoals altijd een betere manier om dit te doen; het wordt de tekenstatus genoemd.

De tekenstatus op canvas is in feite een stapel waarop u de huidige stijlen kunt opslaan en deze vervolgens op een later tijdstip kunt terugzetten.

Het is een omslachtig eenvoudig concept, maar een concept waarmee je zoveel kunt doen als je het volledig begrijpt. In feite bevat de tekentoestand een enorme hoeveelheid visuele informatie over het canvas, zoals de transformatiematrix, het knipgebied en de volgende eigenschappen; globalAlpha, globalCompositeOperation, strokeStyle, fillStyle, lijnbreedte, linecap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, schaduwkleur, doopvont, textAlign, en TextBaseline. De meeste hiervan zullen nieuw voor je zijn, dus maak je geen zorgen. Je leert over transformaties en andere leuke dingen zoals schaduwen in het volgende artikel.

De tekentoestand opslaan

Het gebruik van de tekenstand is doodeenvoudig, maar het volledig begrijpen ervan kan enige tijd duren. Vervang de code van de laatste sectie door het volgende:

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

Dat is echt alles wat u nodig hebt om de tekenstatus op te slaan: een enkele oproep naar de opslaan methode. Ik heb je gezegd dat het eenvoudig was!

Wat hier gebeurt, is dat je de opvulstijl van het canvas in blauw verandert en dan de tekenstatus opslaat, die de huidige staat op de stapel duwt waar ik het eerder over had. Standaard is de stapel trekstaten leeg.

Het is belangrijk om te onthouden dat de stapel net als een stapel papier op uw bureau werkt; het eerste item op de stapel is onderaan, met het nieuwste item bovenaan. Als je weer bij het eerste item wilt komen, moet je eerst alle items erboven verwijderen. Dit staat bekend als een first-in-out-out-systeem, of als 'first in first-out' als je het andersom wilt bekijken.

De tekeningstatus herstellen

Het opslaan van de staat van de tekening is geweldig en alles, maar eigenlijk is het weer een beetje nuttiger om het opnieuw te gebruiken. Om dat te doen, ga je het gebruiken herstellen methode.

Voeg de volgende code toe aan de bovenstaande code:

 ctx.fillStyle = "rgb (255, 0, 0)"; ctx.fillRect (200, 50, 100, 100);

Hiermee wordt een andere rechthoek op het canvas getekend, maar deze keer in een andere kleur (rood):

Allemaal vrij standaarddingen tot nu toe, maar wat als je terug wilt schakelen naar de blauwe kleur en een andere rechthoek wilt tekenen? Nou, je zou de opvulstijl handmatig als blauw kunnen instellen, maar dat zou saai zijn. Laten we proberen de herstelmethode te gebruiken en zien wat er gebeurt.

Voeg de volgende code toe:

 ctx.restore () ctx.fillRect (350, 50, 100, 100);

Hiermee wordt een andere rechthoek getekend, maar deze keer met de oorspronkelijke vulstijl:

Hoe gemakkelijk was dat? De oproep aan herstellen uitgehaald en de laatste tekenstatus verwijderd die aan de stapel is toegevoegd en vervolgens op het canvas is toegepast, waardoor u heel veel tijd hebt bespaard. Ok, nou, het heeft je in dit voorbeeld niet enorm veel tijd bespaard, maar je zou van alles van eigenschappen hebben veranderd en transformaties op het canvas hebben uitgevoerd.

Meerdere tekenstatussen gebruiken

U weet dus hoe u de tekenstatus voor één exemplaar kunt gebruiken, maar wat gebeurt er als u meerdere tekeningstatussen opslaat? Voor de scherpzinnige ogen zou je je kunnen herinneren dat ik de stapel noemde als een stapel papier; Laatste erin, eerste eruit. Laten we eens kijken hoe dit in code werkt.

Werk de vorige code bij om de tekenstatus op te slaan nadat u de vulstijl hebt ingesteld op rood:

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

Hoewel dit praktisch dezelfde code is als voorheen, is alles gewijzigd omdat de nieuwste tekeningstatus die aan de stapel is toegevoegd de rode opvulstijl bevat:

Als u de eerste status (de blauwe opvulstijl) wilt herstellen, moet u bellen herstellen voor een tweede keer, dus voeg de volgende code toe:

 ctx.restore (); ctx.fillRect (50, 200, 100, 100);

Hiermee wordt de eerste staat van de stapel verwijderd en verwijderd en op het canvas toegepast, waardoor u een blauwe opvulstijl krijgt:

Door meerdere tekenstatussen als deze te gebruiken, kunt u heel wat tijd besparen. Het is behoorlijk handig!


De dingen inpakken

Ik hoop dat ik door dit alles niet te snel ben gegaan. Sommige concepten die we hebben behandeld zijn behoorlijk geavanceerd en ik zou je willen aanmoedigen om het artikel opnieuw te lezen en met de code te spelen om een ​​beter inzicht te krijgen in wat er aan de hand is..

In het volgende artikel leert u hoe u transformaties op het canvas kunt uitvoeren en hoe u schaduwen en hellingen kunt gebruiken. Spannende tijden!