Divertimento con tela crea un plugin per grafici a barre, parte 1

In questa serie in due parti, combineremo l'elemento canvas versatile con la robusta libreria jQuery per creare un plug-in per grafici a barre. In questa prima parte, codificheremo la logica di base del plug-in come versione autonoma.

Oggi creeremo un plug-in per grafici a barre. Non un normale plugin, bada bene. Mostreremo un po 'di amore jQuery per l'elemento canvas per creare un plugin molto robusto.

In questo articolo in due parti, partiremo dall'inizio implementando la logica del plug-in come script autonomo, rifattiandolo in un plug-in e infine aggiungendo tutto il contenuto aggiuntivo sul codice del plug-in. In questa prima parte, ci occuperemo esclusivamente dell'attuazione della logica principale.

Hai bisogno di un esempio prima di iniziare? Ecco qui!


Diversi grafici creati con la fornitura di diverse impostazioni per il nostro plugin

Soddisfatto? Interessato ancora? Iniziamo.


Funzionalità

Il nostro plugin ha bisogno di realizzare alcune cose basilari pur non facendo alcune altre cose. Lasciatemi chiarire:

  • Come al solito, utilizzeremo solo l'elemento canvas e JavaScript. Nessuna immagine di alcun tipo, nessuna tecnica CSS spezzata, nessun prerendering. Plain old (o è nuovo?) Elemento canvas insieme ad alcuni jQuery per alleggerire il nostro carico di lavoro.
  • Per quanto riguarda l'origine dati, estrarremo tutti i dati direttamente da una tabella standard. Nessun array per passare il plug-in all'avvio. In questo modo l'utente può semplicemente mettere tutti i dati in una tabella e quindi richiamare il nostro plugin. Inoltre, è molto più accessibile.
  • Nessun markup speciale per la tabella che funge da origine dati e sicuramente nessun nome di classi speciali per le celle di dati. Utilizzeremo solo l'ID del tavolo e tireremo tutti i nostri dati da lì.
  • Nessuna sovrapposizione di testo fragile per il rendering delle etichette e simili sul grafico. Non è solo molto noioso, ma il testo renderizzato non fa parte del grafico quando viene salvato. Useremo il fillText e strokeText come definito dalle specifiche WHATWG.

dipendenze

Mentre stiamo esplorando il mondo della tecnologia all'avanguardia, non ancora completamente specificata, abbiamo alcune dipendenze. Perché l'elemento canvas funzioni, la maggior parte dei browser moderni è sufficiente. Ma poiché utilizziamo la nuova API di rendering del testo, abbiamo bisogno di build più recenti. I browser che utilizzano il motore Webkit r433xx e versioni successive o il motore Gecko 1.9.1 e versioni successive devono essere piattaforme eccellenti per il plug-in. Ti consiglio di prendere una build notturna di Chromium o Firefox.


Prima di iniziare

Mi piacerebbe ricordare che il nostro plugin è puramente a scopo di apprendimento. Questo plugin non è in alcun modo destinato a sostituire altri plugin grafici completi come Flot, Plotr e simili. Anche il codice sarà il più dettagliato possibile. Potresti scrivere lontano, lontano codice più efficiente ma per motivi di apprendimento, tutto sarà il più semplice possibile. Sentitevi liberi di refactoring in favore di efficienza nel codice di produzione.


Il markup HTML

   OMG WTF HAX   
Anno I saldi
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

Niente di speciale sul markup. Farò comunque una rapida panoramica.

  • Iniziamo includendo il doctype richiesto. Dato che stiamo usando l'elemento canvas, usiamo quello appropriato per HTML 5.
  • La tabella dell'origine dati viene quindi definita. Si noti che non viene descritto alcun markup speciale o che nuove classi vengono definite e assegnate all'interno dei suoi membri.
  • Un elemento canvas viene definito e quindi gli viene assegnato un ID per poterlo successivamente consultare. Questo specifico elemento canvas sarà qui solo per la versione standalone. Nella versione plug-in, l'elemento canvas e i relativi attributi verranno iniettati dinamicamente nel DOM e quindi modificati come necessario. Per il miglioramento progressivo, questo modo funziona molto meglio.
  • Infine, includiamo la libreria jQuery e il nostro script personalizzato. Come Jeffrey ha menzionato più e più volte, anche gli script alla fine del documento sono sempre una buona idea.

The Canvas Grid

Prima di avviare Javascript, permettimi di spiegare il sistema di coordinate del canvas. L'angolo in alto a sinistra funge da origine i.e. (0, 0). I punti vengono quindi misurati rispetto all'origine con x crescente lungo la destra e y crescente lungo la sinistra. Per i matematici inclini, stiamo effettivamente lavorando nel 4 ° quadrante eccetto che prendiamo il valore assoluto di y invece del suo valore negativo. Se hai lavorato con la grafica in altre lingue, dovresti essere a casa qui.


Il sistema di coordinate della tela

La routine di rendering di rettangolo

La routine di rendering del rettangolo di Canvas verrà utilizzata estesamente attraverso l'articolo per rendere le barre, la griglia e alcuni altri elementi. Con questo in mente, diamo un'occhiata a quelle routine.

Delle tre routine disponibili, useremo il fillRect e strokeRect metodi. Il fillRect il metodo riempie effettivamente il rettangolo renderizzato mentre il strokeRect il metodo accarezza solo i rettangoli. Oltre a questo, entrambi i metodi hanno gli stessi parametri.

  • X - La coordinata x del punto da cui iniziare a disegnare.
  • y - La coordinata y rispetto all'origine.
  • larghezza - Definisce la larghezza del rettangolo da disegnare.
  • altezza - Definisce l'altezza del rettangolo.

La magia Javascript

Come sempre, consiglio vivamente di scaricare il codice sorgente e averlo sul lato per riferimento. È più semplice guardare l'immagine grande e analizzare ciascuna funzione una per una, piuttosto che osservare singolarmente ciascuna funzione e quindi creare l'immagine generale nella tua mente.


Dichiarazione variabile

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

Variabili del grafico

  • xLabels - Una matrice che contiene il valore delle etichette dell'asse X..
  • yLabels - Come sopra, eccetto per il fatto che contiene i valori delle etichette dell'asse Y..
  • gValues - Array che contiene tutti i dati del grafico estratti dall'origine dati.
  • CV - Variabile da puntare verso l'elemento canvas.
  • CTX - Variabile per riferirsi al contesto dell'elemento canvas.

Variabili di opzione grafico

Queste variabili contengono valori codificati per aiutarci nel posizionamento e nel layout del grafico e delle singole barre.

  • barSpacing - Definisce la spaziatura tra le singole barre.
  • barWidth - Definisce la larghezza di ogni singola barra.
  • cvHeight - Definisce l'altezza dell'elemento canvas. Hard coded poiché abbiamo creato l'elemento canvas in anticipo. La versione del plugin varia in questa funzionalità.
  • numYlabels - Definisce il numero di etichette da disegnare nell'asse Y..
  • xOffset - Definisce lo spazio tra l'inizio dell'elemento canvas e il grafico attuale. Questo spazio è utilizzato per disegnare le etichette dell'asse Y..
  • gWidth, gHeight - Valori hard coded che mantengono la dimensione dello spazio di rendering effettivo del grafico stesso.

In che modo ciascuna variabile controlla l'aspetto del grafico

Afferrando i valori

Con il potente motore di selezione di jQuery diventa molto facile per noi ottenere i dati di cui abbiamo bisogno. Qui abbiamo un certo numero di modi per accedere agli elementi necessari. Lasciatemi spiegare alcuni di seguito:

 $ ("tr"). children ("td: odd"). each (function () // code here);

Il modo più semplice per accedere alle righe necessarie. Cerca a TR elemento e poi accede a vicenda TD elemento. Fallisce miseramente quando hai più di una tabella sulla tua pagina.

 $ ("# dati"). find ("td: odd"). each (function () // code here);

Un modo molto più diretto. Passiamo nell'ID del tavolo e poi accediamo a tutte le altre righe.

 $ ("# data tr td: odd"). each (function () // code here);

Come sopra, eccetto che usiamo solo la sintassi del selettore di stile CSS.

 $ ("# data trtd: nth-child (2)"). each (function () // code here);

La versione che useremo oggi. In questo modo è molto meglio se abbiamo bisogno di prendere i dati da una riga diversa o, se necessario, più righe.

La versione finale sembra così:

 function grabValues ​​() // Accede alla cella della tabella richiesta, estrae e aggiunge il suo valore alla matrice dei valori. $ ("# data tr td: nth-child (2)"). each (function () gValues.push ($ (this) .text ());); // Accede alla cella della tabella richiesta, estrae e aggiunge il suo valore alla matrice xLabels. $ ("# data trtd: nth-child (1)"). each (function () xLabels.push ($ (this) .text ());); 

Niente di complicato qui. Usiamo il frammento di codice di cui sopra per aggiungere il valore della cella di tabella al gValues array. Successivamente, facciamo lo stesso eccetto che accediamo alla prima cella della tabella per estrarre l'etichetta richiesta per l'asse x. Abbiamo incapsulato la logica di estrazione dei dati nella sua funzione per la riusabilità e la leggibilità del codice.


Inizializzazione della tela

 function initCanvas () // Prova ad accedere all'elemento canvas e genera un errore se non è disponibile cv = $ ("# graph"). get (0); se (! cv) return;  // Cerca di ottenere un contesto 2D per il canvas e genera un errore se non riesci a ctx = cv.getContext ('2d'); if (! ctx) return; 

Inizializzazione della tela di routine. Per prima cosa proviamo ad accedere all'elemento canvas stesso. Si genera un errore se impossibile. Quindi, proviamo ad ottenere un riferimento al contesto di rendering 2d attraverso il getContext metodo e genera un errore se non siamo in grado di farlo.


Funzioni di utilità

Prima di entrare nel rendering effettivo del grafico stesso, dobbiamo esaminare un certo numero di funzioni di utilità che ci aiutano enormemente nel processo. Ognuno di essi è piccolo da solo, ma sarà ampiamente utilizzato nel nostro codice.

Determinazione del valore massimo

 function maxValues ​​(arr) maxVal = 0; per (i = 0; i 

Una piccola funzione che itera attraverso l'array passato e aggiorna il MAXVAL variabile. Si noti che si gonfia il valore massimo del 10% per scopi speciali. Se il valore massimo viene lasciato così com'è, la barra che rappresenta il valore più alto toccherà il bordo dell'elemento canvas che non vogliamo. Con questo in mente, viene emesso un incremento del 10%.

Normalizzare il valore

 function scale (param) return Math.round ((param / maxVal) * gHeight); 

Una piccola funzione per normalizzare il valore estratto rispetto all'altezza dell'elemento canvas. Questa funzione è usata estensivamente in altre funzioni e direttamente nel nostro codice per esprimere il valore in funzione dell'altezza della tela. Prende un singolo parametro.

Restituzione della coordinata X.

 function x (param) return (param * barWidth) + ((param + 1) * barSpacing) + xOffset; 

Restituisce l'ordinata x al fillRect per aiutarci nel posizionamento di ogni singola barra. Lo spiegherò un po 'più in dettaglio quando verrà usato.

Restituzione della coordinata Y.

 funzione y (param) return gHeight - scale (param); 

Restituisce l'ordinata y al fillRect metodo per aiutarci nel posizionamento di ogni singola barra. Altre spiegazioni un po 'più tardi.

Tornando alla larghezza

 function width () return barWidth; 

Restituisce la larghezza di ogni singola barra.

Restituendo l'altezza

 altezza della funzione (param) return scale (param); 

Restituisce l'altezza della barra da disegnare. Usa il scala funzione per normalizzare il valore e quindi restituirlo al chiamante.


Disegnare le etichette dell'asse X.

 function drawXlabels () ctx.save (); ctx.font = "10px 'arial'"; ctx.fillStyle = "# 000"; per (indice = 0; indice 

Una semplice funzione per rendere le etichette dell'asse x. Per prima cosa salviamo lo stato attuale della tela, incluse tutte le impostazioni di rendering, in modo che tutto ciò che facciamo all'interno delle funzioni non si estenda mai. Quindi impostiamo la dimensione e il carattere delle etichette. Quindi, iteriamo attraverso il xLabels array e chiama il fillText metodo ogni volta per rendere l'etichetta. Noi usiamo il X funzione per aiutarci nel posizionamento delle etichette.


Disegnare le etichette dell'asse Y.

 function drawYlabels () ctx.save (); per (indice = 0; indice 

Una funzione un po 'più prolissa. Per prima cosa salviamo lo stato attuale della tela e poi procediamo. Quindi dividiamo MAXVAL di valore in n elementi in cui la variabile numYlabels detta il n. Questi valori vengono quindi aggiunti al yLabels array. Ora, come mostrato sopra, il fillText il metodo è chiamato per disegnare le singole etichette con il y funzione che ci aiuta nel posizionamento di ogni singola etichetta.

Rendiamo uno zero nella parte inferiore della tela per completare il disegno delle etichette Y..


Disegnare il grafico

 function drawGraph () for (index = 0; index  

La funzione che disegna le barre effettive nel grafico a barre. Attraversa il gValues matrice e rende ogni singola barra. Noi usiamo il fillRect metodo per disegnare le barre. Come spiegato sopra, il metodo prende quattro parametri, ognuno dei quali è curato dalle nostre funzioni di utilità. L'indice corrente del ciclo viene passato alle nostre funzioni come parametri insieme al valore effettivo contenuto nell'array, secondo necessità.

Il X la funzione restituisce la coordinata x della barra. Ogni volta, viene incrementato del valore della somma di barWidth e barSpacing variabili.

Il y la funzione calcola la differenza tra l'altezza dell'elemento canvas e i dati normalizzati e la restituisce. So che questo suona un po 'sdolcinato, ma questo è dovuto al fatto che i valori di y sulla griglia di tela aumentano quando ci si sposta verso il basso mentre nel nostro grafico i valori y aumentano al salire. Quindi, dobbiamo fare un piccolo lavoro per farlo funzionare nel modo che desideriamo.

Il larghezza la funzione restituisce la larghezza delle singole barre stesse.

Il altezza la funzione restituisce semplicemente il valore normalizzato che verrà utilizzato come altezza della barra da disegnare.


Sommario

In questa prima parte, abbiamo implementato la logica di base del nostro plug-in come versione standalone con l'aspetto e le funzionalità di bare bones. Abbiamo esaminato il sistema di coordinate del canvas, i metodi di rendering del rettangolo, un'elegante estrazione di dati usando l'innata meraviglia di jQuery [ho menzionato quanto mi piace jQuery?], Ho osservato come vengono disegnate le etichette e infine ho esaminato la logica dietro il rendering di il grafico stesso.

Alla fine di questo articolo, l'output dovrebbe apparire così.


Prossimo!

La nostra attuale implementazione è piuttosto carente. Sembra blando, non può creare più grafici sulla stessa pagina, e diciamocelo, è piuttosto spartano sul fronte delle funzionalità. Affronteremo tutto questo la prossima settimana. Nel prossimo articolo faremo:

  • Refactor il nostro codice per renderlo un plugin jQuery completo.
  • Aggiungi un po 'di piacere per gli occhi.
  • Include alcune piccole caratteristiche.

Domande? Critiche? Lodi? Sentiti libero di scrivere i commenti. Grazie per la lettura e, quando sei pronto, passa alla seconda parte!

  • Seguici su Twitter o iscriviti al feed RSS di NETTUTS per ulteriori tuts e articoli di sviluppo web giornalieri.