Fun With Canvas Créer un plugin de graphique à barres, 1ère partie

Dans cette série en deux parties, nous associerons l’élément de canevas polyvalent à la bibliothèque jQuery afin de créer un plug-in de graphique à barres. Dans cette première partie, nous allons coder la logique principale du plugin en tant que version autonome..

Aujourd'hui, nous allons créer un plugin de graphique à barres. Pas un plugin ordinaire, remarquez. Nous allons montrer un peu d'amour jQuery à l'élément canvas pour créer un plugin très robuste.

Dans cet article en deux parties, nous commencerons par implémenter la logique du plugin en tant que script autonome, en le refacturant dans un plugin, puis en ajoutant enfin tout le contenu supplémentaire au-dessus du code du plugin. Dans cette première partie, nous allons traiter uniquement de la mise en œuvre de la logique de base.

Besoin d'un exemple avant de commencer? Voici!


Différents graphiques créés en fournissant différents paramètres à notre plugin

Satisfait? Intéressé encore? Commençons.


La fonctionnalité

Notre plugin doit accomplir des tâches de base tout en ne faisant pas d’autres tâches. Laissez-moi élucider:

  • Comme d'habitude, nous n'utiliserons que l'élément canvas et JavaScript. Aucune image, aucune technique CSS brisée, aucun prérendering. Élément de toile simple (ou nouveau?) Avec quelques jQuery pour alléger notre charge de travail.
  • En ce qui concerne la source de données, nous allons extraire toutes les données directement d'un tableau standard. Aucune matrice à transmettre sur le plugin au démarrage. De cette façon, l'utilisateur peut simplement mettre toutes les données dans une table et ensuite appeler notre plugin. De plus, il est beaucoup plus accessible.
  • Pas de balisage spécial pour la table faisant office de source de données et certainement pas de noms de classes spéciales pour les cellules de données. Nous allons utiliser uniquement l'ID de la table et extraire toutes nos données à partir de là..
  • Pas de superposition de texte fragile pour le rendu des étiquettes et autres sur le graphique. Ce n'est pas seulement très fastidieux, mais le texte rendu ne fait pas partie du graphique lorsqu'il est enregistré. Nous allons utiliser le fillText et strokeText tel que défini par les spécifications du WHATWG.

Les dépendances

Alors que nous nous plongons dans le monde de la technologie de pointe, qui n’est pas encore complètement spécifiée, nous avons certaines dépendances. Pour que l’élément canvas fonctionne, la plupart des navigateurs modernes suffisent. Mais comme nous utilisons la nouvelle API de rendu de texte, nous avons besoin de nouvelles versions. Les navigateurs utilisant le moteur Webkit r433xx et supérieur ou le moteur Gecko 1.9.1 et supérieur devraient constituer d'excellentes plates-formes pour le plug-in. Je recommande de récupérer une version nocturne de Chromium ou de Firefox.


Avant de commencer

Je voudrais mentionner que notre plugin est purement à des fins d'apprentissage. Ce plugin n'est en aucun cas destiné à remplacer d'autres plugins graphiques à part entière comme Flot, Plotr et autres. En outre, le code sera aussi détaillé que possible. Tu pourrais écrire loin, loin un code plus efficace, mais dans un souci d’apprentissage, tout sera aussi simple que possible. N'hésitez pas à le refactoriser en faveur de l'efficacité dans votre code de production.


Le balisage HTML

   OMG WTF HAX   
Année Ventes
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

Rien de spécial à propos du balisage. Je ferai quand même un bref aperçu.

  • Nous commençons par inclure le doctype requis. Puisque nous utilisons l’élément canvas, nous utilisons celui qui convient pour HTML 5.
  • La table de source de données est ensuite définie. Remarquez qu'aucune balise spéciale n'est décrite ou que de nouvelles classes ne sont définies et attribuées à l'intérieur de ses membres.
  • Un élément de canevas est défini, puis un identifiant lui est attribué. Cet élément de canevas spécifique ne sera là que pour la version autonome. Dans la version du plugin, l’élément canvas et ses attributs seront injectés dynamiquement dans le DOM puis manipulés au besoin. Pour une amélioration progressive, cela fonctionne beaucoup mieux.
  • Enfin, nous incluons la bibliothèque jQuery et notre script personnalisé. Comme Jeffrey l’a mentionné à maintes reprises, il est toujours bon d’inclure des scripts à la fin du document..

La grille de toile

Avant de commencer le Javascript, laissez-moi vous expliquer le système de coordonnées de la toile. Le coin supérieur gauche sert d’origine, c’est-à-dire (0, 0). Les points sont ensuite mesurés par rapport à l'origine avec x croissant le long de la droite et y croissant le long de la gauche. Pour les inclinés mathématiquement, nous travaillons effectivement dans le 4ème quadrant, sauf que nous prenons la valeur absolue de y au lieu de sa valeur négative. Si vous avez travaillé avec des graphiques dans d'autres langues, vous devriez être chez vous ici.


Le système de coordonnées de la toile

La routine de rendu rectangle

La routine de rendu rectangle de Canvas sera largement utilisée dans l'article pour restituer les barres, la grille et certains autres éléments. Dans cet esprit, jetons un coup d'œil à ces routines.

Parmi les trois routines disponibles, nous utiliserons le fillRect et strokeRect méthodes. le fillRect méthode remplit effectivement le rectangle rendu tandis que la strokeRect La méthode ne trace que les rectangles. Autre que cela, les deux méthodes prennent les mêmes paramètres.

  • X - La coordonnée x du point à partir duquel commencer à dessiner.
  • y - La coordonnée y par rapport à l'origine.
  • largeur - Définit la largeur du rectangle à dessiner.
  • la taille - Définit la hauteur du rectangle.

La magie Javascript

Comme toujours, je vous recommande fortement de télécharger le code source et de l’avoir sur le côté pour référence. Il est plus facile de regarder la grande image et d'analyser chaque fonction une par une que de regarder chaque fonction individuellement puis de créer la grande image dans votre esprit..


Déclaration de variable

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

Variables graphiques

  • xLabels - Un tableau qui contient la valeur des étiquettes de l'axe X.
  • yLabels - Comme ci-dessus sauf qu'il contient les valeurs des étiquettes de l'axe Y.
  • les valeurs - Tableau contenant toutes les données de graphique extraites de la source de données.
  • CV - Variable pour pointer vers l'élément canvas.
  • ctx - Variable pour faire référence au contexte de l'élément canvas.

Variables d'option graphique

Ces variables contiennent des valeurs codées en dur pour nous aider dans le positionnement et la présentation du graphique et des barres individuelles..

  • barSpacing - Définit l'espacement entre les barres individuelles.
  • barWidth - Définit la largeur de chaque barre individuelle.
  • cvHauteur - Définit la hauteur de l'élément canvas. Codé en dur depuis que nous avons créé l’élément canvas à l’avance. La version du plugin varie dans cette fonctionnalité.
  • numYlabels - Définit le nombre d'étiquettes à dessiner sur l'axe Y.
  • xOffset - Définit l'espace entre le début de l'élément de canevas et le graphique réel. Cet espace est utilisé pour dessiner les étiquettes de l’axe Y.
  • gWidth, gHeight - Valeurs codées en dur contenant la dimension de l'espace de rendu réel du graphique lui-même.

Comment chaque variable contrôle l'apparence du graphique

Saisir les valeurs

Avec le puissant moteur de sélection de jQuery, il devient très facile d'obtenir les données dont nous avons besoin. Nous avons ici plusieurs moyens d’accéder aux éléments nécessaires. Laissez-moi vous expliquer quelques-unes ci-dessous:

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

Le moyen le plus simple d'accéder aux lignes nécessaires. Cherche un tr élément et accède ensuite à tous les autres td élément. Échec misérable quand vous avez plus d'une table sur votre page.

 $ ("# données"). find ("td: impair"). each (function () // code here);

Un chemin beaucoup plus simple. Nous passons l'ID de la table et accédons ensuite toutes les lignes.

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

Comme ci-dessus sauf que nous utilisons simplement la syntaxe de sélecteur de style CSS.

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

La version que nous allons utiliser aujourd'hui. Cette méthode est bien meilleure si nous devons extraire des données d’une autre ligne ou, si nécessaire, de plusieurs lignes..

La version finale ressemble à ceci:

 function grabValues ​​() // Accède à la cellule de table requise, extrait et ajoute sa valeur au tableau de valeurs. $ ("# data tr td: nth-child (2)"). each (function () gValues.push ($ (this) .text ());); // Accédez à la cellule de table requise, extrayez-la et ajoutez sa valeur au tableau xLabels. $ ("# data tr td: nth-child (1)"). each (function () xLabels.push ($ (this) .text ());); 

Rien de compliqué ici. Nous utilisons l'extrait de code mentionné ci-dessus pour ajouter la valeur de la cellule de tableau au les valeurs tableau. Ensuite, nous faisons la même chose, sauf que nous accédons à la première cellule du tableau afin d’extraire l’étiquette requise pour l’axe x. Nous avons encapsulé la logique d'extraction des données dans sa propre fonction pour permettre la réutilisation et la lisibilité du code..


Initialisation de la toile

 function initCanvas () // Essayez d'accéder à l'élément canvas et envoyez une erreur s'il n'est pas disponible cv = $ ("# graph"). get (0); si (! cv) return;  // Essayez d'obtenir un contexte 2D pour le canevas et émettez une erreur si vous ne pouvez pas ctx = cv.getContext ('2d'); si (! ctx) return; 

Initialisation de la toile de routine. Nous essayons d’abord d’accéder à l’élément canvas. Nous jetons une erreur si nous ne pouvons pas. Ensuite, nous essayons d’obtenir une référence au contexte de rendu 2D à travers le getContext méthode et jeter une erreur si nous sommes incapables de le faire.


Fonctions utilitaires

Avant d'entrer dans le rendu réel du graphique lui-même, nous devons examiner un certain nombre de fonctions utilitaires qui nous aident grandement dans le processus. Chacun d'eux est minuscule mais sera largement utilisé dans notre code.

Détermination de la valeur maximale

 fonction maxValues ​​(arr) maxVal = 0; pour (i = 0; i 

Une petite fonction qui parcourt le tableau passé et met à jour le maxVal variable. Notez que nous gonflons la valeur maximale de 10% à des fins spéciales. Si la valeur maximale est laissée telle quelle, la barre représentant la valeur la plus élevée touchera le bord de l'élément de la zone de travail que nous ne souhaitons pas. Dans cet esprit, une augmentation de 10% est émise.

Normaliser la valeur

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

Une petite fonction pour normaliser la valeur extraite par rapport à la hauteur de l'élément de la toile. Cette fonction est largement utilisée dans d'autres fonctions et directement dans notre code pour exprimer la valeur en fonction de la hauteur du canevas. Prend un seul paramètre.

Renvoyer la coordonnée X

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

Renvoie l'ordonnée x à la fillRect pour nous aider dans le positionnement de chaque barre individuelle. Je vais expliquer cela un peu plus en détail quand il est utilisé.

Renvoyer la coordonnée Y

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

Renvoie l'ordonnée y au fillRect méthode pour nous aider dans le positionnement de chaque barre individuelle. Plus d'explications un peu plus tard.

Retourner la largeur

 function width () return barWidth; 

Retourne la largeur de chaque barre individuelle.

Rendre la hauteur

 hauteur de la fonction (param) échelle de retour (param); 

Renvoie la hauteur de la barre à dessiner. Utilise le échelle fonction pour normaliser la valeur, puis la renvoie à l'appelant.


Dessin des étiquettes de l'axe X

 fonction drawXlabels () ctx.save (); ctx.font = "10px 'arial'"; ctx.fillStyle = "# 000"; pour (index = 0; index 

Une fonction simple pour rendre les étiquettes de l'axe x. Nous enregistrons d’abord l’état actuel de la zone de dessin, y compris tous les paramètres de rendu, de sorte que tout ce que nous faisons dans les fonctions ne fuit jamais. Ensuite, nous définissons la taille et la police des étiquettes. Ensuite, nous parcourons le xLabels tableau et appeler le fillText méthode à chaque fois pour rendre l'étiquette. Nous utilisons le X fonction pour nous aider dans le positionnement des étiquettes.


Dessin des étiquettes d'axe Y

 fonction drawYlabels () ctx.save (); pour (index = 0; index 

Une fonction légèrement plus verbeuse. Nous sauvegardons d’abord l’état actuel du canevas puis procédons. Ensuite nous divisons maxVal valeur en n éléments où la variable numYlabels dicte n. Ces valeurs sont ensuite ajoutées à la yLabels tableau. Maintenant, comme indiqué ci-dessus, le fillText méthode est appelée pour dessiner les étiquettes individuelles avec le y fonction nous aidant dans le positionnement de chaque étiquette individuelle.

Nous rendons un zéro au bas de la toile pour finir de dessiner les étiquettes Y.


Dessin du graphique

 function drawGraph () pour (index = 0; index  

La fonction qui dessine les barres réelles dans le graphique à barres. Itère à travers le les valeurs tableau et rend chaque barre individuelle. Nous utilisons le fillRect méthode pour dessiner les barres. Comme expliqué ci-dessus, la méthode utilise quatre paramètres, chacun étant pris en charge par nos fonctions utilitaires. L'index actuel de la boucle est transmis à nos fonctions sous forme de paramètres avec la valeur réelle conservée dans le tableau, si nécessaire..

le X function renvoie la coordonnée x de la barre. A chaque fois, il est incrémenté de la valeur de la somme de barWidth et barSpacing les variables.

le y function calcule la différence entre la hauteur de l’élément de la toile et les données normalisées et la renvoie. Je sais que cela semble un peu renversant, mais cela est dû au fait que les valeurs y sur la grille de la zone de dessin augmentent en descendant, alors que dans notre graphique, les valeurs y augmentent en remontant. Ainsi, nous devons faire un peu de travail pour le faire fonctionner comme nous le souhaitons..

le largeur fonction renvoie la largeur des barres individuelles elles-mêmes.

le la taille la fonction retourne simplement la valeur normalisée qui va être utilisée comme hauteur de la barre à tracer.


Résumé

Dans cette première partie, nous avons implémenté la logique de base de notre plug-in en tant que version autonome avec des aspects et des fonctionnalités de base. Nous avons examiné le système de coordonnées de la toile, les méthodes de rendu au rectangle, une extraction astucieuse de données à l’aide de la génialité innée de jQuery [Ai-je déjà dit combien j’aimais jQuery?], Avons examiné la façon dont les étiquettes sont dessinées et enfin la logique derrière le graphique lui-même.

À la fin de cet article, le résultat devrait ressembler à.


Prochain!

Notre mise en œuvre actuelle manque vraiment vraiment. Il semble fade, ne peut pas créer plusieurs graphiques sur la même page, et avouons-le, est plutôt spartiate au niveau des fonctionnalités. Nous allons aborder tout cela la semaine prochaine. Dans le prochain article, nous allons:

  • Refactoriser notre code pour en faire un plugin à part entière de jQuery.
  • Ajouter des bonbons pour les yeux.
  • Inclure quelques petites fonctionnalités astucieuses.

Des questions? Des reproches? Des louanges? Ne hésitez pas à frapper les commentaires. Merci d'avoir lu et, lorsque vous êtes prêt, passez à la deuxième partie!

  • Suivez-nous sur Twitter ou abonnez-vous au fil RSS NETTUTS pour plus d'articles et de sujets sur le développement Web quotidiens.