Recréer le boutonpoussoir Arduino à l'aide de SVG et
Dans cet article, vous allez apprendre à créer des composants HTML personnalisés qui imitent des objets physiques, tels que le bouton-poussoir Arduino. Nous allons dessiner le composant dans Inkscape à partir de zéro, optimiser le code SVG généré pour le Web et l'envelopper comme un composant Web autonome en utilisant la bibliothèque légère lit-element
en accordant une attention particulière à l'accessibilité et à la convivialité mobile
Aujourd'hui, je vais vous emmener à travers le voyage de la création d'un composant HTML qui imite un composant bouton-poussoir momentané qui est couramment utilisé avec Arduino et dans les projets électroniques. Nous utiliserons des technologies telles que SVG, Web Components et lit-element
et apprendrons à rendre le bouton accessible grâce à une supercherie JavaScript-CSS.
Commençons!
D'Arduino à HTML: Le besoin d'un composant de bouton-poussoir
Avant de commencer le voyage, explorons ce que nous allons créer et, plus important encore, pourquoi. Je crée un simulateur Arduino open source en JavaScript appelé avr8js . Ce simulateur est capable d'exécuter du code Arduino et je vais l'utiliser dans une série de tutoriels et de cours qui enseignent aux fabricants comment programmer pour Arduino.
Le simulateur lui-même ne prend en charge que l'exécution du programme – il exécute l'instruction de code par et met à jour son état interne et un tampon mémoire selon la logique du programme. Pour interagir avec le programme Arduino, vous devez créer des composants électroniques virtuels qui peuvent envoyer des entrées au simulateur ou réagir à ses sorties.
L'exécution du simulateur seul est très similaire à l'exécution de JavaScript de manière isolée. Vous ne pouvez pas vraiment interagir avec l'utilisateur à moins de créer également des éléments HTML et de les accrocher au code JavaScript via le DOM.
Ainsi, en plus du simulateur du processeur, je travaille également sur une bibliothèque de composants HTML qui imitent le matériel physique, en commençant par les deux premiers composants que vous trouverez dans presque tous les projets électroniques: une LED et un bouton-poussoir.

La LED est relativement simple, car elle n'a que deux états de sortie: on et off. Dans les coulisses, il utilise un filtre SVG pour créer l'effet d'éclairage.
Le bouton-poussoir est plus intéressant. Il a également deux états, mais il doit réagir aux entrées des utilisateurs et mettre à jour son état en conséquence, et c'est de là que vient le défi, comme nous le verrons bientôt. Mais d'abord, clouons les exigences de notre composant que nous allons créer.
Définition des exigences pour le bouton-poussoir
Notre composant ressemblera à un bouton-poussoir de 12 mm. Ces boutons sont très courants dans les kits de démarrage électroniques et sont livrés avec des capuchons de plusieurs couleurs, comme vous pouvez le voir sur la photo ci-dessous:

En termes de comportement, le bouton poussoir doit avoir deux états: pressé et relâché. Ceux-ci sont similaires aux événements HTML mousedown / mouseup, mais nous devons nous assurer que les boutons poussoirs peuvent également être utilisés à partir d'appareils mobiles et sont accessibles aux utilisateurs sans souris.
Comme nous utiliserons l'état du bouton poussoir comme entrée pour Arduino, il n'est pas nécessaire de prendre en charge les événements "clic" ou "double clic". Il appartient au programme Arduino exécuté dans la simulation de décider comment agir sur l'état du bouton, et les boutons physiques ne génèrent pas d'événements de clic.
Si vous souhaitez en savoir plus, consultez une conférence que j'ai eue avec Benjamin Gruenbaum à SmashingConf Freiburg en 2019: « Anatomy of a Click ».
Pour résumer nos exigences, notre bouton-poussoir doit:
- ressembler au bouton-poussoir physique 12 mm;
- avoir deux états distincts: enfoncés et relâchés, et ils doivent être visuellement discernables;
- prennent en charge l'interaction avec la souris, les appareils mobiles et sont accessibles aux utilisateurs du clavier;
- prennent en charge différentes couleurs de capuchons (au moins rouge, vert, bleu, jaune,
Maintenant que nous avons défini les exigences, nous pouvons commencer à travailler sur l'implémentation.
SVG For The Win
La plupart des composants Web sont implémentés en utilisant une combinaison de CSS et HTML. Lorsque nous avons besoin de graphiques plus complexes, nous utilisons généralement des images raster, au format JPG ou PNG (ou GIF si vous vous sentez nostalgique).
Dans notre cas, cependant, nous utiliserons une autre approche: les graphiques SVG. SVG se prête beaucoup plus facilement aux graphiques complexes que CSS (oui, je sais, vous pouvez créer des choses fascinantes avec CSS, mais cela ne veut pas dire que cela devrait). Mais ne vous inquiétez pas, nous n'abandonnons pas entièrement le CSS. Cela nous aidera à styliser les boutons poussoirs, et même à les rendre accessibles.
SVG a un autre gros avantage, par rapport aux images graphiques raster: il est très facile à manipuler à partir de JavaScript et peut être stylisé via CSS. Cela signifie que nous pouvons fournir une seule image pour le bouton et utiliser JavaScript pour personnaliser le capuchon de couleur et des styles CSS pour indiquer l'état du bouton.
Enfin, SVG est juste un document XML, qui peut être édité avec des éditeurs de texte, et incorporé directement dans HTML, ce qui en fait une solution parfaite pour créer des composants HTML réutilisables. Êtes-vous prêt à dessiner notre bouton-poussoir?
Dessin du bouton-poussoir avec Inkscape
Inkscape est mon outil préféré pour créer des graphiques vectoriels SVG. Il est gratuit et regorge de fonctionnalités puissantes, telles qu'une grande collection de préréglages de filtre intégrés, de suivi de bitmap et d'opérations binaires de chemin. J'ai commencé à utiliser Inkscape pour créer de l'art PCB mais au cours des deux dernières années, j'ai commencé à l'utiliser pour la plupart de mes tâches d'édition graphique.
Dessiner le bouton-poussoir dans Inkscape est assez simple. Nous allons dessiner une illustration de dessus du bouton et de ses quatre fils métalliques qui le connectent à d'autres parties, comme suit:
- Rectangle gris foncé 12 × 12 mm pour le boîtier en plastique, avec des coins légèrement arrondis pour le rendre plus doux .
- Plus petit, 10,5 × 10,5 rectangle gris clair pour le couvercle en métal.
- Quatre cercles plus sombres, un dans chaque coin pour les broches qui maintiennent le bouton ensemble.
- Un grand cercle au milieu, c'est le contour du capuchon du bouton.
- Un petit cercle au milieu pour le haut du capuchon du bouton.
- Quatre rectangles gris clair en forme de "T" pour les fils métalliques du bouton.
Et le résultat, légèrement agrandi:
Comme touche finale, nous ajouterons un peu de magie de dégradé SVG à le contour du bouton, pour lui donner une sensation 3D:
Voilà! Nous avons les visuels, maintenant nous devons les obtenir sur le Web.
D'Inkscape au Web SVG
Comme je l'ai mentionné ci-dessus, les SVG sont assez simples à intégrer dans HTML – vous pouvez simplement coller le contenu du fichier SVG dans votre document HTML, ouvrez-le dans un navigateur et il sera affiché sur votre écran. Vous pouvez le voir en action dans l'exemple CodePen suivant:
Voir le stylo Bouton-poussoir SVG en HTML par @Uri Shaked
Cependant, les fichiers SVG enregistrés à partir d'Inkscape contiennent beaucoup de bagages inutiles tels que la version d'Inkscape et la position de la fenêtre lors de la dernière sauvegarde du fichier. Dans de nombreux cas, il y a aussi des éléments vides, des dégradés et des filtres inutilisés, et ils gonflent tous la taille du fichier, et rendent plus difficile de travailler avec lui dans HTML.
Heureusement, Inkscape peut nettoyer la majeure partie du désordre pour nous. Voici comment procéder:
- Allez dans le menu Fichier et cliquez sur Nettoyer le document . (Cela supprimera les définitions inutilisées de votre document.)
- Allez à nouveau dans Fichier et cliquez sur Enregistrer sous… . Lors de l'enregistrement, sélectionnez SVG optimisé ( *. Svg ) dans la liste déroulante Enregistrer sous le type .
- Vous verrez une boîte de dialogue «Sortie SVG optimisée» avec trois onglets. Cochez toutes les options, à l'exception de «Conserver les données de l'éditeur», «Conserver les définitions non référencées» et «Conserver les ID créés manuellement…».

La suppression de toutes ces choses créera un fichier SVG plus petit et plus facile à utiliser. Dans mon cas, le fichier est passé de 4593 octets à seulement 2080 octets, soit moins de la moitié de la taille. Pour les fichiers SVG plus complexes, cela peut être une énorme économie de bande passante et peut faire une différence notable dans le temps de chargement de votre page Web.
Le SVG optimisé est également beaucoup plus facile à lire et à comprendre. Dans l'extrait suivant, vous devriez être capable de repérer facilement les deux rectangles qui composent le corps du bouton poussoir:
Vous pouvez même raccourcir davantage le code, par exemple, en modifiant la largeur de trait du premier rectangle de 1.0003
à seulement 1
. Cela ne fait pas une différence significative dans la taille du fichier, mais il rend le code plus facile à lire.
En général, un passage manuel sur le fichier SVG généré est toujours utile. Dans de nombreux cas, vous pouvez supprimer des groupes vides ou appliquer des transformations matricielles, ainsi que simplifier les coordonnées du dégradé en les mappant de «l'espace utilisateur lors de l'utilisation» (coordonnées globales) à la «boîte englobante d'objet» (par rapport à l'objet). Ces optimisations sont facultatives, mais vous obtenez du code plus facile à comprendre et à gérer.
À partir de ce moment, nous allons ranger Inkscape et travailler avec la représentation textuelle de l'image SVG.
Création d'un composant Web réutilisable
Jusqu'à présent, nous avons obtenu les graphiques de notre bouton-poussoir, prêts à être insérés dans notre simulateur. Nous pouvons facilement personnaliser la couleur du bouton en modifiant l'attribut fill
du petit cercle et la couleur de départ du dégradé du plus grand cercle.
Notre prochain objectif est de transformer notre bouton-poussoir en un Composant Web réutilisable qui peut être personnalisé en transmettant un attribut de couleur
et réagit à l'interaction de l'utilisateur (événements de presse / relâchement). Nous utiliserons lit-element
une petite bibliothèque qui simplifie la création de composants Web.
lit-element
excelle dans la création de petites bibliothèques de composants autonomes. Il est construit en plus de la norme des composants Web, qui permet à ces composants d'être consommés par n'importe quelle application Web, quel que soit le cadre utilisé: Angular, React, Vue ou Vanilla JS pourraient tous utiliser notre composant.
Création de composants dans lit-element
se fait en utilisant une syntaxe basée sur une classe, avec une méthode render ()
qui renvoie le code HTML de l'élément. Un peu similaire à React, si vous le connaissez. Cependant, contrairement à react, lit-element
utilise le standard Javascript avec les littéraux de modèle balisés pour définir le contenu du composant.
Voici comment créer un simple bonjour- composant mondial
:
import {customElement, html, LitElement} de 'lit-element';
@customElement ('hello-world')
la classe d'exportation HelloWorldElement étend LitElement {
render () {
retourner html`
Bonjour le monde!
"
}
}
Ce composant peut ensuite être utilisé n'importe où dans votre code HTML en écrivant simplement
.
Remarque : En fait, notre bouton-poussoir nécessite juste un peu plus de code: nous devons déclarer une propriété d'entrée pour la couleur, en utilisant la décoratrice @property ()
(et avec une valeur par défaut de rouge), et collez le code SVG dans notre méthode render ()
en remplaçant le couleur du capuchon du bouton avec la valeur de la propriété color ( voir l'exemple ). Les bits importants se trouvent à la ligne 5, où nous définissons la propriété color: @property () color = 'red';
Aussi, à la ligne 35 (où nous utilisons cette propriété pour définir la couleur de remplissage du cercle qui fait la coiffe du bouton), en utilisant la syntaxe littérale du modèle JavaScript, écrite comme $ {color}
:
Making It Interactive
La dernière pièce du puzzle serait de faire le bouton interactif. Il y a deux aspects que nous devons considérer: la réponse visuelle à l'interaction ainsi que la réponse programmatique à l'interaction.
Pour la partie visuelle, nous pouvons simplement inverser la remplissage en dégradé du contour du bouton, ce qui créera l'illusion sur laquelle le bouton a été pressé:
Le dégradé pour le contour du bouton est défini par le code SVG suivant, où $ {color}
est remplacé par la couleur du bouton par lit-element
comme expliqué ci-dessus:
Une approche pour l'apparence du bouton pressé serait de définir un deuxième dégradé, d'inverser l'ordre des couleurs et de l'utiliser comme remplissage du cercle chaque fois que le bouton est pressé. Cependant, il existe une astuce intéressante qui nous permet de réutiliser le même dégradé: nous pouvons faire pivoter l'élément svg de 180 degrés à l'aide d'une transformation SVG:
L'attribut transform
indique à SVG que nous voulons faire pivoter le cercle de 180 degrés, et que la rotation doit se produire autour du point (6, 6) qui est le centre du cercle (défini par cx
et cy
). Les transformations SVG affectent également le remplissage de la forme, et donc notre dégradé sera également tourné.
Nous voulons uniquement inverser le dégradé lorsque le bouton est enfoncé, donc au lieu d'ajouter l'attribut transform
directement sur l'élément
comme nous l'avons fait ci-dessus, nous allons en fait définir une classe CSS pour cet élément, puis profiter du fait que les attributs SVG peuvent être définis via CSS, mais en utilisant une syntaxe légèrement différente: [19659093] transform: rotation (180deg);
origine de transformation: 6px 6px;
Ces deux règles CSS font exactement la même chose que la transformation
que nous avions ci-dessus – faire pivoter le cercle de 180 degrés autour de son centre en (6, 6). Nous voulons que ces règles soient appliquées uniquement lorsque le bouton est enfoncé, nous allons donc ajouter un nom de classe CSS à notre cercle:
Et maintenant nous pouvons utiliser la: pseudo-classe CSS active pour appliquer une transformation à la button-contour
chaque fois que l'élément SVG est cliqué:
svg: active .button-contour {
transformer: tourner (180deg);
origine de transformation: 6px 6px;
}
lit-element
nous permet d'attacher une feuille de style à notre composant en la déclarant dans un getter statique à l'intérieur de notre classe de composant, à l'aide d'un modèle littéral étiqueté:
static get styles () {
return css`
svg: active .button-contour {
transformer: tourner (180deg);
origine de transformation: 6px 6px;
}
"
}
Tout comme le modèle HTML, cette syntaxe nous permet d'injecter des valeurs personnalisées à notre code CSS, même si nous n'en avons pas besoin ici. lit-element
s'occupe également de créer le Shadow DOM pour notre composant, afin que le CSS n'affecte que les éléments de notre composant et ne saigne pas aux autres parties de l'application.
Maintenant, qu'en est-il du comportement programmatique du bouton lorsqu'il est pressé? Nous voulons déclencher un événement afin que les utilisateurs de notre composant puissent comprendre à chaque fois que l'état du bouton change. Une façon de le faire est d'écouter les événements mousedown et mouseup sur l'élément SVG et de déclencher les événements «bouton-presse» / «bouton-libération» en conséquence. Voici à quoi cela ressemble avec la syntaxe lit-element
:
render () {
const {color} = this;
retourner html`
"
}
Cependant, ce n'est pas la meilleure solution, comme nous le verrons sous peu. Mais d'abord, jetez un coup d'œil au code que nous avons obtenu jusqu'à présent:
import {customElement, css, html, LitElement, property} from 'lit-element';
@customElement ('wokwi-pushbutton')
la classe d'exportation PushbuttonElement étend LitElement {
@property () color = 'red';
styles get statiques () {
return css`
svg: active .button-contour {
transformer: tourner (180deg);
origine de transformation: 6px 6px;
}
"
}
render () {
const {color} = this;
retourner html`
»;
}
}
Vous pouvez cliquer sur chacun des boutons et voir comment ils réagissent. Le rouge a même des écouteurs d'événements (définis dans index.html ), donc quand vous cliquez dessus, vous devriez voir des messages écrits sur la console. Mais attendez, que se passe-t-il si vous souhaitez utiliser le clavier à la place?
Rendre le composant accessible et adapté aux mobiles
Hourra! Nous avons créé un composant de bouton-poussoir réutilisable avec SVG et élément éclairé
!
Avant de nous déconnecter de notre travail, nous devons examiner quelques problèmes. Tout d'abord, le bouton n'est pas accessible aux personnes qui utilisent le clavier. De plus, le comportement sur mobile est incohérent – les boutons semblent enfoncés lorsque vous maintenez votre doigt dessus, mais les événements JavaScript ne sont pas déclenchés si vous maintenez votre doigt pendant plus d'une seconde.
Commençons par aborder le clavier problème. Nous pourrions rendre le bouton accessible au clavier en ajoutant un attribut tabindex à l'élément svg, le rendant focalisable. Une meilleure alternative, à mon avis, consiste simplement à envelopper le bouton avec un élément standard. En utilisant l'élément standard, nous le faisons également jouer agréablement avec les lecteurs d'écran et d'autres technologies d'assistance.
Cette approche présente un inconvénient, comme vous pouvez le voir ci-dessous:

. ( Grand aperçu ) L'élément est livré avec un style intégré. Cela pourrait facilement être corrigé en appliquant du CSS pour supprimer ces styles:
bouton {
frontière: aucune;
fond: aucun;
rembourrage: 0;
marge: 0;
décoration de texte: aucune;
-apparence web: aucun;
-apparence moz: aucune;
}
bouton: actif .button-contour {
transformer: tourner (180deg);
origine de transformation: 6px 6px;
}
Notez que nous avons également remplacé le sélecteur qui inverse la grille du contour des boutons, en utilisant le bouton : actif
à la place de svg: actif
. Cela garantit que le style appuyé sur un bouton s'applique chaque fois que l'élément réel est enfoncé, quel que soit le périphérique d'entrée utilisé.
Nous pouvons même rendre notre composant plus convivial pour le lecteur d'écran en ajoutant un aria-label
attribut qui inclut la couleur du bouton:
Il y a encore une chose à résoudre: les événements de "pression de bouton" et de "libération de bouton". Idéalement, nous voulons les déclencher en fonction du CSS: pseudo-classe active du bouton, tout comme nous l'avons fait dans le CSS ci-dessus. En d'autres termes, nous aimerions déclencher l'événement «bouton-pression» chaque fois que le bouton devient : actif
et l'événement «bouton-relâchement» pour se déclencher chaque fois qu'il est : non (: actif
.
Mais comment écoutez-vous une pseudo-classe CSS à partir de Javascript?
Il s'avère que ce n'est pas si simple. J'ai posé cette question à la communauté JavaScript d'Israël et j'ai finalement trouvé une idée qui a fonctionné à partir du fil sans fin : utilisez le sélecteur : actif
pour déclencher une animation CSS super courte, puis je peux l'écouter à partir de JavaScript en utilisant l'événement animationstart
.
Une rapide expérience CodePen a prouvé que cela fonctionnait de manière fiable. Autant j'ai aimé la sophistication de cette idée, j'ai décidé d'aller avec une solution différente et plus simple. L'événement animationstart
n'est pas disponible sur Edge et iOS Safari, et le déclenchement d'une animation CSS uniquement pour détecter le changement de l'état du bouton ne semble pas être la bonne façon de faire les choses.
nous allons ajouter trois paires d'écouteurs d'événements à l'élément : mousedown / mouseup pour la souris, touchstart / touchend pour les appareils mobiles et keyup / keydown pour le clavier. Pas la solution la plus élégante, à mon avis, mais elle fait l'affaire et fonctionne sur tous les navigateurs.
Où SPACE_KEY
est une constante qui équivaut à 32, et vers le haut
/ vers le bas
sont deux méthodes de classe qui envoient le bouton-poussoir
et événements de libération de bouton
:
@property () pressé = faux;
privé vers le bas () {
si (! this.pressed) {
this.pressed = true;
this.dispatchEvent (nouvel événement ('bouton-pression'));
}
}
privé () {
si (this.pressed) {
this.pressed = false;
this.dispatchEvent (nouvel événement ('bouton-libération'));
}
}
- Vous pouvez trouver le code source complet ici .
Nous l'avons fait!
Ce fut un assez long voyage qui a commencé par définir les exigences et dessiner l'illustration du bouton dans Inkscape, est passé par la conversion de notre fichier SVG en un composant Web réutilisable en utilisant lit-element
et après nous être assuré qu'il est accessible et adapté aux mobiles, nous nous sommes retrouvés avec près de 100 lignes de code d'un délicieux composant de bouton-poussoir virtuel. [19659005] Ce bouton n'est qu'un composant unique dans une bibliothèque open-source de composants électroniques virtuels que je construis. Vous êtes invité à jeter un œil au code source ou à consulter le livre d'histoires en ligne où vous pouvez voir et interagir avec tous les composants disponibles.
Et enfin, si vous êtes intéressé dans Arduino, jetez un œil au cours de programmation Simon pour Arduino Je suis en train de construire, où vous pouvez également voir le bouton-poussoir en action.
Jusqu'à la prochaine fois, alors!
![Éditorial fracassant [19659137] (dm, il) </span data-recalc-dims=](https://i0.wp.com/blog.arcoptimizer.com/wp-content/uploads/2018/04/1523030185_12_frappez-le-terrain-en-courant-avec-vue-js-et-firestore-smashing-magazine.png?w=660)
Source link