Développement de diagrammes d'arbres dynamiques à l'aide de SVG et Vue.js

Le matériel, dont nous publions la traduction aujourd'hui, est consacré au processus de développement d'un système de visualisation pour les diagrammes d'arbres dynamiques. Pour dessiner des courbes de Bézier cubiques, la technologie SVG (Scalable Vector Graphics, scalable vector graphics) est utilisée ici. Le travail réactif avec les données est organisé par Vue.js.

Voici une version de démonstration du système avec laquelle vous pouvez expérimenter.


Graphique d'arbre interactif

La combinaison des puissantes fonctionnalités de SVG et du cadre Vue.js nous a permis de créer un système de construction de diagrammes basés sur des données, interactifs et personnalisables.

Un diagramme est un ensemble de courbes de Bézier cubiques commençant à un point. Les courbes se terminent en différents points équidistants les uns des autres. Leur position finale dépend des données saisies par l'utilisateur. En conséquence, le graphique est capable de réagir de manière réactive aux changements de données.

Tout d'abord, nous parlerons de la façon dont les courbes cubiques de Bézier sont formées, puis nous verrons comment les représenter dans le système de coordonnées de l'élément <svg> , et parler de la création de masques pour les images.

L'auteur du document dit qu'elle a préparé de nombreuses illustrations pour lui, en essayant de le rendre compréhensible et intéressant. Le but du matériel est d'aider chacun à acquérir les connaissances et les compétences nécessaires pour développer ses propres systèmes de schémas.

Svg


▍ Comment se forment les courbes de Bézier cubiques?


Les courbes utilisées dans ce projet sont appelées Cubic Bezier Curve. La figure suivante montre les éléments clés de ces courbes.


Éléments clés d'une courbe cubique de Bézier

La courbe est décrite par quatre paires de coordonnées. La première paire (x0, y0) est le point d'ancrage de départ de la courbe. La dernière paire de coordonnées (x3, y3) est le point de référence final.

Entre ces points, vous pouvez voir les soi-disant points de contrôle. C'est le point (x1, y1) et le point (x2, y2) .

L'emplacement des points de contrôle par rapport aux points de contrôle détermine la forme de la courbe. Si la courbe n'était définie que par les points de début et de fin, les coordonnées (x0, y0) et (x3, y3) , alors cette courbe ressemblerait à un segment droit situé en diagonale.

Nous allons maintenant utiliser les coordonnées des quatre points décrits ci-dessus pour tracer la courbe à l'aide de l'élément <path> SVG. Voici la syntaxe utilisée dans l'élément <path> pour construire des courbes de Bézier cubiques:

 <path D="M x0,y0 C x1,y1 x2,y2 x3,y3" /> 

La lettre , visible dans le code, est l'abréviation de Cubic Bezier Curve. La lettre minuscule ( c ) signifie l'utilisation de valeurs relatives, la majuscule ( C ) signifie l'utilisation de valeurs absolues. J'utilise des valeurs absolues pour construire le diagramme, cela est indiqué par la lettre majuscule utilisée dans l'exemple.

▍Création d'un diagramme symétrique


La symétrie est un aspect clé de ce projet. Pour construire un diagramme symétrique, j'ai utilisé une seule variable, recevant sur sa base des valeurs telles que la hauteur, la largeur ou les coordonnées du centre d'un certain objet.

Appelons cette size variable. Étant donné que le graphique est orienté horizontalement, la variable de size peut être considérée comme l'ensemble de l'espace horizontal disponible pour le graphique.

Attribuez à cette variable une valeur réaliste. Nous utiliserons cette valeur pour calculer les coordonnées des éléments du graphique.

 size = 1000 

Recherche des coordonnées des éléments du graphique


Avant de pouvoir trouver les coordonnées nécessaires pour construire le diagramme, nous devons traiter avec le système de coordonnées SVG.

▍Système coordonné et viewBox


L'attribut de l' <svg> viewBox très important dans notre projet. Le fait est qu'il décrit le système de coordonnées utilisateur de l'image SVG. Autrement dit, la viewBox détermine la position et la taille de l'espace dans lequel l'image SVG visible à l'écran sera créée.

L'attribut viewBox compose de quatre nombres qui spécifient les paramètres du système de coordonnées et les suivants dans cet ordre: min-x , min-y , width , height . Les paramètres min-x et min-y définissent l'origine du système de coordonnées utilisateur, les paramètres width et height définissent la largeur et la hauteur de l'image affichée. Voici à quoi pourrait ressembler l'attribut viewBox :

 <svg viewBox="min-x min-y width height">...</svg> 

La variable de size que nous avons décrite ci-dessus sera utilisée pour contrôler les paramètres de width et de height de ce système de coordonnées.

Plus tard, dans la section sur Vue.js, nous viewBox le viewBox à une propriété calculée pour spécifier les valeurs de width et de height . De plus, dans notre projet, les propriétés min-x et min-y seront toujours mises à 0.

Notez que nous n'utilisons pas les attributs de height et de width de l'élément <svg> lui-même. Nous allons les régler sur width: 100% et height: 100% utilisant CSS. Cela nous permettra de créer une image SVG qui s'adapte de manière flexible à la taille de la page.

Maintenant que le système de coordonnées utilisateur est prêt à dessiner un graphique, parlons de l'utilisation de la variable de size pour calculer les coordonnées des éléments du graphique.

▍ Coordonnées invariables et dynamiques



Concept graphique

Le cercle dans lequel le dessin est affiché fait partie du diagramme. C'est pourquoi il est important de l'inclure dans les calculs dès le début. À partir de l'illustration ci-dessus, recherchons les coordonnées du cercle et d'une courbe expérimentale.

La hauteur du graphique est divisée en deux parties. Ce sont topHeight (20% de la size ) et bottomHeight (les 80% restants de la size ). La largeur totale du diagramme est divisée en 2 parties - la longueur de chacune d'entre elles est de 50% de la size .

Cela rend la conclusion des paramètres du cercle ne nécessitant pas d'explications spéciales (ici, les indicateurs halfSize et topHeight sont utilisés). Le paramètre radius est défini sur la moitié de la valeur de topHeight . Grâce à cela, le cercle s'intègre parfaitement dans l'espace disponible.

Voyons maintenant les coordonnées des courbes.

  • Les coordonnées (x0, y0) définissent le point de référence de départ de la courbe. Ces coordonnées restent constantes tout le temps. La coordonnée x0 est le centre du graphique (la moitié de la size ) et y0 est la coordonnée à laquelle se termine le bas du cercle. Par conséquent, dans la formule de calcul de cette coordonnée, le rayon du cercle est utilisé. Par conséquent, les coordonnées de ce point peuvent être trouvées par la formule suivante : (50% size, 20% size + radius) .
  • Les coordonnées (x1, y1) sont le premier point de contrôle de la courbe. Il reste également inchangé pour toutes les courbes. Si nous n'oublions pas que les courbes doivent être symétriques, il s'avère que les valeurs de x1 et y1 toujours égales à la moitié de la valeur de size . D'où la formule de leur calcul: (50% size, 50% size) .
  • Les coordonnées (x2, y2) représentent le deuxième point de contrôle de la courbe de Bézier. Ici, x2 indique la forme de la courbe. Cet indicateur est calculé dynamiquement pour chaque courbe. Et l'indicateur y2 , comme précédemment, sera de moitié. D'où la formule suivante pour calculer ces coordonnées: (x2, 50% size) .
  • Les coordonnées (x3, y3) sont le point de référence final de la courbe. Cette coordonnée indique où vous souhaitez terminer le tracé de la ligne. Ici, la valeur de x3 , comme x2 , est calculée dynamiquement. Et y3 prend une valeur égale à 80% de la size . En conséquence, nous obtenons la formule suivante: (x3, 80% size) .

Nous réécrivons, en termes généraux, le code de l'élément <path> , en tenant compte des formules que nous venons de dériver. Les pourcentages utilisés ci-dessus sont présentés ici en les divisant par 100.

 <path d="M size*0.5, (size*0.2) + radius          C size*0.5, size*0.5           x2,    size*0.5           x3,    size*0.8" > 

Veuillez noter qu'à première vue, l'utilisation de pourcentages dans nos formules peut sembler facultative, basée uniquement sur mon propre avis. Cependant, ces valeurs ne sont pas appliquées sur un coup de tête, mais parce que leur utilisation aide à atteindre la symétrie et les proportions correctes du diagramme. Après avoir senti leur rôle dans la représentation graphique, vous pouvez essayer vos propres valeurs de pourcentage et examiner les résultats obtenus en les appliquant.

Parlons maintenant de la façon dont nous chercherons les coordonnées x2 et x3 . Ils vous permettent de créer dynamiquement de nombreuses courbes en fonction de l' index éléments dans le tableau correspondant.

La division de l'espace horizontal disponible du graphique en parties égales est basée sur le nombre d'éléments dans le tableau. Par conséquent, chaque pièce reçoit le même espace le long de l'axe x.

La formule que nous dérivons devrait ensuite fonctionner avec n'importe quel nombre d'éléments. Mais ici, nous allons expérimenter avec un tableau contenant 5 éléments: [0,1,2,3,4] . La visualisation d'un tel tableau signifie qu'il est nécessaire de tracer 5 courbes.

▍Trouver des coordonnées dynamiques (x2 et x3)


Tout d'abord, j'ai divisé la size par le nombre d'éléments, c'est-à-dire par la longueur du tableau. J'ai appelé cette distance variable. Il représente la distance entre deux éléments.

 distance = size/arrayLength // distance = 1000/5 = 200 

Puis j'ai parcouru le tableau et multiplié l'index de chacun de ses éléments ( index ) par la distance . Pour simplifier, j'appelle simplement x à la fois le paramètre x2 et le paramètre x3 .

 //  x2  x3 x = index * distance 

Si vous appliquez les valeurs obtenues lors de la construction du diagramme, c'est-à-dire utilisez la valeur x calculée ci-dessus pour x2 et x3 , cela aura l'air un peu étrange.


Le diagramme est asymétrique

Comme vous pouvez le voir, les éléments sont situés dans la zone où ils devraient être, mais le diagramme s'est révélé asymétrique. Il semble que dans sa partie gauche il y ait plus d'éléments qu'à droite.

Maintenant, je dois x3 valeur x3 au centre des segments correspondants, dont la longueur est définie à l'aide de la variable de distance .

Afin d'amener le diagramme à la forme dont j'ai besoin, j'ai simplement ajouté à x moitié de la valeur de la distance .

 x = index * distance + (distance * 0.5) 

En conséquence, j'ai trouvé le centre du segment de distance et y ai placé la coordonnée x3 . De plus, j'ai apporté à la forme que nous avons besoin de la coordonnée x2 pour la courbe n ° 2.


Diagramme symétrique

L'ajout de la moitié de la valeur de la distance aux coordonnées x2 et x3 rendu la formule de calcul de ces coordonnées appropriée pour visualiser des tableaux contenant un nombre pair et impair d'éléments.

▍ Masquage d'image


Nous avons besoin qu'une certaine image soit affichée en haut du diagramme, dans le cercle. Pour résoudre ce problème, j'ai créé un masque d'écrêtage contenant un cercle.

 <defs>  <mask id="svg-mask">     <circle :r="radius"             :cx="halfSize"             :cy="topHeight"             fill="white"/>  </mask> </defs> 

Ensuite, en utilisant la <image> de l'élément <image> <svg> <image> pour afficher l'image, j'ai lié l'image à l'élément <mask> créé ci-dessus en utilisant l'attribut mask de l'élément <image> .

 <image mask="url(#svg-mask)"      :x="(halfSize-radius)"      :y="(topHeight-radius)" ... > </image> 

Puisque nous essayons d'ajuster une image carrée dans une «fenêtre» ronde, j'ai ajusté la position de l'élément en soustrayant le paramètre de radius paramètres correspondants. En conséquence, l'image est visible à travers un masque réalisé sous la forme d'un cercle.

Rassemblons tout ce dont nous avons parlé dans un dessin. Cela nous aidera à voir le tableau d'ensemble de l'avancement des travaux.


Données utilisées dans le calcul des paramètres du graphique

Création d'une image SVG dynamique à l'aide de Vue.js


À ce stade, nous avons déterminé les courbes de Bézier cubiques et effectué les calculs nécessaires pour former le diagramme. Par conséquent, nous pouvons maintenant créer des diagrammes SVG statiques. Si nous combinons les capacités de SVG et Vue.js, nous pouvons créer des diagrammes pilotés par les données. Les diagrammes statiques deviendront dynamiques.

Dans cette section, nous révisons le diagramme SVG, le présentant comme un ensemble de composants Vue. Nous attacherons également des attributs SVG aux propriétés calculées et ferons en sorte que le graphique réponde aux modifications des données.

De plus, à la fin du projet, nous allons créer un composant qui est un panneau de configuration. Ce composant sera utilisé pour saisir les données qui seront transmises à la carte.

▍Lier des données aux paramètres viewBox


Commençons par ajuster le système de coordonnées. Sans cela, nous ne pourrons pas dessiner d'images SVG. La propriété viewbox calculée viewbox ce dont nous avons besoin en utilisant la variable de size . Il y aura quatre valeurs séparées par des espaces. Tout cela deviendra la valeur de l'attribut viewBox de l'élément <svg> .

 viewbox() {   return "0 0 " + this.size + " " + this.size; } 

En SVG, le nom de l'attribut viewBox déjà écrit en utilisant le style camel.

 <svg viewBox="0 0 1000 1000"> </svg> 

Par conséquent, afin de lier correctement cet attribut à la propriété calculée, j'ai noté le nom de l'attribut dans le style kebab et mis le modificateur .camel après. Avec cette approche, il est possible de "tromper" le HTML et d'implémenter correctement la liaison d'attribut.

 <svg :view-box.camel="viewbox">   ... </svg> 

Maintenant, lorsque vous modifiez la size graphique est reconfiguré indépendamment. Nous n'avons pas besoin de modifier manuellement la mise en page.

▍Calcul des paramètres de courbe


Étant donné que la plupart des valeurs nécessaires pour construire les courbes sont calculées sur la base d'une seule variable ( size ), j'ai utilisé pour trouver toutes les coordonnées fixes par les propriétés calculées. Ce que nous appelons ici "coordonnées fixes" est calculé sur la base de la size , et après cela, il ne change pas et ne dépend pas du nombre de courbes que le diagramme inclura.

Si vous changez la size - "les coordonnées fixes" seront recomptées. Après cela, ils ne changeront pas avant le prochain changement de size . Compte tenu de ce qui précède, voici cinq valeurs dont nous avons besoin pour tracer des courbes de Bézier:

  • topHeight — size * 0.2
  • bottomHeight — size * 0.8
  • width — size
  • halfSize — size * 0.5
  • distance — size/arrayLength

Il ne nous reste plus que deux valeurs inconnues - x2 et x3 . La formule de calcul que nous avons déjà dérivée:

 x = index * distance + (distance * 0.5) 

Pour trouver des valeurs spécifiques, nous devons remplacer les indices des éléments du tableau dans cette formule.

Maintenant, demandons-nous si la propriété calculée nous convient pour trouver x . Répondez brièvement à cette question, alors - non, cela ne suffira pas.

Impossible de transmettre des paramètres à la propriété calculée. Le fait est que c'est une propriété, pas une fonction. De plus, la nécessité d'utiliser un paramètre pour calculer quelque chose signifie qu'il n'y a aucun avantage tangible à utiliser des propriétés calculées en termes de mise en cache.

Veuillez noter qu'il existe une exception concernant le principe ci-dessus. Il s'agit de Vuex. Si vous utilisez des getters Vuex qui renvoient des fonctions, vous pouvez leur transmettre des paramètres.

Dans ce cas, nous n'utilisons pas Vuex. Mais même dans cette situation, nous avons deux façons de résoudre ce problème.

▍ Numéro d'option 1


Vous pouvez déclarer une fonction à laquelle l' index passé en argument et qui renvoie le résultat dont nous avons besoin. Cette approche semble plus propre si nous allons utiliser la valeur renvoyée par une fonction similaire à plusieurs endroits du modèle.

 <g v-for="(item, i) in itemArray">  <path :d="'M' + halfSize + ','     + (topHeight+r) +' '+            'C' + halfSize + ','     + halfSize +' '+                     calculateXPos(i) + ',' + halfSize +' '+                  calculateXPos(i) + ',' + bottomHeight"  /> </g> 

La méthode calculateXPos() effectuera des calculs à chaque appel. Cette méthode prend comme argument l'indice de l'élément - i .

 <script>  methods: {    calculateXPos (i)    {      return distance * i + (distance * 0.5)    }  } </script> 

Voici un exemple sur CodePen qui utilise cette solution.


Écran de la première variante d'application

▍ Option numéro 2


Cette option est meilleure que la première. Nous pouvons extraire le petit balisage SVG nécessaire pour construire la courbe dans un petit composant enfant séparé et lui passer l' index comme l'une des propriétés.

Avec cette approche, vous pouvez même utiliser la propriété calculée pour trouver x2 et x3 .

 <g v-for="(item, i) in items">    <cubic-bezier :index="i"                   :half-size="halfSize"                   :top-height="topHeight"                   :bottom-height="bottomHeight"                   :r="radius"                   :d="distance"     >     </cubic-bezier> </g> 

Cette option nous donne la possibilité de mieux organiser le code. Par exemple, nous pouvons créer un autre composant enfant pour le masque:

 <clip-mask :title="title"           :half-size="halfSize"           :top-height="topHeight"                               :r="radius"> </clip-mask> 

▍ Panneau de configuration



Panneau de configuration

Vous avez probablement déjà vu le panneau de configuration, appelé par le bouton situé dans le coin supérieur gauche de l'écran de l' exemple ci-dessus. Ce panneau facilite l'ajout d'éléments au tableau et leur suppression. En suivant les idées discutées dans la section "Option # 2", j'ai créé un composant enfant pour le panneau de configuration. Grâce à cela, le composant de niveau supérieur est propre et bien lisible. En conséquence, notre petite arborescence de composants Vue ressemble à celle ci-dessous.


Arborescence des composants du projet

Vous voulez jeter un œil au code qui implémente cette version du projet? Si oui, jetez un œil ici .


Écran de la deuxième variante d'application

Dépôt de projets


Voici le référentiel GitHub du projet ("Option # 2" est implémentée ici). Je pense qu'il vous sera utile de l'examiner avant de passer à la section suivante.

Devoirs


Essayez de créer le même diagramme que nous avons décrit ici, mais faites-le orienté verticalement. Profitez des idées décrites dans cet article.

Si vous pensez que c'est une tâche facile, que pour construire un tel diagramme il suffit d'échanger les coordonnées x et y , alors vous avez raison. Étant donné que le projet considéré ici n'a pas été créé comme universel, après avoir modifié les coordonnées là où vous en avez besoin, vous devrez également modifier le code en renommant certaines variables et méthodes.

Grâce à Vue.js, notre graphique simple peut être équipé de fonctionnalités supplémentaires. Par exemple, les éléments suivants:

  • Vous pouvez créer un mécanisme qui vous permet de basculer entre les modes de graphique horizontal et vertical.
  • Les courbes peuvent essayer d'animer. Par exemple, utiliser GSAP.
  • Vous pouvez ajuster les propriétés des courbes (disons - couleur et largeur de ligne) depuis le panneau de configuration.
  • Vous pouvez utiliser une bibliothèque externe pour organiser l'enregistrement des diagrammes dans n'importe quel format graphique ou sous forme de fichier PDF. Ces documents peuvent être téléchargés pour ceux qui travaillent avec le graphique.

Essayez ces devoirs. Et si vous avez des problèmes - ci-dessous sera donné un lien vers sa solution.

Résumé


L'élément <path> est l'une des puissantes fonctionnalités de SVG. Cet élément vous permet de créer diverses images avec une grande précision. Ici, nous avons compris comment les courbes de Bézier sont structurées et comment les mettre en pratique pour créer vos propres diagrammes.

, , JavaScript-. Vue.js . , , , , DOM. , — .

, , , , , Vue.js SVG. — , Vue.js. — .

, - , , , — .

Chers lecteurs! ?

Source: https://habr.com/ru/post/fr463329/


All Articles