Lerret fra grunnen Avansert tegning

I den forrige artikkelen i denne serien lærte du om lerretelementet, og grunnleggende for å tegne på det. I denne artikkelen skal jeg demonstrere noen av de mer avanserte tegnefunksjonene.


Setter opp

Vi bruker samme HTML-mal fra forrige artikkel; så åpne din favorittredaktør og lim inn i følgende kode:

    Lerret fra grunnen av          

Dette er ikke noe mer enn en grunnleggende HTML-side med en lerret element og noen JavaScript som kjører etter at DOM har lastet inn. Ingenting galt.


Tegnesirkler

I den siste artikkelen viste jeg deg hvordan du tegner grunnleggende former og stier; I denne delen skal jeg vise deg hvordan du tar ting et skritt videre og tegner sirkler. Det er ikke så enkelt som du kanskje tror, ​​men det er fortsatt ikke vanskelig i det hele tatt.

Det er ikke en metode i lerret som lar deg tegne en sirkel med en enkelt linje med kode, som hvordan fillRect Fungerer for rektangler. I stedet må du tegne sirkler med en sti ved hjelp av bue metode; en sirkel er bare en 360 graders lysbue. Årsaken til dette er at sirkler er faktisk veldig komplekse former, og bue Metoden gir mulighet for all slags kontroll over måten du tegner dem på. For eksempel vil du kanskje bare tegne en halvcirkel. De bue Metoden lar deg gjøre det. Du kan til og med kombinere bue Metode med standard rette baner for å tegne pizza skiver og kvart sirkler.

Jeg skal forklare hvordan bue Metoden fungerer kort, men for nå, la oss tegne en sirkel ved å legge til følgende kode under CTX variabel:

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

Dette vil tegne en sirkel plassert litt vekk fra øverst til venstre på lerretet:

Ser enkelt ut, ikke sant? Og det er, men la oss se nærmere på hva som skjer.

De bue Metoden har totalt seks argumenter:

  • Den første er x posisjon av opprinnelsespunktet (senterets sirkel).
  • Den andre er y posisjon av opprinnelsespunktet.
  • Den tredje er radius av sirkelen.
  • Den fremste er startvinkelen til sirkelen.
  • Den femte er sluttvinkelen til sirkelen.
  • Og sjette er retningen for å tegne buen (sant er mot klokken, og falsk er med urviseren)

Skrevet i pseudokode, bue ville se slik ut:

 bue (x, y, radius, startAngle, endAngle, mot urviseren);

De tre første argumentene er selvforklarende, som det er sist, men hva med start- og sluttvinkelen? La meg forklare.

Som nevnt tidligere, er sirkler bare 360 ​​graders buer. I lerret er en bue definert som en buet linje som starter på avstand fra et opprinnelsespunkt som er avstanden til radiusen. Den buede linjen begynner med vinkelen definert som startvinkelargumentet (den fremre), og fortsetter rundt omkretsen av en imaginær sirkel til den når vinkelen definert som endvinkelargumentet (den femte). Høres enkelt, rett?

Kanskje en illustrasjon vil bidra til å forklare situasjonen:

Det kan bli gal, men det gir mye mening når du er i stand til å få hodet rundt det.

Vinkler i lerret

På dette punktet er det sannsynligvis verdt å nevne at vinkler i lerret er gjort i radianer, ikke grader. Dette betyr at vinkler går fra 0 til pi multiplisert med to. Vinkler i lerret starter også fra høyre side, som det fremgår av illustrasjonen nedenfor:

Hvis du egentlig ikke liker radianer, kan du enkelt konvertere grader til radianer med følgende JavaScript-formel:

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

Denne formelen er død enkel, og det er ekstremt verdifullt hvis du vil avtale i grader.


Bier-stier

Arcs er morsomme og alle, men de er ganske begrensende for den slags kurver som kan opprettes med lerret. For noe mer komplekst, vil du begynne å se på B zier kurve metoder quadraticCurveTo, og bezierCurveTo. Disse metodene lar deg lage buede stier som har en radius som ikke er sentralt for kurven, og også å lage stier som har flere kurver.

Bier-baner bruker kontrollpunkter til å definere hvordan og hvor å tegne kurver. For eksempel, quadraticCurveTo har ett kontrollpunkt, mens bezierCurveTo har to. Sjekk ut følgende illustrasjon for å se hvordan kontrollpunktene påvirker måten en kurve tegnes på:

Hvis du har brukt et vektorbasert tegneprogram som Adobe Illustrator før, kan du allerede være komfortabel med slike kurver.

La oss hoppe inn og lage en kvadratisk B? Zier-bane. Erstatt bue-koden med følgende:

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

Dette vil tegne en buet sti som ser ut som den til venstre for illustrasjonen ovenfor:

De quadraticCurveTo metoden tar fire argumenter:

  • Den første er x posisjonen til kontrollpunktet.
  • Den andre er y posisjonen til kontrollpunktet.
  • Den tredje er x posisjon av enden av banen.
  • Og den andre er den y posisjon av enden av banen.

Skrevet i pseudokode, quadraticCurveTo ville se slik ut:

 quadraticCurveTo (cpx, cpy, x, y);

Startposisjonen til kurven er hvor banen ligger. For eksempel i koden ovenfor flyttet du starten på banen ved å ringe flytte til metode.

La oss gå opp på et nivå, og opprett en kubisk B? Zier-bane. Erstatt den forrige koden med følgende:

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

Dette vil tegne en buet sti som ser ut som den til høyre for illustrasjonen ovenfor:

De bezierCurveTo metoden tar seks argumenter:

  • Den første er x posisjon av det første kontrollpunktet.
  • Den andre er y posisjon av det første kontrollpunktet.
  • Den tredje er x posisjon for det andre kontrollpunktet.
  • Den frem er den y posisjon for det andre kontrollpunktet.
  • Den femte er den x posisjon av enden av banen.
  • Og den sjette er y posisjon av enden av banen.

Skrevet er pseudokode, bezierCurveTo ville se slik ut:

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

På egen hånd er Bier zier ikke helt fantastiske, men når de kombineres med normale baner, eller når de brukes flere ganger, kan resultatene være ganske dype. De lar deg lage alle slags kompliserte og sprø former i lerret!

Du vil kanskje sjekke ut Ai-> Lerret plugin for Adobe Illustrator som lar deg eksportere din fancy vektor tegning som lerretskode. Det er ganske pent, og vil spare deg for mye tid!


Tegningsstat

I den forrige artikkelen i denne serien, har jeg beskrevet hvordan du kan endre påfyllings- og slagtekstilen på lerretet, samt hvordan du endrer linjebredden. Et av problemene å være oppmerksom på når du endrer disse egenskapene, er at du må manuelt endre fargene og linjebredden igjen hvis du vil ha farge eller bredde som du opprinnelig hadde. Heldigvis er det som alltid en bedre måte å gjøre dette på; det kalles tegningstilstanden.

Tegningstilstanden i lerret er i hovedsak en stabel der du kan lagre de nåværende stilene, og deretter gjenopprette dem igjen på et senere tidspunkt.

Det er et deviously enkelt konsept, men en som lar deg gjøre så mye når du forstår det. Faktisk har tegningstilstanden en enorm mengde visuell informasjon om lerretet, som transformasjonsmatrisen, klipperegionen og de følgende egenskaper; globalAlpha, globalCompositeOperation, strokeStyle, fyllstil, linje bredde, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, font, Tekstjustering, og textBaseline. De fleste av disse vil være nye for deg, så ikke bekymre deg. Du lærer om transformasjoner og andre morsomme ting som skygger i neste artikkel.

Lagrer tegningstilstanden

Bruke tegningstilstanden er død enkel, men å forstå det fullt kan ta litt tid. Erstatt koden fra den siste delen med følgende:

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

Det er virkelig alt du trenger for å lagre tegningstilstanden: et enkelt anrop til lagre metode. Jeg fortalte deg at det var enkelt!

Det som skjer her er at du endrer fyllestilen til lerretet til blått og deretter lagrer tegningstilstanden, som skyver nåværende tilstand på stakken som jeg snakket om tidligere. Som standard er stakken med tegningstilstander tom.

Det er viktig å huske at stakken fungerer som en bunke på skrivebordet ditt; Det første elementet på bunken er nederst, med det nyeste produktet øverst. Hvis du vil komme til det første elementet igjen, må du først ta av alle elementene på toppen av det. Dette er kjent som en første i siste ut systemet, eller sist i første ut hvis du vil se på den den andre veien.

Gjenoppretter tegningstilstanden

Lagre tegningstilstanden er flott, og alt, men det er egentlig litt mer nyttig å bruke det igjen. For å gjøre det, skal du bruke restaurere metode.

Legg til følgende kode i koden ovenfor:

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

Dette vil tegne et annet rektangel på lerretet, men denne gangen i en annen farge (rød):

Alle ganske standard ting så langt, men hva om du vil bytte tilbake til den blå fargen og tegne et annet rektangel? Vel, du kan sette fyllestilen manuelt som blå, men det ville være kjedelig. La oss prøve å bruke gjenopprettingsmetoden og se hva som skjer.

Legg til følgende kode:

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

Dette vil tegne et annet rektangel, men denne gangen med den originale fyllestilen:

Hvor lett var det? Anropet til restaurere trukket ut og fjernet den siste tegningstilstanden som ble lagt til stabelen, og deretter påført den på lerretet, og sparer deg en hel masse tid. Ok, det har kanskje ikke spart deg en enorm tid i dette eksempelet, men det ville ha gjort at du endret alle slags egenskaper og utførte transformasjoner på lerretet.

Bruke flere tegningstilstander

Så du vet hvordan du bruker tegningstilstanden for en enkelt forekomst, men hva skjer hvis du lagrer flere tegningstilstander? For det skarpe øynet kan du huske at jeg henviste til stakken som en haug med papir; sist inn, først ut. La oss se hvordan dette fungerer i kode.

Oppdater den forrige koden for å lagre tegningstilstanden etter å ha satt fyllestilen til rød:

 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);

Selv om dette er praktisk talt samme kode som før, vil alt ha endret seg, siden den siste tegningstilstanden som ble lagt til stakken, inneholder den røde fyllestilen:

For å gjenopprette den første tilstanden (den blå fyllestilen), må du ringe restaurere for en gang, så legg til følgende kode:

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

Dette vil trekke og fjerne den første tilstanden fra stakken og legge den på lerretet, og gi deg en blå fyllestil:

Ved å bruke flere tegningstilstander som dette kan du lagre en hel masse tid. Det er ganske greit!


Innpakning Ting opp

Jeg håper at jeg ikke har gått for fort gjennom alt dette. Noen av konseptene vi har dekket er ganske avanserte, og jeg vil oppfordre deg til å lese artikkelen og spille rundt med koden for å få bedre forståelse av hva som skjer.

I neste artikkel lærer du hvordan du utfører transformasjoner på lerretet, samt hvordan du bruker skygger og gradienter. Spennende tider!