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 seconde partie, nous allons le convertir en un plugin jQuery, puis ajouter des améliorations et des fonctionnalités supplémentaires.
Conclure le Fun avec de la toile série en deux parties, nous allons créer un plugin de graphique à barres; pas un plug-in ordinaire, remarquez. Nous allons montrer un peu d'amour jQuery à l'élément canvas pour créer un plugin très robuste.
Dans la première partie, nous avons uniquement cherché à implémenter la logique du plug-in en tant que script autonome. À la fin de la première partie, notre graphique à barres ressemblait à.
Dans cette dernière partie, nous allons travailler sur la conversion de notre code et en faire un plugin jQuery approprié, en ajoutant quelques détails visuels et en incluant enfin des fonctionnalités supplémentaires. En fin de compte, notre sortie ressemblera à ceci:
Tout réchauffé? Permet de plonger dans!
Avant de commencer à convertir notre code en plugin, nous devons d'abord examiner quelques formalités concernant la création de plugins..
Nous commençons par choisir un nom pour le plugin. j'ai choisi graphique à barres et renommé le fichier JavaScript en jquery.barGraph.js. Nous enfermons maintenant tout le code de l'article précédent dans l'extrait suivant.
$ .fn.barGraph = fonction (paramètres) // code ici
Réglages contient tous les paramètres optionnels passés au plugin.
Dans la création de plug-in jQuery, il est généralement préférable d'utiliser jQuery au lieu de $ alias dans votre code, afin de minimiser les conflits avec d'autres bibliothèques Javascript. Au lieu de passer par tous ces problèmes, nous pouvons simplement utiliser des alias personnalisés, comme indiqué dans la documentation jQuery. Nous enfermons tout notre code de plug-in dans cette fonction anonyme à exécution automatique, comme indiqué ci-dessous:
(function ($) $ .fn.barGraph = function (paramètres) // code d'implémentation du plugin ici) (jQuery);
Essentiellement, nous encapsulons tout notre code dans une fonction et lui passons jQuery. Nous sommes libres d'utiliser le $ alias autant que nous le souhaitons dans notre code, sans avoir à nous soucier de son potentiel de conflit avec d'autres bibliothèques JavaScript..
Lors de la conception d'un plug-in, il est judicieux d'exposer un nombre raisonnable de paramètres à l'utilisateur, tout en utilisant des options par défaut raisonnables si les utilisateurs utilisent le plug-in sans lui transmettre aucune option. Dans cet esprit, nous allons permettre à l'utilisateur de modifier chacune des variables d'option de graphique que j'ai mentionnées dans cet article précédent de cette série. C'est facile. nous venons de définir chacune de ces variables en tant que propriétés d'un objet, puis d'y accéder.
var par défaut = barSpacing = 20, barWidth = 20, cvHeight = 220, numYlabels = 8, xOffset = 20, maxVal, gWidth = 550, gHeight = 200; ;
Nous devons enfin fusionner les options par défaut avec les options passées, en donnant la préférence à celles-ci. Cette ligne s'occupe de ça.
var option = $ .extend (valeurs par défaut, paramètres);
N'oubliez pas de changer les noms des variables si nécessaire. Un péché -
return (param * barWidth) + ((param + 1) * barSpacing) + xOffset;
… Change en:
return (param * option.barWidth) + ((param + 1) * option.barSpacing) + option.xOffset;
C'est là que le plugin est martelé. Notre ancienne implémentation ne pouvait produire qu'un seul graphique dans une page, et la possibilité de créer plusieurs graphiques dans une page est la raison principale pour laquelle nous créons un plugin pour cette fonctionnalité. De plus, nous devons nous assurer que l'utilisateur n'a pas besoin de créer un élément de canevas pour chaque graphique à créer. En gardant cela à l'esprit, nous allons créer les éléments de la toile de manière dynamique en fonction des besoins. Continuons. Nous examinerons les versions antérieures et mises à jour des parties pertinentes du code..
Avant de commencer, je voudrais préciser comment notre plugin sera appelé.
$ ("# années"). barGraph (barSpacing = 30, barWidth = 25, numYlabels = 12,);
Aussi simple que cela. années est l'ID de la table contenant toutes nos valeurs. Nous passons dans les options au besoin.
Pour commencer, nous avons d’abord besoin d’une référence à la source de données pour les graphiques. Nous accédons maintenant à l'élément source et obtenons son ID. Ajoutez la ligne suivante au groupe de variables graphiques que nous avons déclaré précédemment.
var dataSource = $ (this) .attr ("id");
Nous définissons une nouvelle variable et lui attribuons la valeur de l'attribut ID de l'élément transmis. Dans notre code, ce fait référence à l'élément DOM actuellement sélectionné. Dans notre exemple, cela fait référence à la table avec un ID de années.
Dans l’implémentation précédente, l’ID de la source de données était codé en dur. Nous le remplaçons maintenant par l’attribut ID extrait précédemment. La version précédente du grabValues fonction est ci-dessous:
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 ()););
Il est mis à jour pour ceci:
function grabValues () // Accède à la cellule de table requise, extrait et ajoute sa valeur au tableau de valeurs. $ ("#" + dataSource + "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. $ ("#" + dataSource + "tr td: nth-child (1)"). each (function () xLabels.push ($ (this) .text ()););
function initCanvas () $ ("#" + source de données) .after (""); // Essayez d'accéder à l'élément de structure cv = $ (" # bargraph - "+ dataSource) .get (0); if (! Cv.getContext) return; // Essayez d'obtenir un contexte 2D pour le canvas et renvoie une erreur si impossible ctx = cv.getContext ('2d'); if (! ctx) return;
Nous créons un élément canvas et l'injectons dans le DOM après la table, qui sert de source de données. jQuery's après la fonction est vraiment pratique ici. Un attribut de classe de graphique à barres et un attribut ID au format barGraph-dataSourceID est également appliqué pour permettre à l'utilisateur de les styler tous en groupe ou individuellement selon les besoins.
En fait, vous pouvez invoquer ce plugin de deux manières. Vous pouvez créer chaque graphe séparément en transmettant une seule source de données ou plusieurs sources. Dans ce dernier cas, notre construction actuelle rencontrera une erreur et quittera. Pour remédier à cela, nous utilisons le chaque construire pour parcourir l'ensemble des éléments passés.
(function ($) $ .fn.barGraph = fonction (paramètres) // Variables d’option var par défaut = // options ici; // Fusionner les paramètres passés avec les valeurs par défaut var option = $ .extend (valeurs par défaut, paramètres ); // // parcourt chaque objet transmis this.each (function () // Code d'implémentation ici); // Retourne l'objet jQuery pour permettre la chaîne. Return this;) (jQuery);
Nous encapsulons tout le code après avoir obtenu et fusionné les paramètres à l’intérieur du this.each construction. Nous nous assurons également de renvoyer l'objet jQuery à la fin pour permettre la chaînabilité.
Avec cela, notre refactoring est terminé. Nous devrions pouvoir invoquer notre plugin et créer autant de graphiques que nécessaire.
Maintenant que notre conversion est terminée, nous pouvons travailler à l'améliorer visuellement. Nous allons faire un certain nombre de choses ici. Nous allons examiner chacun d'eux séparément.
L'ancienne version utilisait un gris neutre pour dessiner les graphiques. Nous allons maintenant mettre en place un mécanisme de thématisation pour les barreaux. Cela, en soi, consiste en une série d'étapes.
var defaults = // Autres valeurs par défaut ici theme: "Ocean",;
Nous ajoutons un thème option aux valeurs par défaut permettant à l'utilisateur de changer le thème en l'un des quatre préréglages disponibles.
function grabValues () // commutateur de code précédent (option.theme) case 'Ocean': gTheme = thBlue; Pause; cas 'Feuillage': gTheme = thGreen; Pause; cas 'Fleur de cerisier': gTheme = thPink; Pause; case 'Spectrum': gTheme = thAssorted; Pause;
Un simple commutateur construire regarde le option.theme réglage et pointe le gTheme variable au tableau de couleurs nécessaire. Nous utilisons des noms descriptifs pour les thèmes au lieu de noms génériques.
// Thèmes var thPink = ['#FFCCCC', '# FFCCCC', '# FFC0C0', '# FFB5B5', '# FFADAD', '# FFA4A4', '# FF9A9A', '# FF8989', '# FF8989', '# FF8989', '# FF998D' ']; var thBlue = ['# ACE0FF', '# 9CDAFF', '# 90D6FF', '# 86D2FF', '# 7FCFFF', '# 79CDFF', '# 72CAFF', '# 6CC8FF', '# 57C0FF']]; var thGreen = ['# D1FFA6', '# C6FF91', '# C0FF86', '# BCFF7D', '# B6FF72', '# B2FF6B', '# AAFE5D', '# # A5FF51', '# 9FFF46']; var thAssorted = ['# FF93C2', '# FF93F6', '# E193FF', '# B893FF', '# 93A0FF', '# 93D7FF', '# 93F6FF', '# # ABFF93', '# FF9B93'];
Nous définissons ensuite un certain nombre de tableaux, chacun contenant une série de nuances d'une couleur spécifique. Ils commencent avec la teinte plus claire et continuent à augmenter. Nous allons parcourir ces tableaux plus tard. Ajouter des thèmes est aussi simple que d’ajouter un tableau pour la couleur spécifique dont vous avez besoin, puis de modifier la commutateur refléter les changements.
function getColour (param) return Math.ceil (Math.abs (((gValues.length / 2) -param))));
C'est une fonction minuscule qui nous permet d'obtenir et d'appliquer un dégradé comme un effet sur les graphiques. Essentiellement, nous calculons la différence absolue entre la moitié du nombre de valeurs à restituer et le paramètre passé, qui correspond à l'index de l'élément actuellement sélectionné dans le tableau. De cette façon, nous pouvons créer un dégradé lisse. Comme nous n’avons défini que neuf couleurs dans chacun des tableaux de couleurs, nous sommes limités à dix-huit valeurs par graphique. L'extension de ce nombre devrait être assez triviale.
function drawGraph () pour (index = 0; indexC’est là que nous avons effectivement thématisé les graphiques. Au lieu de définir une valeur statique à la fillStyle la propriété, nous utilisons le getColour fonction permettant de récupérer l'index nécessaire de l'élément dans le tableau du thème sélectionné.
Opacité
Ensuite, nous allons donner à l'utilisateur la possibilité de contrôler l'opacité des barres dessinées. Paramètres ceci est un processus en deux étapes.
Sans transparence
Avec une valeur de 0.8L'ajouter aux options
var defaults = // Autres valeurs par défaut ici barOpacity: 0.8,;Nous ajoutons un barOpacité option aux valeurs par défaut, permettant à l'utilisateur de changer l'opacité des graphiques en une valeur de 0 à 1, 0 étant complètement transparent et 1 complètement opaque.
Réglage du globalAlpha
function drawGraph () pour (index = 0; indexle globalAlpha property contrôle l'opacité ou la transparence de l'élément rendu. Nous définissons la valeur de cette propriété sur la valeur transmise ou sur la valeur par défaut pour ajouter un peu de transparence. Par défaut, nous utilisons une valeur de 0,8 pour le rendre légèrement transparent..
la grille
Une grille peut être extrêmement utile pour traiter les données présentées dans un graphique. Bien que je souhaitais au départ une grille correcte, je me suis ensuite tourné vers une série de lignes horizontales alignées avec les étiquettes de l’axe Y et j’ai complètement jeté les lignes verticales, puisqu’elles gênaient les données. Avec cela hors de propos, allons mettre en œuvre un moyen de le rendre.
Avec grille désactivée
Avec grille activéeCréation des lignes à l'aide de chemins et du lineto La méthode semblait être la solution la plus évidente pour dessiner les graphiques, mais il m'est arrivé de rencontrer un bogue de rendu qui rendait cette approche inappropriée. Je reste donc avec le fillRect méthode pour créer ces lignes aussi. Voici la fonction dans son intégralité.
function drawGrid () pour (index = 0; indexCela ressemble beaucoup au dessin des étiquettes d'axe Y, sauf qu'au lieu de rendre une étiquette, nous traçons une ligne horizontale couvrant la largeur du graphique avec une largeur de 1 px. le y la fonction nous aide dans le positionnement.
L'ajouter aux options
var defaults = // Autres valeurs par défaut ici disableGrid: false,;Nous ajoutons un disableGrid option aux valeurs par défaut, permettant à l’utilisateur de contrôler si une grille est rendue ou non. Par défaut, il est rendu.
// Appels de fonction if (! Option.disableGrid) drawGrid ();Nous vérifions simplement si l'utilisateur veut que la grille soit affichée et procédons en conséquence.
Grandes lignes
Maintenant que toutes les barres sont colorées, il manque d'accent sur un fond plus clair. Pour remédier à cela, nous avons besoin d’un coup de 1px. Il y a deux façons de faire ça. La première, et la plus simple, consisterait simplement à ajouter un strokeRect méthode à la drawGraph méthode; ou, nous pourrions utiliser le lineto méthode pour rapidement caresser les rectangles. J'ai choisi l'ancien itinéraire depuis avant lineto la méthode a jeté un bug de rendu bizarre sur moi.
Sans caresser
Avec caresserL'ajouter aux options
Nous l’ajoutons d’abord au défauts objet pour donner à l'utilisateur le contrôle de savoir si cela est appliqué ou non.
var defaults = // Autres valeurs par défaut ici showOutline: true,;function drawGraph () // Code précédent if (option.showOutline) ctx.fillStyle = "# 000"; ctx.strokeRect (x (index), y (gValues [index]), width (), height (gValues [index])); // Reste du codeNous vérifions si l'utilisateur veut rendre les contours et, si oui, nous procédons. C’est presque la même chose que de rendre les barres réelles, sauf qu’au lieu d’utiliser le fillRect méthode on utilise le strokeRect méthode.
Ombres
Dans l'implémentation d'origine, il n'y a pas de différenciation entre l'élément canvas et l'espace de rendu réel des barres. Nous allons corriger cela maintenant.
Sans ombrage
Avec ombragefonction shadeGraphArea () ctx.fillStyle = "# F2F2F2"; ctx.fillRect (option.xOffset, 0, gWidth-option.xOffset, gHeight);Ceci est une fonction minuscule qui ombrage la zone requise. Nous recouvrons l’élément de la toile moins la surface couverte par les étiquettes des deux axes. Les deux premiers paramètres pointent sur les coordonnées x et y du point de départ et les deux derniers sur la largeur et la hauteur requises. En commençant à option.offset, nous éliminons la zone couverte par les étiquettes de l'axe Y, et en limitant la hauteur à gHauteur, nous éliminons les étiquettes d'axe X.
Ajout de fonctionnalités
Maintenant que notre graphique est assez joli, nous pouvons nous concentrer sur l'ajout de nouvelles fonctionnalités à notre plugin. Nous allons regarder chacun séparément.
Considérez ce graphique des célèbres pics 8K.
Lorsque la valeur la plus élevée est suffisamment élevée et que la plupart des valeurs tombent à moins de 10% de la valeur maximale, le graphique cesse d’être utile. Nous avons deux façons de rectifier cela.
ShowValue
Nous allons commencer par la solution la plus facile. En reprenant la valeur des graphiques respectifs en haut, le problème est pratiquement résolu car les valeurs individuelles peuvent être facilement différenciées. Voici comment cela est implémenté.
var defaults = // Autres valeurs par défaut ici showValue: true,;Tout d'abord, nous ajoutons une entrée au défauts objet pour permettre à l'utilisateur d'allumer et d'éteindre à volonté.
// Appels de fonction if (option.showValue) drawValue ();Nous vérifions si l'utilisateur veut que la valeur soit affichée et procédons en conséquence.
function drawValue () pour (index = 0; indexNous parcourons le les valeurs tableau et rendre chaque valeur individuellement. Les calculs impliquant valAsString et valX ne sont que des calculs minuscules pour nous aider dans les empreintes correctes, de sorte qu'il ne semble pas hors de propos.
Échelle
C'est le plus difficile des deux solutions. Dans cette méthode, au lieu de commencer les étiquettes d’axe Y à 0, nous commençons beaucoup plus près de la valeur minimale. Je vais expliquer que nous allons. Notez que, dans l'exemple ci-dessus, la différence entre les valeurs suivantes par rapport à la valeur maximale est assez insignifiante et ne montre pas autant son efficacité. D'autres ensembles de données devraient faciliter l'analyse des résultats.
L'ajouter aux options
var defaults = // Autres valeurs par défaut ici scale: false;Mise à jour de la fonction d'échelle
Depuis le échelle La fonction faisant partie intégrante du processus de rendu, nous devons la mettre à jour pour permettre la mise à l'échelle. Nous le mettons à jour comme suit:
fonction scale (param) return ((option.scale)? Math.round (((param-minVal) / MaxVal-minVal)) * * gHeight): Math.round ((param / maxVal) * gHeight));Je sais que cela semble un peu compliqué, mais cela semble uniquement dû à l'utilisation de l'opérateur conditionnel ternaire. Essentiellement, nous vérifions la valeur de option.échelle et si elle dit faux, l'ancien code est exécuté. Si c'est vrai, au lieu de normaliser la valeur en fonction de la valeur maximale dans le tableau, nous la normalisons maintenant en fonction de la différence entre les valeurs maximale et minimale. Ce qui nous amène à:
Mise à jour du maxValues Une fonction
Nous devons maintenant déterminer à la fois la valeur maximale et la valeur minimale, par opposition à la valeur maximale auparavant. La fonction est mise à jour pour ceci:
fonction minmaxValues (arr) maxVal = 0; pour (i = 0; iparseInt (arr [i])) minVal = parseInt (arr [i]); maxVal * = 1.1; minVal = minVal - Math.round ((maxVal / 10)); Je suis sûr que vous pouvez accomplir la même chose en une seule boucle sans utiliser autant de lignes de code que moi, mais je me sentais particulièrement peu créatif à l'époque, alors supportez-moi. Les formalités de calcul étant réglées, nous émettons une augmentation de 5% du maxVal variable et à la minVal variable, on soustrait une valeur égale à 5% de maxVal valeur. Cela garantit que les barres ne touchent pas le haut à chaque fois et que les différences entre les étiquettes de l'axe Y sont uniformes..
Mise à jour du drawYlabels Une fonction
Avec tout le travail de base effectué, nous allons maintenant mettre à jour la routine de rendu du libellé de l’axe Y pour refléter la mise à l’échelle..
fonction drawYlabels () ctx.save (); pour (index = 0; indexMise à jour assez charnue si vous me demandez! Le noyau de la fonction reste le même. Nous vérifions simplement si l'utilisateur a activé la mise à l'échelle et dériver le code au besoin. Si activé, nous modifions la façon dont les étiquettes Y sont attribuées pour nous assurer qu'elles adhèrent au nouvel algorithme. Au lieu de la valeur maximale divisée en n nombres de nombres régulièrement espacés, nous calculons maintenant la différence entre la valeur maximale et la valeur minimale, la divisons en nombres uniformément espacés et l'ajoutons à la valeur minimale pour construire notre tableau d'étiquettes d'axe des ordonnées. Après cela, nous procédons normalement, en rendant chaque étiquette individuellement. Puisque nous avons rendu manuellement le plus bas 0 manuellement, nous devons vérifier si la mise à l'échelle est activée, puis restituer la valeur minimale à sa place. Ne vous occupez pas des petits ajouts numériques à chaque paramètre passé; il suffit de s'assurer que chaque élément du graphique s'aligne comme prévu.
Redimensionnement dynamique
Dans notre implémentation précédente, nous avions codé en dur les dimensions du graphique, ce qui présente des difficultés importantes lorsque le nombre de valeurs change. Nous allons rectifier cela maintenant.
L'ajouter aux options
var defaults = // Autres valeurs par défaut ici cvHeight: 250, // In px;Nous laissons l'utilisateur définir la hauteur de l'élément canvas seul. Toutes les autres valeurs sont calculées dynamiquement et appliquées au besoin.
Mise à jour du initCanvas Une fonction
le initCanvas function gère toute l'initialisation de la toile et doit donc être mis à jour pour implémenter la nouvelle fonctionnalité.
function initCanvas () $ ("#" + source de données) .after (""); // Essayez d'accéder à l'élément de structure cv = $ (" # bargraph - "+ source de données) .get (0); cv.width = gValues.length * (option.barSpacing + option.barWidth) + option.xOffset + option.barSpacing; cv.height = option.cvHeight; gWidth = cv.width; gHeight = option.cvHeight-20; if (! cv.getContext) return; // Essayez d'obtenir un contexte 2D pour le canevas et renvoie une erreur si impossible ctx = cv.getContext ('2d'); if (! ctx) return;Après avoir injecté l'élément canvas, nous obtenons une référence à l'élément créé. La largeur de l'élément canvas est calculée en fonction du nombre d'éléments dans le tableau. - les valeurs , l'espace entre chaque barre - option.barSpacing, la largeur de chaque barre elle-même - option.barWidth et enfin option.xOffset. La largeur du graphique change dynamiquement en fonction de chacun de ces paramètres. La hauteur est modifiable par l'utilisateur. La valeur par défaut est 220px, la zone de rendu correspondant à la barre étant de 220px. Le 20px est attribué aux étiquettes de l'axe X.
Cacher la source
Il est logique que l'utilisateur veuille masquer le tableau source une fois le graphique créé. En gardant cela à l’esprit, nous laissons l’utilisateur choisir de supprimer ou non la table..
var defaults = // Autres valeurs par défaut ici hideDataSource: true,;if (option.hideDataSource) $ ("#" + dataSource) .remove ();Nous vérifions si l'utilisateur veut masquer la table et si oui, nous la supprimons complètement du DOM en utilisant jQuery retirer méthode.
Optimiser notre code
Maintenant que tout le travail a été fait, nous pouvons examiner comment optimiser notre code. Étant donné que ce code a été entièrement écrit à des fins pédagogiques, la plupart des travaux ont été encapsulés sous forme de fonctions distinctes et, de plus, ils sont beaucoup plus verbeux que nécessaire..
Si vous voulez vraiment le code le plus léger possible, notre plug-in entier, à l'exclusion de l'initialisation et du calcul, peut être réécrit en deux boucles. Une boucle à travers le les valeurs tableau pour dessiner les barres elles-mêmes et les étiquettes de l'axe X; et la seconde boucle itérant de 0 à numYlabels pour rendre la grille et les étiquettes d'axe des ordonnées. Le code aurait l'air beaucoup plus salissant, cependant, il devrait conduire à une base de code considérablement plus petite.
Résumé
C'est ça les gars! Nous avons créé un plugin de haut niveau complètement à partir de zéro. Nous avons examiné un certain nombre de sujets de cette série, notamment:
- Regarder le schéma de rendu de l'élément canvas.
- Quelques méthodes de rendu de l'élément canvas.
- Normaliser des valeurs permettant de l'exprimer en fonction d'une autre valeur.
- Quelques techniques d'extraction de données utiles utilisant jQuery.
- La logique de base du rendu du graphique.
- Conversion de notre script en un plugin jQuery à part entière.
- Comment l’améliorer visuellement et l’étendre encore davantage au niveau des fonctionnalités.
J'espère que vous avez eu autant de plaisir à lire ceci qu'à mon écriture. Ceci étant un travail de 270 lignes, je suis sûr d’avoir omis quelque chose. Ne hésitez pas à frapper les commentaires et me demander. Ou me critiquer. Ou louez moi. Vous savez, c'est votre appel! Bonne codage!