Distracție cu panza Creați un plugin de grafică în bara, partea 1

În această serie din două părți, vom combina elementul versatil de canvas cu biblioteca robustă jQuery pentru a crea un plugin pentru graficele de bare. În această primă parte, vom codifica logica de bază a plugin-ului ca versiune independentă.

Astăzi, vom crea un plugin pentru bare grafice. Nu este un plugin obișnuit. Vom arăta o dragoste jQuery cu elementul de panza pentru a crea un plugin foarte robust.

În acest articol din două părți, vom începe de la început prin implementarea logicii plugin-ului ca script independent, refăcând-o într-un plugin și adăugând în final toate bomboanele suplimentare de pe partea de sus a codului plugin-ului. În această primă parte, vom aborda numai implementarea logicii centrale.

Aveți nevoie de un exemplu înainte de a începe? Poftim!


Diferite grafice create cu furnizarea de setări diferite pentru plugin-ul nostru

Mulțumit? Interesat încă? Să începem.


Funcționalitate

Pluginul nostru trebuie să realizeze câteva lucruri de bază în timp ce nu face alte lucruri. Permiteți-mi să clarific:

  • Ca de obicei, vom utiliza doar elementul de panza și JavaScript. Nu există imagini de niciun fel, tehnici CSS rupte, fără preîncărcare. Element de panza vechi (sau este nou?), Împreună cu unele jQuery pentru a ușura volumul de muncă.
  • În ceea ce privește sursa de date, vom trage toate datele direct dintr-o masă standard. Nu există machete care să treacă pluginul la pornire. În acest fel, utilizatorul poate pune doar toate datele într-un tabel și apoi invocă plugin-ul nostru. În plus, este mult mai accesibil.
  • Nu există nicio marcare specială pentru tabelul care acționează ca sursă de date și cu siguranță nu există nume de clase speciale pentru celulele de date. Vom folosi doar ID-ul tabelului și vom trage toate datele de acolo.
  • Nu există o suprapunere de text subțire pentru redarea etichetelor și a acestora pe grafic. Nu este doar foarte obositoare, dar textul redat nu face parte din grafic atunci când este salvat. Vom folosi fillText și strokeText așa cum este definită de specificațiile WHATWG.

dependenţe

Pe măsură ce suntem înflăcărători în lumea tehnologiei de ultimă oră, care nu este pe deplin specificată, avem unele dependențe. Pentru ca elementul canvas să funcționeze, cele mai moderne browsere sunt suficiente. Dar, din moment ce facem uz de noul API de redare a textului, avem nevoie de construiri noi. Navigatorii care utilizează motorul Webkit r433xx și de mai sus sau motorul Gecko 1.9.1 și de mai sus ar trebui să fie platforme excelente pentru plugin. Vă recomandăm să luați o construcție de noapte Chromium sau Firefox.


Înainte de a începe

Aș dori să menționez că plugin-ul nostru este exclusiv în scopuri de învățare. Acest plugin nu este în nici un caz menit să înlocuiască alte plug-in-uri cu grafică completă precum Flot, Plotr și altele asemenea. De asemenea, codul va fi cât se poate de detaliat. Ai putea scrie departe, departe un cod mai eficient, dar de dragul învățării, totul va fi la fel de necomplicat. Simțiți-vă liber să o refacționați în favoarea eficienței codului dvs. de producție.


Marcajul HTML

   OMG WTF HAX   
An Vânzări
2009 130
2008 200
2007 145
2006 140
2005 210
2004 250
2003 170
2002 215
2001 115
2000 135
1999 110
1998 180
1997 105

Nimic special despre marcaj. Voi face oricum o scurtă trecere în revistă.

  • Începem prin includerea doctype-ului necesar. Din moment ce folosim elementul de panza, folosim cel corespunzător pentru HTML 5.
  • Tabelul sursă de date este apoi definit. Observă că nu este descris niciun marcaj special sau că sunt definite și atribuite noi clase în cadrul membrilor săi.
  • Se definește un element de panza și se atribuie apoi un cod de identificare pentru ao referi ulterior la acesta. Acest element specific de panza va fi disponibil numai pentru versiunea standalone. În versiunea pluginului, elementul canvas și atributele acestuia vor fi injectate dinamic în DOM și apoi manipulate după cum este necesar. Pentru îmbunătățirea progresivă, acest mod funcționează mult mai bine.
  • În final, includem biblioteca jQuery și scriptul personalizat. Așa cum Jeffrey a menționat de mai multe ori, inclusiv scripturile de la sfârșitul documentului este întotdeauna o idee bună.

Grilă de canvas

Înainte de a începe Javascript, permiteți-mi să explic sistemul de coordonate de pânză. Colțul din stânga sus acționează ca originea, adică (0, 0). Punctele sunt apoi măsurate cu privire la origine, cu x în creștere de-a lungul dreptului și y crescând de-a lungul stângii. Pentru înclinația matematică, lucrăm în mod efectiv în cadranul 4, cu excepția faptului că luăm valoarea absolută a y în loc de valoarea ei negativă. Dacă ați lucrat cu grafică în alte limbi, ar trebui să fiți acasă aici.


Sistemul de coordonate pentru panza

Rutina de redare a dreptunghiului

Rutina de randare a dreptunghiului canvasului va fi utilizată extensiv prin intermediul articolului pentru a reda barele, grila și alte elemente. Având în vedere acest lucru, să examinăm puțin aceste rutine.

Dintre cele trei rutine disponibile, vom folosi fillRect și strokeRect metode. fillRect metoda de fapt umple dreptunghiul rendered în timp ce strokeRect metoda numai loveste dreptunghiurile. În afară de aceasta, ambele metode iau aceiași parametri.

  • X - Coordonata x a punctului de unde să începeți desenul.
  • y - Coordonata y cu privire la origine.
  • lăţime - Definește lățimea dreptunghiului de tras.
  • înălţime - Definește înălțimea dreptunghiului.

Javascript Magic

Ca întotdeauna, vă recomandăm să descărcați codul sursă și să îl aveți pe o parte pentru referință. Este mai ușor să te uiți la imaginea de ansamblu și să analizezi fiecare funcție una câte una decât să privești fiecare funcție în parte și apoi să creezi imaginea de ansamblu în mintea ta.


Declarație variabilă

 Var barSpacing = 20, barWidth = 20, cvHeight = 220, numYlabels = 8, xOffset = 20, gWidth = 550, gHeight = 200; var maxVal, gValues ​​= [], xLabels = [], yLabels = []; var cv, ctx;

Grafic variabile

  • xLabels - O matrice care păstrează valoarea etichetelor axei X..
  • yLabels - La fel ca mai sus, cu excepția faptului că conține valorile etichetelor axei Y.
  • gValues - Arraia care conține toate datele din grafice, scoatem sursa de date.
  • CV - Variabilă pentru a indica spre elementul de panza.
  • CTX - Variabila pentru a se referi la contextul elementului de panza.

Variabile de opțiune grafică

Aceste variabile mențin valori codate greu pentru a ne ajuta în poziționarea și aspectul graficului și barelor individuale.

  • barSpacing - Definește distanța dintre barele individuale.
  • barWidth - Definește lățimea fiecărei bare individuale.
  • cvHeight - Definește înălțimea elementului de panza. Codificat greu de când am creat elementul de panza în prealabil. Versiunea Plugin variază în funcție de această funcție.
  • numYlabels - Definește numărul de etichete care urmează a fi desenate în axa Y.
  • xOffset - Definește spațiul dintre începutul elementului de panza și graficul real. Acest spațiu este utilizat pentru desenarea etichetelor axei Y.
  • gWidth, g Heights - Valorile codificate tari care dețin dimensiunea spațiului real de redare a graficului propriu-zis.

Modul în care fiecare variabilă controlează aspectul graficului

Prinde Valorile

Cu motorul selector al lui jQuery devine foarte ușor pentru noi să obținem datele de care avem nevoie. Aici avem o serie de modalități de accesare a elementelor necesare. Permiteți-mi să explic câteva dintre ele:

 $ ("tr") copii ("td: impar") fiecare (functie () // cod aici);

Cea mai simplă modalitate de a accesa rândurile necesare. Se caută a tr element și apoi accesează toate celelalte td element. Ea nu reușește atunci când aveți mai mult de un tabel pe pagină.

 $ ("# data") găsiți ("td: odd") fiecare (funcția () // code here);

O cale mult mai dreaptă. Trecem în ID-ul tabelului și apoi accesăm fiecare rând.

 $ ("# data tr td: impar") fiecare (functie () // cod aici);

La fel ca mai sus, cu excepția faptului că folosim doar sintaxa selectorului de stil CSS.

 $ ("# data tr td: nth-child (2)") fiecare (funcția () // cod aici);

Versiunea pe care o vom folosi astăzi. Acest mod este mult mai bine dacă trebuie să luăm datele dintr-un rând diferit sau, dacă este necesar, mai multe rânduri.

Versiunea finală arată astfel:

 funcția grabValues ​​() // Accesați celula de tabelă cerută, extrageți și adăugați valoarea acesteia la matricea valorilor. $ ("# data tr td: nth-child (2)") fiecare (functie () gValues.push ($ (this) .text ()); // Accesați celula de tabelă cerută, extrageți și adăugați valoarea acesteia la matricea xLabels. $ ("# date tr td: nth-child (1)") fiecare (functie () xLabels.push ($ (this) .text ()); 

Nimic nu este complicat aici. Utilizăm fragmentul de cod menționat mai sus pentru a adăuga valoarea celulei de tabelă la gValues matrice. Apoi, facem același lucru, cu excepția faptului că accesăm prima celulă de tabel pentru a extrage eticheta necesară pentru axa x. Am încapsulat logica extragerii de date la funcția proprie pentru reutilizarea și lizibilitatea codului.


Initializarea canvasului

 function initCanvas () // Incearca sa accesezi elementul canvas si sa arunci o eroare daca nu este disponibila cv = $ ("# graph"). get (0); dacă (! cv) retur;  // Încercați să obțineți un context 2D pentru panza și aruncați o eroare dacă nu puteți să ctx = cv.getContext ('2d'); dacă (! ctx) retur; 

Rutină initializare canvas. În primul rând încercăm să accesăm elementul de pânză în sine. Noi aruncăm o eroare dacă nu putem. În continuare, încercăm să obținem o referință la contextul de redare 2d prin getContext și aruncă o eroare dacă nu putem face acest lucru.


Funcții utilitare

Înainte de a intra în redarea reală a graficului în sine, trebuie să ne uităm la o serie de funcții de utilitate care ne ajută foarte mult în acest proces. Fiecare dintre ele este mică de la sine, dar va fi utilizată extensiv în codul nostru.

Determinarea valorii maxime

 funcția maxValues ​​(arr) maxVal = 0; pentru (i = 0; i 

O funcție mică care iterează prin matricea trecută și actualizează maxval variabil. Rețineți că umidem valoarea maximă cu 10% pentru scopuri speciale. Dacă valoarea maximă este lăsată ca atare, atunci bara reprezentând valoarea cea mai de sus va atinge marginea elementului de pânză pe care nu o dorim. În acest sens, se emite un increment de 10%.

Normalizarea valorii

 scară funcțională (param) retur Math.round ((param / maxVal) * gHeight); 

O funcție mică pentru a normaliza valoarea extrasă în raport cu înălțimea elementului de panza. Această funcție este utilizată extensiv în alte funcții și direct în codul nostru pentru a exprima valoarea în funcție de înălțimea pânzei. Are un singur parametru.

Întoarcerea Coordonatorului X

 funcția x (param) retur (param * barWidth) + (param + 1) * barSpacing) + xOffset; 

Returnează ordonata x la fillRect pentru a ne ajuta în poziționarea fiecărui bare individual. O să explic acest lucru mai detaliat când este folosit.

Returnează Coordonatul Y

 funcția y (param) întoarcere gHigh - scale (param); 

Returnează ordinul y la fillRect metodă pentru a ne ajuta în poziționarea fiecărei bare individuale. Mai multe explicații mai târziu.

Returnați lățimea

 lățimea funcției () return barWidth; 

Returnează lățimea fiecărei bare individuale.

Revenind la înălțime

 înălțimea funcției (param) scară înapoi (param); 

Returnează înălțimea barei de trasat. Utilizează scară funcția de a normaliza valoarea și apoi o returnează apelantului.


Desenarea etichetelor axei X

 funcția drawXlabels () ctx.save (); ctx.font = "10px" arial ""; ctx.fillStyle = "# 000"; pentru (indice = 0; index 

O funcție simplă pentru a face etichetele axei x. Salvăm mai întâi starea actuală a pânzei, inclusiv toate setările de randare, astfel încât tot ce facem în interiorul funcțiilor să nu scurgă niciodată. Apoi am setat dimensiunea și fontul etichetelor. Apoi, vom itera prin xLabels și apelați fillText de fiecare dată pentru a face eticheta. Noi folosim X pentru a ne ajuta în poziționarea etichetelor.


Desenarea etichetelor axei Y

 funcția drawYlabels () ctx.save (); pentru (indice = 0; index 

O funcție mai puțin verbală. Salvăm mai întâi starea actuală a pânzei și apoi continuăm. Apoi împărțim lui maxval valoare în n elemente în cazul în care variabila numYlabels dictează n. Aceste valori sunt apoi adăugate la yLabels matrice. Acum, așa cum am arătat mai sus, fillText se cere să se deseneze etichetele individuale cu y care ne ajută în poziționarea fiecărei etichete individuale.

Facem un zero în partea de jos a pânzei pentru a termina desenarea etichetelor Y..


Desenarea graficului

 funcția drawGraph () pentru (index = 0; index  

Funcția care atrage barele efective în graficul de bare. Iterate prin gValues și face fiecare bară individuală. Noi folosim fillRect pentru a desena barele. După cum sa explicat mai sus, metoda are patru parametri, fiecare dintre care este îngrijit de funcțiile noastre de utilitate. Indicele curent al buclă este trecut la funcțiile noastre ca parametri împreună cu valoarea reală deținută în matrice, după cum este necesar.

X funcția returnează coordonatul x al barei. De fiecare dată, este incrementat de valoarea sumei barWidth și barSpacing variabile.

y funcția calculează diferența dintre înălțimea elementului de panza și datele normalizate și o returnează. Știu că sună un pic turbionar, dar acest lucru se datorează faptului că valorile y pe grila de canvas cresc pe parcursul deplasării, în timp ce în graficul nostru valorile y cresc pe treaptă în sus. Astfel, trebuie să facem o mică lucrare pentru ao face să funcționeze așa cum dorim.

lăţime funcția returnează lățimea barelor individuale.

înălţime funcția returnează valoarea normalizată care urmează să fie folosită ca înălțimea barei care urmează să fie desenată.


rezumat

În această primă parte, am implementat logica de bază a plug-in-ului nostru ca versiune independentă cu aspectul și caracteristicile oaselor goale. Am analizat sistemul de coordonate de canvas, metodele de randare a dreptunghiului, unele extragere de date minuțioase folosind jQuery's awesomeness, am privit cum etichetele sunt desenate și, în cele din urmă, sa uitat la logica din spatele redării graficul în sine.

La sfârșitul acestui articol, rezultatul ar trebui să arate așa.


Urmatorul!

Actuala noastră punere în aplicare este destul de lipsită într-adevăr. Pare a fi neclintit, nu poate crea mai multe grafice pe aceeași pagină, și să o facem față, este mai degrabă spartan pe frontul caracteristicilor. Vom aborda toată săptămâna viitoare. În următorul articol vom:

  • Refactor codul nostru spre a face un plugin complet jQuery.
  • Adăugați niște bomboane ochi.
  • Includeți câteva caracteristici minunate.

Întrebări? Critici? Laudele? Simțiți-vă libertatea de a lovi comentariile. Vă mulțumim că ați citit și, când sunteți gata, treceți la partea a doua!

  • Urmăriți-ne pe Twitter sau abonați-vă la feed-ul RSS NETTUTS pentru mai multe tutoriale și articole zilnice de dezvoltare web.


Cod