Canvas de la zero transformări și înclinații

În acest articol, voi trece prin transformări în panza, precum și umbre și gradienți. Transformările sunt un set extrem de valoroasă de metode care vă permit să începeți să deveniți creativi cu modul în care desenați obiecte pe panza. Să începem după salt!


Configurare

Veți utiliza același șablon HTML din articolele anterioare, deschideți astfel editorul dvs. preferat și lipiți-l în următorul cod:

   Canvas de la zero          

Aici nu avem decât o pagină HTML de bază cu un pânză element și unele JavaScript care rulează după încărcarea DOM. Nimic nebun.


Traduceri în acțiune

Traducerea în esență schimbă întregul sistem de coordonate.

Una dintre cele mai simple transformări în panza este Traduceți. Aceasta vă permite să mutați punctul de origine al contextului de redare 2d; poziția (0, 0) de pe panza. Permiteți-mi să vă arăt ce înseamnă asta.

Mai întâi plasați un pătrat în panza la poziția (0, 0):

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

Se va desena la marginea din stanga sus a pânzei. Totuși, nimic neobișnuit aici.

Acum, încercați să traduceți contextul de redare 2d și să desenați un alt pătrat în aceeași poziție:

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

Ce crezi ca se va intampla? Aveți o stea de aur dacă ați ghicit că noul pătrat va fi tras la poziția (100, 100). Nu a jucat timp pentru cei care au ghicit greșit. scuze!

Deci, ce sa întâmplat aici? În ceea ce privește codul pentru desenarea celui de-al doilea pătrat, te-ai desenat în același loc ca primul pătrat. Motivul pentru aceasta este că ați schimbat practic întregul sistem de coordonate al pânzei astfel încât poziția sa (0, 0) să fie acum la locul (100, 100).

Are acum ceva mai mult sens? Așa sper. Poate dura ceva timp pentru a-ți lua capul, dar este un concept simplu când o înțelegi.

Probabil că nu ați folosi această transformare prea mult pe cont propriu, pentru că ați putea desena cel de-al doilea pătrat la (100, 100) pentru a obține același efect. Frumusețea lui Traduceți, deși este că o puteți combina cu alte transformări pentru a face niște lucruri destul de reci.

Să aruncăm o privire la următoarea transformare din listă.


Scalarea imaginilor voastre

Așa cum probabil ați ghicit, scară transformarea este utilizată pentru redimensionare. Mai precis, transformarea scării este utilizată pentru a scala contextul de redare 2d.

Eliminați codul cu care ați lucrat Traduceți exemplu și adăugați următorul cod:

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

Aceasta va desena un pătrat standard la poziția (100, 100), cu o lățime și înălțime de 100 de pixeli. Deci, cum să diminuăm acest lucru?

Proprietățile în scară sunt multiplicatori pentru dimensiunile x și y.

scară transformarea este utilizată într-un mod similar cu Traduceți, în sensul că se numește înainte de a desena obiectele pe care doriți să le aplicați. Este important să subliniem că proprietățile din scară sunt multiplicatori pentru X și y dimensiuni. Aceasta înseamnă că a scară din (1, 1) ar înmulți mărimea contextului de redare 2d cu unul, lăsându-l aceeași dimensiune ca înainte. A scară din (5, 5) va înmulți mărimea contextului de redare 2d cu cinci, făcându-l de cinci ori mai mare decât a fost anterior. Simplu.

În cazul tău, vrei să dublezi dimensiunea pătratului, deci aplici a scară din (2, 2):

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

Care rezultă într-un pătrat de două ori mai mare decât dimensiunea:

Cu toate acestea, observați cum este acum trasată pătratul într-o poziție diferită de cea în care a fost trasată înainte de a aplica scară. Motivul pentru asta este acela scară înmulțește mărimea totului în contextul de redare 2d, inclusiv coordonatele. În cazul tău, poziția (100, 100) devine acum (200, 200); coordonatele sunt de două ori mai mari decât cele pe care le vor fi fără a fi redimensionate.

Pentru a face acest lucru, putem efectua o Traduceți care mută originea contextului de redare 2d în poziția pe care doriți să o desenați. Dacă aplicați apoi scară și trageți pătratul în poziție (0, 0), poziția sa nu va fi schimbată:

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

Care rezultă într-un pătrat care este de două ori mai mare decât originalul, dar care este tras la aceeași poziție cu originalul:

Este conștient de aceste mici ciudățenii în transformări care chiar ajută la folosirea lor. Cele mai multe dintre problemele obișnuite cu transformările par a fi rezultatul faptului că nu înțeleg pe deplin modul în care funcționează.


Elemente rotative

Până acum, toate transformările pe care le-ați tratat au fost destul de inexplicabile. Din fericire, roti transformarea este aici pentru a salva ziua, și este cu ușurință preferatul meu din buchet.

sunt sigur roti nu are nevoie de introducere, așa că hai să mergem și să rotind un pătrat de 45 de grade (amintiți-vă că gradele trebuie să fie în radiani):

ctx.save (); ctx.rotate (Math.PI / 4); // Rotire 45 grade (în radiani) ctx.fillRect (100, 100, 100, 100); ctx.restore ();

Care poziționează un pătrat la (100, 100) și se rotește? Woah, stai! Acest lucru nu pare drept:

Vezi ce sa întâmplat? Pătratul pare să încerce să scape din fereastra browserului, mai degrabă decât să se rotească la fața locului la poziția (100, 100). Asta pentru ca roti, ca toate transformările, afectează întregul context de redare 2d, și nu obiecte în mod individual.

Iată o ilustrare a ceea ce se întâmplă cu sistemul de coordonate atunci când efectuați un grad de 45 de grade roti:

Observați cum întregul sistem de coordonate sa rotit la 45 de grade față de punctul de origine (0, 0)? Aceasta a determinat pătratul să arate ca și cum ar fi fost scos din fereastra browserului, pur și simplu pentru că poziția (100, 100) fusese rotită cu bârnă pe marginea browserului.

Modul simplu de a face față acestei probleme este de a combina roti cu Traduceți, ca astfel:

ctx.save (); ctx.translate (150, 150); // Traduceți în centrul paginii ctx.rotate (Math.PI / 4); // Rotiți 45 de grade ctx.fillRect (-50, -50, 100, 100); // Centru la punctul de rotație ctx.restore ();

Efectuarea Traduceți muta punctul de origine al contextului de redare 2d (0, 0) la ceea ce ar trebui să fie punctul central al pătratului (150, 150). Aceasta înseamnă că orice rotire se va baza acum în jurul poziției (150, 150). Dacă apoi trageți un pătrat cu un negativ X și y poziție, egală cu jumătate din lățimea și înălțimea pătratului, veți ajunge la desenarea unui pătrat care pare să fi fost rotit în jurul punctului său central:

roti transformarea este probabil cea mai grea dintre ei să înțeleagă pe deplin. Este important să rețineți că transformările sunt efectuate pe întregul context de redare 2d și, dacă doriți să rotiți o formă în jurul punctului său central, va trebui să combinați roti cu Traduceți.

Să trecem la ceva mai impresionant vizual.


Adăugarea de umbre

Adăugarea de umbre la obiecte este încântător de simplă.

Canvas vine livrat cu câteva proprietăți pentru a manipula aspectul obiectelor care sunt trase pe ea, și un set de aceste proprietăți vă permite să adăugați umbre.

Adăugarea de umbre la obiecte este încântător de simplă. Pur și simplu necesită shadowColor proprietatea care trebuie setată pe contextul de redare 2d într-o culoare care nu este transparentă negru și nici una dintre ele shadowBlur, shadowOffsetX, sau shadowOffsetY proprietățile să fie setate la o valoare diferită de 0.

Încercați următorul cod:

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

Acest lucru va oferi umbrei o estompare de cincisprezece pixeli și va seta culoarea pe negru solid:

Lucruri destul de standard până acum.

Dacă setați shadowBlur la 0, modificați shadowColor la un gri deschis, și dați un rezultat pozitiv shadowOffsetX și shadowOffsetY:

ctx.save (); ctx.shadowBlur = 0; ctx.shadowOffsetX = 6; ctx.shadowOffsetY = 6; ctx.shadowColor = "rgba (125, 125, 125, 0,5)"; // Ctx.fillRect gri transparent (300, 100, 100, 100); ctx.restore ();

Veți ajunge cu o umbra solidă care apare ușor în partea dreaptă și sub obiectul care a fost desenat:

Atât de cool ca umbrele, ele pot fi un pic de râs de resurse.

Este important să rețineți că umbrele afectează tot ce este desenat după ce acestea sunt definite, deci este util să utilizați Salvați și restabili metode pentru a vă salva de la necesitatea de a reseta proprietățile umbrelor după ce le-ați utilizat.

Rețineți că performanța poate suferi atunci când aplicați o umbră la o mulțime și la o mulțime de obiecte în același timp. În unele cazuri, ar putea fi util să utilizați o imagine PNG cu o umbră în loc să desenați manual un obiect și să aplicați o umbră dinamică folosind codul. Vom analiza modul de utilizare a imaginilor cu panza în următoarea tranșă din această serie.


Crearea declivităților

Puteți crea două tipuri de gradienți în panza - liniară și radială.

Ultimele caracteristici pe care vreau să le acordez în acest tutorial sunt gradienții. Există două tipuri de gradienți în panza, primele fiind gradienți liniari (drepți). Puteți crea un gradient liniar utilizând createLinearGradient (destul de surprinzător), care arată astfel în pseudo-cod:

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

Primul set de două argumente este X și y poziția începutului gradientului, iar al doilea set de argumente sunt X și y poziția sfârșitului gradientului. De asemenea, este important să subliniem că un gradient în panza este de fapt un tip de valoare a culorii, deci le aplicați la stil de completare și strokeStyle proprietăţi.

Iată un exemplu de cum se creează un gradient liniar care rulează din partea de sus a pânzei, până la capăt:

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

Observați cum asignați gradientul la o variabilă, apoi utilizați acea variabilă pentru a apela addColorStop metodă. Această metodă vă permite să setați culoarea în anumite puncte de-a lungul gradientului. De exemplu, poziția 0 ar reprezenta începutul gradientului (primul X și y poziție), iar 1 ar reprezenta sfârșitul gradientului (al doilea X și y poziţie). De asemenea, puteți utiliza puncte zecimale între 0 și 1 pentru a atribui o culoare într-un alt punct de-a lungul gradientului, cum ar fi 0,5 la jumătatea drumului.

Aplicând variabila gradient la stil de completare proprietate, ajungeți cu un gradient frumos, care trece de la alb (la poziția 0 în partea de sus a pânzei), până la negru (la poziția 1 în partea de jos a pânzei):

Dar nu trebuie întotdeauna să utilizați gradienți liniari; puteți crea și gradienți radiali!

Radierele radiale sunt create cu createRadialGradient metodă, care arată astfel în pseudo-cod:

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

Primul set de trei argumente este X și y poziția, precum și raza cercului la începutul gradientului, ultimele trei argumente reprezentând X și y precum și raza cercului la capătul gradientului.

Sunet confuz, nu? Este un pic, așa că hai să intrăm și să creăm un gradient radial pentru a vedea ce se întâmplă:

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 = gradient; ctx.fillRect (0, 0, canvas.width, canvas.height); ctx.restore ();

Ați creat un gradient radial care are un punct de pornire la (350, 350) cu o rază de 0 și un punct final la (50, 50) cu o rază de 100. Puteți ghici ce va arăta aceasta? 20 de puncte dacă ați ghicit că ar arăta astfel:

Dacă ești ceva ca mine, nu asta mă așteptam să văd. Am folosit gradienti radiali in aplicatii ca Adobe Photoshop si nu arata asa! Deci, de ce arata asa? Ei bine, asta ar trebui să arate, ciudat.

Consultați această diagramă care descrie exact cum funcționează un gradient radial în panza:

Interesant, nu-i așa? În principiu, vă permite să creați o formă de con, dar dacă doriți să creați un gradient radial adecvat, precum cel din Photoshop? Din fericire, este simplu.

Crearea unui gradient radial adecvat necesită doar plasarea celor două cercuri ale gradientului exact la fel X și y , asigurându-vă că unul dintre cercurile de gradient este mai mare decât celălalt:

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 = gradient; ctx.fillRect (0, 0, canvas.width, canvas.height); ctx.restore ();

Codul de mai sus creează un gradient radial care se află în centrul panzei. Una dintre cercurile în gradient are o rază de 0, în timp ce cealaltă are o rază de 250. Rezultatul este un gradient radial tradițional care se deplasează din centrul pânzei spre exterior, după cum urmează:

Asta arata mai bine! Am fost sincer uimită când am văzut cum au fost implementate gradiente radiale în pânză. Pun pariu că o mulțime de oameni s-au împiedicat atunci când văd forma conului. Ei bine, cel puțin știi cum să creezi cele potrivite acum.

Merită să subliniem faptul că gradientele din panza sunt, de asemenea, operații destul de intense. Dacă doriți să acoperiți întreaga pânză într-un gradient, aș face mai întâi să considerați aplicarea unui fundal gradient CSS3 la elementul canvas.


Înfășurarea în sus

În acest articol, am analizat modul de efectuare a transformărilor de bază pe panza, inclusiv traducerile, scalarea și rotația. De asemenea, ați învățat cum să adăugați umbre la obiecte și cum să creați gradienți. Nu sună prea mult, dar transformările, în special, formează coloana vertebrală a unora dintre cele mai tari lucruri care pot fi obținute în pânză.

În următoarea intrare din "Canvas from Scratch", vom renunța la desenarea obiectelor și vom arunca o privire asupra modului de a manipula imaginile și videoclipurile în panza. Acesta este locul unde lucrurile încep să devină cu adevărat interesante! Rămâneți aproape!

Cod