SVG dans la vraie vie. Rapport Yandex

Bonjour, je m'appelle Artyom, je suis à la tête d'un des groupes de développement d'interfaces de Yandex. Il y a une semaine sur Ya. Subbotnik, j'ai expliqué comment nous utilisions SVG pour créer un calendrier interne. Ceci est une transcription de mon rapport, plusieurs histoires de la mise en œuvre du widget calendrier: mise à l'échelle, remplissage de motifs, masques, symboles et fonctionnalités de format.



- Il y a beaucoup de gens qui travaillent à Yandex, tous dans différentes villes, dans différents fuseaux horaires, et vous devez comprendre quand vos collègues sont occupés et quand vous pouvez les rencontrer et leur parler. Nous avons décidé de concevoir un calendrier qui vous aidera à le découvrir.

Nous avons commencé, bien sûr, par une mise en page. Il ressemblait à ceci:



Il montre des événements pairs et impairs avec des remplissages différents. Les événements qui chevauchent d'autres événements, c'est-à-dire, sont sur la deuxième couche - un autre remplissage. Des événements qui occupent toute la journée de la peinture toute la journée. L'heure actuelle est affichée ci-dessous. C'était le but.



Nous avons commencé à choisir sur quoi nous allons le faire. Réalisation de plusieurs prototypes différents. Nous avons commencé avec le canevas, mais il y avait beaucoup de code, évoluant manuellement pour écrire. Nous avons eu l'idée que le calendrier prend autant d'espace que nécessaire, dans différentes dispositions, il est de différentes formes et tailles. Et pour la toile, c'était compliqué.

Il y avait un prototype sympa lorsque nous avons généré toute cette image avec des dégradés linéaires, mais il s'est déplacé lors de la mise à l'échelle et lors du passage à la rétine. Par conséquent, à la fin, nous sommes arrivés à SVG. Pourquoi? Tout d'abord, il existe un système de coordonnées complètement indépendant du document, vous pouvez donc tout positionner complètement à l'intérieur, et cela ne se cassera pas quoi que ce soit. Il y a aussi un travail normal avec la mise à l'échelle. Même si vous zoomez dans le navigateur, si vous ouvrez la rétine ou étirez le calendrier d'une manière ou d'une autre, il se redimensionnera comme une image et dans tous les cas aura l'air normal. Nous avions un remplissage de cellule sur la mise en page, et c'est très bien que SVG ait un remplissage de motif.



Pour dessiner un calendrier, vous avez besoin de quelques données. Pour dessiner celui sur la mise en page, vous devez savoir à quelle date il commence - généralement la date actuelle - pour savoir combien de jours doivent être horizontaux, combien d'heures doivent être affichées verticalement et à quelle heure commence le jour sur le calendrier. Nous devons en quelque sorte obtenir des événements.

Étant donné que nous avons de nombreux bureaux dans différents fuseaux horaires, nous avons décidé que les événements arriveront toujours en UTC et nous les afficherons déjà sur le client pour les utilisateurs, car il est nécessaire de consulter le calendrier de notre fuseau horaire et du fuseau horaire de la personne, dont vous regardez l'agenda - pour comprendre qu'il fait nuit maintenant, et qu'il vaut mieux ne pas prendre de rendez-vous. Ce qui est surligné en rouge sera utilisé ultérieurement.



Commençons par les bases. SVG est un plan de coordonnées géant sur lequel des graphiques vectoriels peuvent être placés arbitrairement. Dans ce cas, la partie de la zone que nous voyons est déterminée par la viewBox, et ce qui est au-delà de ses limites est un tel débordement caché sur les stéroïdes. Quoi qu'il en soit, il ne sera pas visible. Nous avons décidé que pour simplifier les calculs, nous ferions un pixel du calendrier égal à une minute. Par conséquent, une heure occupera exactement 60 pixels. Pour le rendre encore plus simple, nous avons décidé que le jour en largeur serait également de 60 pixels - pour que tout soit carré, comme dans l'armée. Et ils ont commencé à composer.

La Viewbox est définie par quatre paramètres. Les deux premiers sont le point supérieur gauche du système de coordonnées, à partir duquel le viewBox est considéré, pour nous, il est de 0,0. La largeur est de 60 * pour le nombre de jours et la hauteur est de 60 * pour le nombre d'heures.

Il est valide d'insérer d'autres documents SVG à l'intérieur du SVG, qui auront leur propre système de coordonnées à l'intérieur. Et pour que les événements de la journée ne puissent être positionnés que le long de l'axe vertical, nous avons décidé que pour chaque jour, nous aurions un SVG distinct, et nous les déplacerions horizontalement de 60 * vers la position du jour dans le calendrier. Ensuite, tous les événements peuvent être simplement définis verticalement en Y, ce sera très pratique. Et à l'intérieur de chaque SVG, qui est un jour, nous mettons un rectangle qui affichera le remplissage de la journée.

Ce rectangle, car aucune couleur de remplissage n'est spécifiée, héritera de la propriété fill de SVG. Dans ce cas, cette journée fonctionne et deux jours par semaine de repos, ils sont donc inondés de lumière. Ceci est juste déterminé par les classes.



Il y a un blanc. Vous devez maintenant ajouter la grille. Comme nous voulions redimensionner le calendrier et que les lignes de la grille devraient toujours être à un seul pixel, nous avons utilisé l'attribut vector-effect = non-scaling-stroke. Cela conduit au fait que, peu importe la façon dont nous redimensionnons ou zoomons, il y aura toujours une grille à un pixel. Il suffit juste d'ajouter la bonne quantité de lignes horizontales et verticales, et il y aura une telle grille.



Nous avons trouvé la base, passons aux événements qui durent toute la journée. C'est une chose tellement délicate. Vous avez remarqué qu'il y a des événements sur les calendriers et il y a une coche «toute la journée». Ces événements sont différents en ce sens qu'ils se déroulent toute la journée, quel que soit le fuseau horaire que vous regardez. Par conséquent, si quelque part au tout début des fuseaux horaires en Alaska, l'événement commence tôt le matin, alors quelque part dans 48 heures à l'autre bout du globe, il continuera. Cela semble compliqué, mais il est plus facile à mettre en œuvre: il suffit de comparer la date avec la date du jour affiché. S'il frappe, cela signifie un événement ce jour-là. Si deux événements de la journée entière tombent le même jour, celui qui a commencé plus tard s'affiche. Alors remplissez montre les événements de toute la journée.



Avec d'autres événements, c'est un peu plus difficile. Il y a, disons, une réunion. Il est bleu, tout est simple. Cependant, si deux réunions se tiennent consécutivement, selon notre disposition, nous les remplissons de couleurs différentes, elles sont paires et impaires.

Si une réunion croise une autre, se situe plus haut, vous devez l'afficher d'une manière ou d'une autre. S'il y a des intersections avec des réunions, elles sont versées complètement séparément, dans des cellules. Et pour nous rendre encore plus amusant, nous avons non seulement des réunions, mais aussi des absences, des conférences, et beaucoup de tout cela. Je ne voulais pas coder en dur tout cela dans la mise en page, nous avons donc décidé de comprendre comment il est plus ou moins cross-browser et pratique à configurer en CSS.



Maintenant, il y aura l'exemple le plus difficile de tout le rapport, soyez patient et regardez, il y aura trois étapes, puis cela deviendra plus facile.

Commençons dans l'ordre. SVG a une balise <defs>, il vous permet de déclarer des éléments à l'intérieur qui ne sont pas affichés, mais vous pouvez les utiliser par référence, en vous référant à eux. La première chose que nous ferons est de déclarer <defs> et de créer un modèle dedans. <pattern> est une balise qui vous permet de déclarer un modèle que vous pouvez utiliser pour remplir un élément particulier avec un modèle particulier.

Nous devons créer des cellules dans ce modèle. Nous avons 60 par 60 pixels, les cellules doivent être 6 par 6, nous avons donc déclaré un motif 12 par 12 et dessiné un <path> à l'intérieur, comme dans le diagramme de gauche. Il a un attribut d, qui indique exactement comment la ligne se déplace. Il part du point 0,0, puis les coordonnées montrent les flèches comme il est dessiné. Si nous le remplissons de blanc, nous obtenons le modèle suivant: ce qui n'est pas inondé de blanc est inondé de noir.



Passez à l'étape suivante, déclarez maintenant le masque. <mask> est un tel élément en SVG qui vous permet d'ajouter un canal alpha à d'autres éléments. Ce qui est dessiné en noir dans le masque, dans cet élément auquel le masque est appliqué, est invisible, transparent. Ce qui est peint en blanc est opaque. Ce qui est gris est translucide. Nous avons un motif en noir et blanc, et nous allons ajouter un rectangle à l'intérieur du masque et le remplir avec ce motif. Maintenant, nous avons un masque.

L'étape suivante est <symbole>. Il s'agit d'une telle balise en SVG, qui vous permet de déclarer des graphiques réutilisables. Le plus souvent, les symboles sont utilisés, par exemple, pour les icônes. Et ici, nous déclarons un symbole, à l'intérieur duquel nous mettons deux rectangles. L'un ne remplit rien de sorte qu'il hérite de la propriété fill du parent SVG, et l'autre se remplit de currentColor et lui applique un masque. Nous allons maintenant avoir deux rectangles: l'un avec des trous et rempli de currentColor, et l'autre sans trous et rempli de remplissage. Et ils sont couchés les uns sur les autres. Si nous définissons ces couleurs de la même manière, nous obtiendrons un remplissage solide. Et si différent - des cellules. Tout est parti. Maintenant, vous pouvez simplement utiliser CSS et à travers les classes définir un remplissage arbitraire de deux couleurs pour tous les événements.



Vous devez maintenant déterminer exactement quels événements doivent être inclus dans le calendrier un jour donné. Nous avons un fuseau horaire de +3, dans lequel nous sommes tous assis, il a une échelle de 9 à 20 heures. Il y a aussi une personne qui s'assoit à Orenburg conditionnelle, elle a un fuseau horaire de +5, son échelle est décalée de deux heures par rapport à nous. Nous allons faire une projection sur UTC, et voir que sur UTC cet intervalle de haut en bas doit être affiché en bas afin que l'utilisateur puisse, en changeant de fuseau horaire, voir à la fois les événements qui tombent dans son calendrier et le calendrier de la personne qu'il regarde .

N'oubliez pas ces nombres, qui sont en décalage, car il est plus facile de positionner les événements qui arrivent en UTC dans le même UTC. Pour ce faire, nous prenons la balise <g>, qui désigne un groupe en SVG, et nous y positionnons tous les événements de manière absolue par UTC, et nous décalons <g> du nombre de pixels dont nous avons besoin pour afficher l'un ou l'autre fuseau horaire.



Pour résumer cette étude, nous obtenons que nous avons un symbole auquel nous nous référons, il y a un type d'événement, un niveau, une parité, il y a -120 minutes à partir du début de la journée en UTC et une durée de 30 minutes. En ajoutant tous les événements, nous obtenons une telle image.



L'heure actuelle se fait également simplement, ce sera une ligne avec le même effet de non-mise à l'échelle, de sorte qu'elle soit toujours à un seul pixel. Voici comment cela s'affiche.

Le temps ne s'arrête pas et il faut que la flèche bouge. La façon la plus cool que nous ayons trouvée est l'animation. Nous avons décidé que nous ferions une animation qui décalerait la flèche du nombre de minutes dans une journée, et le ferait en une journée. Et pour qu'il ne bouge pas constamment lentement, à savoir, en cochant une fois par minute, nous avons utilisé les étapes (). Et dès que nous l'avons ajouté, le temps a commencé à bouger. En même temps, en fait, puisque l'animation ne garantit pas qu'elle se déplacera constamment, elle est en retard, ou autre chose. Mais nos événements dans le calendrier sont mis à jour de temps en temps, et quelque part toutes les deux ou trois minutes ou lorsque l'utilisateur a quitté l'onglet et revient, le calendrier entier est redessiné et l'heure est mise à jour. Par conséquent, l'animation n'est visible que lorsque vous êtes assis et regardez attentivement si elle est en train de cocher ou non.



Il y a un problème. Ici, j'ai élargi un calendrier pour qu'il ressemble davantage à celui de la production. Il est devenu clair que les cellules n'étaient plus carrées. En effet, les proportions ne sont pas conservées et si nous étirons ou modifions physiquement le rapport hauteur / largeur, cela change comme dans l'image. Pour éviter cela, vous devez écrire un petit JS. Il y a le rapport d'aspect viewBox, qui était dans notre SVG d'origine, et le rapport d'aspect réel, qui est utilisé dans notre mise en page. Si vous trouvez le rapport de ces rapports et que vous le mettez ensuite dans la transformation du motif, les cellules deviendront carrées. Et aussi ce coefficient, que nous avons obtenu ici, peut être utilisé si nous voulons comprendre où l'utilisateur a cliqué. Étant donné que nous avons une minute dans le SVG d'origine égale à un pixel, puis par les coordonnées du clic multipliées par ce coefficient, nous pouvons comprendre l'heure que l'utilisateur a obtenue.



Il reste à ajouter du HTML pour qu'il y ait des lettres et des chiffres en haut. Obtenez un calendrier.



Donc, cette chose regarde en production à travers les yeux d'un utilisateur qui se trouve dans le fuseau horaire +5. Vous trouverez ci-dessous un interrupteur à bascule sur lequel mon collègue appuie et le calendrier se déplace dans les fuseaux horaires. Ensuite, il clique sur l'événement et voit que samedi dans le fuseau horaire +5, c'est-à-dire qu'en ce moment, mon rapport est activé.



Encore quelques exemples. Voici le calendrier du développeur, il a des stand-ups, plusieurs réunions régulières et c'est tout. Voici le calendrier du manager. Et voici le designer.

Utilisez CSS, utilisez SVG. Je vous remercie!

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


All Articles