Composants de page Web SVG pour l'IoT et les créateurs (Partie 1)
Publié: 2022-03-10Le marché de l'IoT en est encore à ses débuts, mais prend de l'ampleur. Nous sommes à un tournant dans l'histoire de l'IdO. Les marchés quadruplent en cinq ans, de 2015 à 2020. Pour les développeurs web, cette croissance de l'IoT est significative. Il existe déjà une forte demande pour les techniques Web IoT.
De nombreux appareils seront répartis géospatialement et leurs propriétaires souhaiteront un contrôle et une gestion à distance. Des piles Web complètes doivent être créées afin de créer des canaux de téléopération. De plus, l'interaction se fera avec un ou plusieurs appareils IoT à la fois. L'interaction doit être en temps réel du monde physique.
Cette discussion se penche sur les exigences d'interface en utilisant Vue.js comme catalyseur et illustre une méthode de communication de page Web à appareil parmi de nombreuses substitutions.
Voici quelques-uns des objectifs prévus pour cette discussion :
- Créer une application Web SPWA d'une seule page qui héberge des groupes d'interfaces homme-machine IoT (nous pouvons appeler ces « groupes de panneaux ») ;
- Afficher des listes d'identificateurs de groupes de panneaux à la suite d'une requête auprès d'un serveur ;
- Afficher les panneaux d'un groupe sélectionné à la suite d'une requête ;
- Assurez-vous que l'affichage du panneau est chargé paresseusement et s'anime rapidement ;
- Assurez-vous que les panneaux se synchronisent avec les appareils IoT.
L'IoT et la croissance rapide des pages Web
La présentation de graphiques pour la visualisation et le contrôle à distance du matériel ainsi que la synchronisation des pages Web avec des processus physiques en temps réel relèvent du domaine de la résolution de problèmes de page Web inhérente à cet avenir IoT.
Nous sommes nombreux à commencer notre recherche de techniques de présentation IoT, mais il existe quelques normes Web ainsi que quelques techniques de présentation que nous pouvons commencer à utiliser dès maintenant. Alors que nous explorons ensemble ces normes et techniques, nous pouvons rejoindre cette vague IoT.
Les tableaux de bord et la visualisation des données sont en demande. De plus, la demande pour aller au-delà des pages Web qui fournissent des formulaires ou affiche des listes ou du contenu textuel est élevée. Les tableaux de bord pour l'IoT doivent être pictographiques, animés. Les animations doivent être synchronisées avec les processus physiques en temps réel afin de fournir une vue véridique de l'état de la machine aux utilisateurs. L'état de la machine, comme une flamme allumée ou non, l'emporte sur l'état de l'application et fournit des informations critiques aux opérateurs, peut-être même des informations de sécurité.
Les tableaux de bord nécessitent plus que la visualisation des données. Nous devons garder à l'esprit que la partie choses de l'IoT est constituée d'appareils qui ont non seulement des capteurs mais aussi des interfaces de contrôle. Dans les implémentations matérielles, les microcontrôleurs sont étendus avec des commutateurs, des commutateurs de seuil, des réglages de paramètres, etc. Néanmoins, les pages Web peuvent remplacer ces composants de contrôle matériels .
Rien de nouveau. Les interfaces informatiques pour le matériel existent depuis longtemps, mais la croissance rapide de l'utilisation des pages Web pour ces interfaces fait partie de notre expérience actuelle. WebRTC et Speech API sont sur une voie de développement qui a commencé en 2012. WebSockets s'est développé dans un laps de temps similaire.
L'IoT est dans nos esprits depuis longtemps. L'IoT fait partie du dialogue humain depuis 1832. Mais, l'IoT et le sans fil tels que nous apprenons à le connaître ont été envisagés par Tesla vers 1926. Forbes 2018 State of Iot nous indique l'orientation actuelle du marché pour l'IoT. Intéressant pour les développeurs Web, l'article appelle les tableaux de bord :
"Les premiers utilisateurs ou défenseurs de l'IoT donnent la priorité aux tableaux de bord, aux rapports, aux cas d'utilisation de l'IoT qui fournissent des flux de données intégrés à l'analyse, à la visualisation avancée et à l'exploration de données."
Le marché de l'IoT est énorme. Cet article Market Size donne une prédiction du nombre d'appareils qui apparaîtront : 2018 : 23,14 milliards ⇒ 2025 : 75,44 milliards. Et, il tente d'y mettre un chiffre financier : 2014 : \ 2,99 billions de dollars ⇒ 2020 : 8,90 billions de dollars. La demande de compétences IoT connaîtra la croissance la plus rapide : IoT in Demand.
Alors que nous développons des interfaces claires pour contrôler et surveiller les appareils, nous rencontrons un nouveau problème pour développer nos interfaces. Tous les milliards d'appareils appartiendront à de nombreuses personnes (ou organisations). En outre, chaque personne peut posséder n'importe quel nombre d'appareils. Peut-être même que certains appareils seront partagés.
Les interfaces modernes conçues pour les commandes de machines ont souvent une disposition bien définie spécifique à une machine particulière ou à l'installation de quelques machines. Par exemple, dans une maison intelligente, un système haut de gamme aura un écran LCD avec des panneaux pour les appareils soigneusement placés. Mais, à mesure que nous grandissons avec la version Web de l'IoT, il y aura un nombre illimité de panneaux pour un flux dynamique et même mobile d'appareils.
La gestion des panneaux pour les appareils devient similaire à la gestion des connexions sociales sur les sites Web sociaux.
"Nos interfaces utilisateur devront être dynamiques pour gérer quel panneau en temps réel hautement animé doit être affiché à tout moment pour chaque utilisateur particulier."
Le tableau de bord est une application Web SPWA d'une seule page. Et, on peut imaginer une base de données de panneaux. Ainsi, si un seul utilisateur doit accéder à un certain nombre de panneaux et de configurations pour ses appareils éparpillés sur la planète, la SPWA doit accéder aux composants du panneau à la demande. Les panneaux et certains de leurs JavaScript de support devront se charger paresseusement.
"Nos interfaces devront fonctionner avec des frameworks de pages Web qui peuvent permettre d'incorporer des liaisons de composants asynchrones sans réinitialiser leurs frameworks."
Utilisons Vue.js, WebSockets, MQTT et SVG pour faire notre entrée sur le marché de l'IoT.
Lecture recommandée : Construire une infographie interactive avec Vue.js
Architecture de haut niveau pour une application Web IoT
Lors de la conception de l'interface de la page Web IoT, on a toujours de nombreuses options. Une option pourrait être de dédier une seule page à un seul appareil. La page peut même être rendue côté serveur. Le serveur aurait pour tâche d'interroger l'appareil pour obtenir ses valeurs de capteur, puis de placer les valeurs aux endroits appropriés dans la chaîne HTML.
Beaucoup d'entre nous connaissent les outils qui permettent d'écrire des modèles HTML avec des marqueurs spéciaux qui indiquent où placer les valeurs des variables. Voir {{temperature}}
dans un tel modèle nous dit, ainsi qu'au moteur de vue , de prendre la température interrogée à partir d'un appareil et de remplacer le symbole {{temperature}}
par celui-ci. Ainsi, après avoir attendu que le serveur interroge l'appareil, l'appareil répondant, rendant la page et livrant la page, l'utilisateur pourra enfin voir la température signalée par l'appareil.
Pour cette page par architecture d'équipement, l'utilisateur peut alors souhaiter envoyer une commande à l'équipement. Pas de problème, il peut remplir un formulaire HTML et le soumettre. Le serveur peut même avoir une route uniquement pour l'appareil, ou peut-être un peu plus intelligemment, une route pour le type d'appareil et l'ID de l'appareil. Le serveur traduirait alors les données du formulaire en un message à envoyer à l'appareil, l'écrirait dans un gestionnaire d'appareil et attendrait un accusé de réception. Ensuite, le serveur peut enfin répondre à la demande de publication et dire à l'utilisateur que tout va bien avec l'appareil.
De nombreux CMS fonctionnent de cette manière pour mettre à jour les entrées de blog, etc. Rien ne semble étrange à ce sujet. Il semble que HTML sur HTTP ait toujours été conçu pour obtenir des pages qui ont été rendues et pour envoyer des données de formulaire à gérer par le serveur Web. De plus, il existe des milliers de CMS parmi lesquels choisir. Ainsi, afin de mettre en place notre système IoT, il semble raisonnable de parcourir ces milliers de CMS pour voir lequel convient le mieux à la tâche. Ou, nous pourrions appliquer un filtre sur les CMS pour commencer.
Nous devons tenir compte de la nature en temps réel de ce à quoi nous sommes confrontés. Ainsi, alors que HTML dans sa forme originale est assez bon pour de nombreuses tâches d'entreprise, il a besoin d'un peu d'aide pour devenir le mécanisme de livraison pour la gestion de l'IoT. Nous avons donc besoin d'un CMS ou d'un serveur Web personnalisé qui aide HTML à faire ce travail IoT. Nous pouvons également penser au serveur car nous supposons que les CMS fournissent des fonctionnalités de serveur. Nous devons juste garder à l'esprit que le serveur doit fournir une animation basée sur les événements, de sorte que la page ne peut pas être une impression statique finalisée à 100 %.
Voici quelques paramètres qui pourraient guider les choix pour notre page Web liée à l'appareil, ce qu'elle devrait faire :
- Recevoir les données du capteur et d'autres messages d'état de l'appareil de manière asynchrone ;
- Restituer les données du capteur pour la page dans le client (presque corollaire à 1) ;
- Publier des commandes vers un appareil particulier ou un groupe d'appareils de manière asynchrone ;
- Envoyez éventuellement des commandes via le serveur ou contournez-le.
- Maintenir en toute sécurité la relation de propriété entre l'appareil et l'utilisateur ;
- Gérez le fonctionnement critique de l'appareil en n'interférant pas ou en annulant.
La liste vient à l'esprit lorsqu'on pense à une seule page servant d'interface avec un appareil sélectionné . Nous voulons pouvoir communiquer librement avec l'appareil en ce qui concerne les commandes et les données.
Quant à la page, il suffit de la demander une seule fois au serveur web. Nous nous attendrions à ce que le serveur Web (ou l'application associée) fournisse une voie de communication sécurisée. Et, le chemin ne doit pas nécessairement passer par le serveur, ou peut-être devrait-il éviter complètement le serveur car le serveur peut avoir des tâches plus prioritaires autres que la prise en charge de la communication d'une page pour les données provenant de capteurs.
En fait, nous pouvons imaginer des données provenant d'un capteur une fois par seconde, et nous ne nous attendrions pas à ce que le serveur Web lui-même fournisse une mise à jour constante seconde par seconde pour des milliers de flux de capteurs individuels multipliés par des milliers de téléspectateurs. Bien sûr, un serveur Web peut être partitionné ou configuré dans un cadre d'équilibrage de charge, mais il existe d'autres services personnalisés pour la livraison des capteurs et le marshaling des commandes au matériel.
Le serveur Web devra fournir un paquet afin que la page puisse établir des canaux de communication sécurisés avec l'appareil. Nous devons être prudents lorsque nous envoyons des messages sur des canaux qui ne permettent pas de gérer les types de messages qui transitent. Il doit y avoir une certaine connaissance pour savoir si un appareil est dans un mode qui peut être interrompu ou s'il peut y avoir une demande d'action de l'utilisateur si un appareil est hors de contrôle. Ainsi, le serveur Web peut aider le client à obtenir les ressources appropriées qui peuvent en savoir plus sur l'appareil. La messagerie pourrait être effectuée avec quelque chose comme un serveur MQTT. De plus, certains services de préparation du serveur MQTT peuvent être lancés lorsque l'utilisateur accède à son panneau via le serveur Web.
En raison du monde physique avec ses exigences en temps réel et en raison de considérations de sécurité supplémentaires, notre diagramme devient un peu différent de l'original.
Nous ne pouvons pas nous arrêter ici. Mettre en place une seule page par appareil, même s'il est réactif et gère bien la communication, n'est pas ce que nous demandions. Nous devons supposer qu'un utilisateur se connectera à son compte et accédera à son tableau de bord. À partir de là, il demandera une liste de projets de contenu (probablement des projets sur lesquels il travaille). Chaque élément de la liste fera référence à un certain nombre de ressources. Lorsqu'il sélectionne un élément en cliquant ou en appuyant dessus, il aura accès à une collection de panneaux, chacun contenant des informations sur une ressource ou un appareil IoT particulier.
N'importe quel nombre de panneaux délivrés en réponse à la requête générée à la suite de l'action de l'interface utilisateur peut être ces panneaux qui interagissent avec des dispositifs actifs. Ainsi, dès qu'un panneau s'affichera, on s'attendra à ce qu'il affiche l'activité en temps réel et qu'il puisse envoyer une commande à un appareil.
La façon dont les panneaux sont vus sur la page est une décision de conception. Il peut s'agir de fenêtres flottantes ou de cases sur un arrière-plan déroulant. Quelle que soit la présentation, les panneaux indiqueront le temps, la température, la pression, la vitesse du vent ou tout ce que vous pouvez imaginer. Nous nous attendons à ce que les panneaux soient animés selon différentes échelles graphiques. La température peut être présentée sous la forme d'un thermomètre, la vitesse sous la forme d'un indicateur de vitesse semi-circulaire, le son sous la forme d'une forme d'onde en continu, etc.
Le serveur Web a pour tâche de fournir les bons panneaux au bon utilisateur en fonction des requêtes adressées à une base de données de panneaux et étant donné que les appareils doivent être physiquement disponibles. De plus, étant donné qu'il y aura de nombreux types d'appareils différents, les panneaux de chaque appareil seront probablement différents. Ainsi, le serveur web doit pouvoir délivrer les informations pictographiques nécessaires au rendu d'un panneau. Cependant, la page HTML du tableau de bord ne doit pas être chargée avec tous les panneaux possibles. On ne sait pas combien il y en aura.
Voici quelques paramètres qui pourraient guider les choix de notre page de tableau de bord, ce qu'elle devrait faire :
- Présenter une manière de sélectionner des groupes de panneaux d'appareils associés ;
- Utiliser des mécanismes de communication simultanée d'appareils pour un certain nombre d'appareils ;
- Activez les panneaux de l'appareil lorsque l'utilisateur les demande ;
- Incorporez des graphiques chargés paresseusement pour des conceptions de panneaux uniques ;
- Utiliser des jetons de sécurité et des paramètres par rapport à chaque panneau ;
- Maintenir la synchronisation avec tous les appareils sous inspection par l'utilisateur.
Nous pouvons commencer à voir comment le jeu change, mais dans le monde de la conception de tableaux de bord, le jeu change un peu ici et là depuis un certain temps. Nous devons simplement nous limiter à des outils de développement de pages à jour et utiles pour nous lancer.
Commençons par la façon dont nous pouvons rendre les panneaux. Cela semble déjà être un gros travail. Nous imaginons de nombreux types de panneaux différents. Mais, si vous avez déjà utilisé une DAW musicale, vous verriez comment ils ont utilisé des graphiques pour faire ressembler les panneaux aux appareils analogiques utilisés par les groupes d'il y a longtemps. Tous les panneaux des DAW sont dessinés par les plugins qui fonctionnent sur le son. En fait, beaucoup de plugins de ces DAW pourraient utiliser SVG pour rendre leurs interfaces. Nous nous limitons donc à gérer les interfaces SVG, qui à leur tour peuvent être n'importe quel graphique que nous pouvons imaginer.
Choisir SVG pour les panneaux
Bien sûr, j'aime les DAW et je l'utiliserais comme exemple, mais SVG est une norme de page Web. SVG est une norme W3C. C'est pour transporter des dessins au trait sur les pages Web. SVG était autrefois un citoyen de seconde classe sur la page Web, nécessaire pour vivre dans des iFrames. Mais, depuis HTML5, c'est un citoyen de première classe. Peut-être que lorsque SVG2 sortira, il pourra utiliser des éléments de formulaire. Pour l'instant, les éléments de formulaire sont des objets étrangers en SVG. Mais cela ne devrait pas nous empêcher de faire de SVG le substrat des panneaux.
SVG peut être dessiné, stocké pour l'affichage et il peut être chargé paresseusement. En fait, en explorant le système de composants, nous verrons que SVG peut être utilisé pour les modèles de composants. Dans cette discussion, nous utiliserons Vue.js pour créer des composants pour les panneaux.
Dessiner SVG n'est pas difficile, car il existe de nombreux programmes de dessin au trait faciles à obtenir. Si vous dépensez de l'argent, vous pouvez obtenir Adobe Illustrator, qui exporte du SVG. Inkscape est un goto pour la création SVG depuis un certain temps. Il est open source et fonctionne bien sur Linux, mais peut également être exécuté sur Mac et Windows. Ensuite, il existe plusieurs programmes d'édition SVG de pages Web qui sont open source, ainsi que certaines versions SaaS.
J'ai cherché un éditeur SVG open source basé sur le Web. Après quelques recherches, je suis tombé sur SVG-Edit. Vous pouvez l'inclure dans vos propres pages Web, peut-être si vous créez un blog basé sur SVG ou quelque chose du genre.
Lorsque vous enregistrez votre travail dans un fichier, SVG-Edit le télécharge dans votre navigateur et vous pouvez récupérer le fichier dans votre répertoire de téléchargement.
L'image que j'ai dessinée montre une porte ET contrôlant un intégrateur. Ce n'est pas ce que l'on s'attend généralement à voir dans un panneau pour un MCU. Le panneau peut avoir un bouton pour alimenter l'une des entrées de la porte ET, peut-être. Ensuite, il peut avoir un affichage d'un ADC qui lit la sortie de l'intégrateur. Ce sera peut-être un graphique linéaire sur un axe temporel. La plupart des panneaux auront des graphiques qui permettent à l'utilisateur de se rapporter à ce qui se passe à l'intérieur du MCU. Et, si notre circuit doit vivre n'importe où, ce sera à l'intérieur du MCU.
Tout de même, notre schéma électronique peut être utilisé pour parler d'animation. Ce que nous voulons faire, c'est jeter un coup d'œil au SVG et voir où nous pouvons accéder à certaines des balises DOM que nous aimerions modifier d'une manière ou d'une autre. Nous pouvons ensuite animer le SVG en utilisant un peu de JavaScript vanille et une minuterie. Faisons clignoter la porte ET de différentes couleurs.
Le SVG que nous recherchons se trouve dans la zone de code suivante. Cela n'a pas l'air très convivial pour le programmeur, même si l'utilisateur sera plutôt content. Néanmoins, il reste encore quelques indices à suivre pour trouver sur quel élément DOM nous souhaitons opérer. Premièrement, la plupart des outils de dessin SVG ont un moyen d'accéder aux propriétés de l'objet, en particulier l'attribut id
. SVG-Edit a aussi un moyen. Dans l'éditeur, sélectionnez la porte ET et observez la barre d'outils. Vous verrez également un champ pour l' id
et la class
CSS.
Si vous ne pouvez pas accéder à un outil d'édition pour une raison quelconque, vous pouvez ouvrir le SVG dans un navigateur et inspecter le DOM. Dans tous les cas, nous avons constaté que notre portail avait id
= "svg_1".
<svg width="640" height="480" xmlns="https://www.w3.org/2000/svg" xmlns:svg="https://www.w3.org/2000/svg"> <g class="layer"> <title>Layer 1</title> <path d="m80.59881,87.020171l14.714795,0m-14.714793,-11.938687l14.714797,0.000004m-0.033867,-6.543869l0,24.758504c42.377882,2.221929 43.364812,-27.139117 0,-24.758504zm47.366321,12.333056l-15.303943,0m-48.188699,-6.489897l1.454753,0l0,1.454751l-1.454753,0l0,-1.454751zm-0.068425,11.869359l1.454753,0l0,1.454753l-1.454753,0l0,-1.454753zm63.545246,-6.089294l1.454751,0l0,1.454751l-1.454751,0l0,-1.454751z" fill="#FF0000" stroke="#000000"/> <path d="m48.58886,119.662231l18.234678,0l2.523043,-7.173309l4.128604,13.808613l4.587337,-13.987948l4.013933,13.808613l4.35797,-13.629278l4.35797,13.718944l2.408353,-6.72497l18.349357,0m-64.482612,-0.623112l1.515724,0l0,1.515728l-1.515724,0l0,-1.515728zm64.484275,-0.103111l1.515721,0l0,1.515728l-1.515721,0l0,-1.515728z" fill="#FF0000" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="rotate(90.3367 80.0675 119.304)"/> <polygon cx="108.5" cy="79.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="#000000"/> <polygon cx="215.5" cy="192.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="165.5" cy="164.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="161.5" cy="138.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="160.5" cy="161.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <g> <path d="m225.016923,53.008793l0,3.419331m-4.558966,-1.709666l9.11791,0m10.303228,4.235512l-25.770656,0m-34.429182,0l24.544724,0m0.220544,-4.058194l1.543807,0l0,8.164451l-1.543807,0l0,-8.164451zm7.939567,-4.473673l1.543805,0l0,16.999955l-1.543805,0l0,-16.999955zm-34.176663,8.126854l1.474036,0l0,0.747515l-1.474036,0l0,-0.747515zm61.677552,0.018809l1.474038,0l0,0.747515l-1.474038,0l0,-0.747515z" fill="#FF0000" sides="3" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/> <polygon cx="171.5" cy="159.5" edge="43.256342" fill="#ffffff" orient="x" points="223.47406005859375,91.5 186.01296997070312,113.128173828125 186.01296997070312,69.871826171875 223.47406005859375,91.5 " shape="regularPoly" sides="3" stroke="#000000" stroke-width="null" strokeWidth="null" strokecolor="#000000"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171" x2="186" y1="103.5" y2="103.5"/> <path d="m130.801817,80.659041l15.333707,0l2.12165,-4.564833l3.47178,8.787299l3.857534,-8.901421l3.375353,8.787299l3.664657,-8.673176l3.664657,8.730237l2.025206,-4.279526l15.430142,0m-54.224016,-0.396526l1.274586,0l0,0.964554l-1.274586,0l0,-0.964554zm54.225414,-0.065616l1.274584,0l0,0.964554l-1.274584,0l0,-0.964554z" fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171.5" x2="171.5" y1="103.75" y2="135.388167"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="177.75" x2="177.75" y1="58.75" y2="80.255951"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="223.75" x2="266.854524" y1="91.75" y2="91.75"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="241.75" x2="241.75" y1="59.75" y2="91.754167"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="168.25" x2="180.75" y1="135.75" y2="135.75"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="169.75" x2="179.25" y1="138.5" y2="138.5"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" x1="171" x2="179.75" y1="141.25" y2="141.25"/> </g> </g> </svg>
Tout ce dont nous avons besoin maintenant, c'est d'un peu de JavaScript. Nous notons d'abord que l'attribut d'élément "fill" est présent. Ensuite, il y a juste le programme simple qui suit :
<html> <head> </head> <body> <!-- ALL THE SVG FROM ABOVE GOES HERE --> </body> <html> </svg> <script> // Set up a timer interval flash the color. var gateElement = document.getElementById("svg_1"); if ( gateElement ) { setInterval( () => { var fillC = gateElement.getAttribute("fill"); gateElement.setAttribute("fill", (fillC == "#00FF00") ? "#FF0000" : "#00FF00" ); }, 2000 ) } </script>
Notez que nous avons une page HTML minimale. Vous pouvez couper et coller le code dans votre éditeur préféré. Et, ensuite, n'oubliez pas de couper et coller le SVG pour remplacer le commentaire. Ma version de Chrome nécessite que la page soit HTML afin d'avoir la section JavaScript. Donc, c'est un navigateur qui traite toujours SVG comme quelque chose de séparé. Mais on est loin de l'époque <iframe>
.
Si vous coupez et collez correctement, vous pouvez afficher la page et voir la porte ET passer du rouge au vert encore et encore.
Lecture recommandée : SVG Circle Decomposition To Paths
Construire des panneaux à partir de composants VUE
Nous sommes déjà en train de donner vie à n'importe quel panneau, mais si nous voulons gérer de grandes collections de panneaux de manière sensée, nous aurions du pain sur la planche. Ce serait particulièrement le cas si nous nous appuyions simplement sur notre premier exemple.
Alors que le premier exemple nous montre comment nous pouvons modifier de manière asynchrone une vue d'objet, il ne nous montre pas comment lier la vue à l'état de n'importe quel objet de données et encore moins celui qui gère une machine. Nous pouvons certainement comprendre comment la démonstration setInterval
peut être remplacée par un gestionnaire de fetch
, mais nous pourrions même ne pas obtenir l'état d'une machine à partir du serveur Web qui dessert la page contenant SVG. De plus, lorsque nous obtenons les données, nos programmes doivent maintenant connaître la structure DOM de la page donnée.
Heureusement, des frameworks tels que Vue sont devenus populaires et peuvent nous faire économiser beaucoup de travail.
Il est facile de se renseigner sur Vue. La documentation de Vue est très accessible. Donc, si cette discussion va trop loin, vous passerez peut-être un peu de temps à vous renseigner sur Vue sur son propre site Web. Mais, il y a de très bonnes discussions dans les pages Smashing. Krutie Patel a écrit un article étonnant sur la création d'une infographie. Souvik Sarkar nous explique comment créer un tableau de bord météo avec Vue.
Sélection de groupe de panneaux associés
Pour la première étape, nous devrions aborder la recherche de groupes de panneaux. L'une des raisons de le faire en premier est que c'est au niveau du cadre de nos interactions humaines.
L'utilisateur recherche quelque chose qui l'intéresse. Il est peut-être intéressé par tous les appareils situés dans une même ville. Peut-être a-t-il de nombreux lots de produits liquides et souhaite-t-il se limiter à un type de produit, chaque lot étant régi par une petite collection d'appareils IoT. Ainsi, l'utilisateur recherchera d'abord pour obtenir une petite liste.
Voici le processus :
- Recherche de groupes de panneaux par caractéristiques/paramètres.
- Afficher une liste d'icônes représentant des groupes.
- Sélectionnez une icône (cliquez/appuyez).
- Commencez à utiliser les panneaux identifiés par l'icône lorsqu'ils apparaissent.
Une autre raison pour laquelle c'est une bonne première étape est que nous pouvons utiliser Vue dans sa forme la plus simple. Aucun outil de construction nécessaire. Nous allons simplement inclure vue.js
avec une balise de script en HTML. En fait, nous n'avons même pas besoin de le télécharger. Il existe un site où une copie de travail de vue.js
est servie.
Tout ce dont nous avons besoin est la balise suivante :
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
J'ai copié la balise de script directement à partir de la documentation de Vue sur l'installation.
Maintenant, nous avons besoin d'une page Web qui peut charger des icônes et les transformer en quelque chose qui clique. Vue rend cela très facile. En fait, je viens d'écrire une petite application pour gérer une liste Twitter en utilisant Vue. Il gère uniquement les champs de texte. Comme il est un tout petit peu plus simple qu'un SPWA utilisant des icônes, nous pouvons y jeter un coup d'œil, puis le modifier pour qu'il devienne notre framework d'application à page unique souhaité.
Voici une partie de ce à quoi ressemble la page :
Cela ressemble à une page assez simple. Chaque entrée numérique externe est un créneau horaire contenant un ou deux tweets. Le deuxième tweet est facultatif. Si vous éditez un tweet, les mécanismes de Vue mettent à jour un objet JavaScript. Cette page laisse à l'utilisateur le soin de cliquer sur le bouton "Mettre à jour les entrées" pour indiquer au serveur que quelque chose a changé, via sa fonction de gestion de bouton.
Pour que le gestionnaire de boutons relaie les données au serveur, il doit transformer l'objet de données Vue en une chaîne JSON. Maintenant, vous vous demandez peut-être à quel point il sera difficile de traduire un objet Vue en JSON. Il s'avère être une ligne de code. Vous pouvez trouver la ligne dans le code source suivant, mais si vous voulez la trouver plus rapidement, elle est mise en surbrillance dans le paragraphe après le code source.
La page semble simple. Les apparences peuvent être trompeuses. Bien sûr, la page semble simple, mais le code est-il simple ? Oui, en effet ! En utilisant Vue, la page gère le contenu des champs presque comme par magie. Voici le code :
<!DOCTYPE html> <html lang="en" prefix="og: https://ogp.me/ns#"> <!-- define microdata scope and type --> <head itemscope itemtype="https://schema.org/Article"> <title>Tweet Keeper</title> <style> body { margin: 2em; } .entryart { border: solid 1px navy; width: 80%; padding: 2px; padding-left: 6px; margin-bottom: 3px; background-color: #EEF4EE; } </style> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> </head> <body onload="GetTweets()"> <!-- some old fashioned handling --> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div> <!-- Recognize the name from the Vue doc --> <div itemscope itemtype="https://schema.org/Article"> <h1 itemprop="name">mangage tweets</h1> <p itemprop="description">My personal Tweet engine. This page accesses a personal tweet page that belongs to {{tweetOwner}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button>Update Entries</button> </div> <!-- Here is a Vue loop for generating a lit --> <ol> <li v-for="tweet in tweets"> <!-- here is the first tweet represented as an object with a lable and tweet text --> <div class="entryart"> <input v-model="tweet.def[0].label" /> <input v-model="tweet.def[0].tweet" /> </div> <!-- here is the second tweet in the slot. But, notice that it is optional. --> <div class="entryart" v-if="tweet.def.length > 1"> <input v-model="tweet.def[1].label"/> <input v-model="tweet.def[1].tweet"/> </div> </li> </ol> </div> <script> var twtApp = new Vue({ el: '#tweetAppDiv', data: { tweets: [ // Where is the data? Still on the server.s ], tweetOwner : "Lucky Dude" // picked a name for demo } }); </script> </body> </html> <script> // Notice that you don't have to do everything in the Vue framework. // Here we are using some native API calls var gDefaultPostInfo = { // there server is beyond simple - an example from node.js docs method: 'POST', // or 'PUT' mode: "cors", // no-cors, cors, *same-origin cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached credentials: "same-origin", // include, *same-origin, omit redirect: "follow", // manual, *follow, error referrer: "no-referrer", // no-referrer, *client body: "", headers:{ 'Content-Type': 'application/json' } } // // // recall the "onload" function GetTweets(event) { var url = "https://localhost:8080/twitlist1.json" // We have a fixed file name. fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. twtApp.tweets = newData // the page update right away with new data. }); }); } function sendTweets() { // recall the button up above. This is not a Vue style button, but still in the Vue app. var url = "https://localhost:8080/" var data = twtApp.tweets; // GET THE DATA OUT OF VUE. That's all folks. // // so happens that Vue pulls out the right data and stringifies it. var jdata = JSON.stringify(data); // data can be `string` or {object}! // gDefaultPostInfo.body = jdata; // that's for fetch - not Vue related // fetch(url,gDefaultPostInfo).then(res => { // We use fetch to POST as well as GET res.json() }).then(response => { console.log('Success:', JSON.stringify(response)) // promises }).catch(error => { console.error('Error:', error) }); } // // // </script>
Donc, juste pour mettre en évidence les lignes étonnantes qui témoignent de la puissance du framework, répétons ici :
A. Il s'agit d'extraire les données.
postOptionsObject.body = JSON.stringify(twtApp.tweets);
B. Il s'agit de mettre les données dans Vue et de voir la mise à jour de l'écran :
twtApp.tweets = JSON.parse(text) // text is the server response
Combien de travail est-ce?
Il semble qu'il y aura une bonne façon d'exprimer comment les données mettront à jour les panneaux pour l'IoT.
Transformons maintenant les tweets en icônes cliquables conçues pour récupérer les composants du serveur Web.
Des tweets aux icônes de récupération de panneau
Les gens aiment utiliser SVG pour les icônes. Ils aiment cette utilisation pour SVG plus que pour d'autres choses pour autant que je sache. Je ne parle que du nombre de sites Web qui vendent ou donnent des icônes en SVG. L'argument de vente est que les graphiques linéaires ont moins d'octets que les images. Et, si j'allais demander des listes d'images avec un comportement semblable à un bouton, j'aurais peut-être saisi des PNG ou des JPEG à l'époque où SVG était dans des iframes. But, we can even find libraries in the Vue contributor lists that help us to a serving of icons.
We can turn the tweets page into an icon list returned as a search result. Just a little code has to be changed. Of course, there are a few things to be careful about if we want SVG icons to be loaded as buttons. Vue provides mechanisms for putting HTML into the application. These mechanisms have to be used or DOM elements fetched from the server don't get interpreted.
Here is the kind of rendering you can get from view if you follow your first impulse in creating a handlebars style variable location in the application DOM.
Here is the code that produces the result in the picture:
<div> <div class="entryart"> <span class="oneItem" v-for="icon in iconList"> {{icon}} </span> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } }); </script>
Notice that we have gone from looping over tweets to looping over icons. tweet in tweets
changed into icon in iconList
. Our twtApp
hooks into the DOM element #tweetAppDiv
, while our iconApp
hooks into the DOM element #iconAppTry
. Within the Vue option object, the data
subobject has a tweets
in the first app, and iconList
in the second. The fields are both empty arrays that receive data when the fetch
routine does its job.
But, we have imitated our tweet app too closely. In the code above, the iconList is an array, and the server is expected to send an array of strings. So, let's say the server has sent us HTML, and we have it properly decoded with the array assigned to data.iconList
. Then, the picture above can be seen.
Now, let's change the code just a little. In this revised code, we can see the following:
v-html="icon">
Vue responds to the v-html syntax by putting in the DOM of the icon
element. Notice that the syntax is included after the loop directive as another attribute to the span
tag.
By removing the handlebars
syntax and using v-html
, our picture changes to something more comprehensible:
<div> <div class="entryart"> <span class="oneItem" v-for="icon in iconList" v-html="icon"> </span> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry2', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } }); </script>
While v-html
is a quick way to do things, the Vue team recommends using components to get the desired HTML into the page. That seems like a good idea, and we shall soon set about doing that.
But, let's use the v-html
syntax for our next example.
It's time to set up our working example for fetching SVG icons. Let's have those icons be responsive to a button click. Once those are working, we can get the panels associated with an icon.
Let's suppose that the SVG required for icons is stored in a database. For our example, we can just fetch a JSON file from the server. The grown-up version of the icon server would store many such files in a database, and deliver them to the page with the same mechanisms.
Also, it's best if the SVG arrives on the page URL encoded since we will be using JSON parse. The SVG can be decoded by calling JavaScript's decodeURIComponent
function.
In order to simulate the response to searching, we can make use of several JSON files. The page can have one button for each file. Here is the code for the page:
<!DOCTYPE html> <html lang="en" prefix="og: https://ogp.me/ns#"> <!-- define microdata scope and type --> <head itemscope itemtype="https://schema.org/Article"> <title>Search Bar</title> <style> body { margin: 2em; } div { margin: 6px; } .entryart { border: solid 1px navy; width: 80%; padding: 2px; padding-left: 6px; margin: 2px; margin-bottom: 3px; background-color: #EEF4EE; } .oneItem { background-color: #EEFFFF; margin: 2px; padding: 4px; border: solid 1px purple; } </style> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> </head> <body> <!-- some old fashioned handling --> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Request MCU Groups</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button>Find All</button> <button>Find 5 Point</button> <button>Find 6 Point</button> </div> <!-- Here is a Vue loop for generating a lit --> <div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo }, methods : { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } } }); </script> </body> </html> <script> // // recall the "onclick" on the <buttons> function GetIcons(points) { // special file names instead of search parameters // var url = (points == 11) ? "https://localhost:8080/batchQuery-all.json" : ((points == 5) ? "https://localhost:8080/batchQuery-five.json" : "https://localhost:8080/batchQuery-six.json") fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. newData = newData.map(obj => { obj.icon = decodeURIComponent(obj.icon); return(obj) }); iconApp.iconList = newData; // the page update right away with new data. }); }); } </script>
Here is one display of icons that have been fetched from the server:
The data being sent is an array with the following kind of structure:
{ "style" : { "color" : "red", "backgroundColor" : "yellow" }, "icon" : svg1, "name" : "thermos" },
Ici, svg1
est SVG extrait d'un fichier. Bien sûr, un serveur juste aurait pris la structure d'une base de données, où le SVG serait stocké dans la structure.
Voici un extrait du code ci-dessus. C'est le code qui récupère le JSON et place le tableau de structures dans l'application Vue. Vous pouvez voir la structure de promesse de fetch
en cours d'utilisation. Le texte est analysé et dans la ligne suivante, le SVG encodé est décodé. Une ligne de plus, et Vue met à jour la page. Le nombre de boutons dans la barre de boutons sera égal à la longueur du tableau JSON.
fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. newData = newData.map(obj => { obj.icon = decodeURIComponent(obj.icon); return(obj) }); // the page update right away with new data. iconApp.iconList = newData; }); });
Maintenant, juste deux extraits de plus. L'application Vue. Le lecteur remarquera que la directive @click
a été incluse sur les boutons. L'élément de données, iconEntry.name
, est passé à une méthode entre guillemets.
La méthode est définie dans l'application Vue :
<div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div>
Voici l'extrait pour la définition des méthodes. L'objet methods
est ajouté juste après l'objet data
dans l'objet app parameters :
, methods: { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } }
Le lecteur devrait trouver la définition goGetPanel
, et son utilisation a été signalée pour le gestionnaire @click
. Dans notre application finale, l'appel d' alert
peut être remplacé par une fonction qui récupère les panneaux du serveur.
Une bibliothèque de composants pour les panneaux IoT
Nous pourrions simplement décider que les panneaux que nous récupérons du serveur peuvent être des dessins HMTL ou simplement SVG, mais s'il doit y avoir plusieurs types de panneaux, nous espérons que le travail de création de panneaux pourrait être simplifié en ayant des bibliothèques de composants à choisissez parmi. Nous pouvons imaginer que les éditeurs SVG pourraient être améliorés pour permettre aux composants de la bibliothèque d'être déposés sur les images dans le cadre de l'édition. Ensuite, si l'éditeur SVG pouvait produire une version de l'image avec des balises de composant, l'utilisation de Vue permettrait de créer l'image tout en garantissant que l'automatisation et l'animation JavaScript sont parfaitement imbriquées. Pour notre discussion, quelques modifications manuelles peuvent nous aider à y arriver.
Si nous voulons créer des panneaux à partir de composants Vue, nous ferions mieux de trouver comment créer les composants, puis de les rassembler en quelque chose d'utile. Nous devrons passer à l'utilisation des outils de ligne de commande fournis par Vue et organiser notre flux de travail.
Composants
La documentation de Vue souligne que la section data
composant (sous-objet) de la définition de composant doit être une fonction qui renvoie des données. La raison en est que Vue doit séparer les données entre les instances. Ainsi, en passant d'une initialisation d'application Vue à une définition de composant, il y a un autre petit changement de code.
Dans ce premier extrait de code, une application Vue est en cours d'initialisation :
var iconApp = new Vue({ el: '#iconApp', data: { // this is the data field that can be easily updated }, methods : { ... } });
Dans ce nouvel extrait de code, un composant est défini et enregistré. Tout d'abord, notez qu'au lieu de créer une new Vue
, un composant nommé iconic
est en cours d'enregistrement. Ensuite, le champ data
renvoie des données personnalisées pour toute instance iconic
créée par l'application Vue. Enfin, le champ template
est présent à la fin de l'enregistrement du composant. Tout code HTML éventuellement écrit sur la page Web pour afficher le composant peut faire partie du template
.
Vue.component('iconic', data: () => { var instanceData = { // data fields named for the // variables appearing in the template onevar : "test" } return(instanceData); }, methods : { ... }, template: '<div>This appears in every instance {{onevar}}</div>' });
Ainsi, on peut imaginer un panneau avec des thermomètres. Donc, si quelqu'un fournissait un composant de thermometer
, nous nous attendrions à une définition de composant quelque part dans notre code. En tant que tel:
Vue.component('thermometer', data: () => { var instanceData = { // data fields named for the // variables appearing in the template temperature : 0 } return(instanceData); }, methods : { ... }, template: '<div>Some SVG will go here</div>' });
Nous essayons de créer quelque chose qui ressemble à ceci :
Le composant thermomètre est très similaire aux premiers composants que vous rencontrerez dans les tutoriels Vue. Mais, il est un peu difficile de comprendre comment le mettre à jour. Il existe une meilleure façon de définir le composant pour la réactivité en utilisant les propriétés. Et, c'est dans ce qui suit :
Vue.component('thermometer', { props: ['temperature'], computed : { y: function() { var t = this.temperature/100; var h = 54.724472; var y_bar = 41.176476 // starts near the top // pretend the scale is 1 to 100, so that the temperature is a precentage return((1 - t)*h + y_bar) }, height : function() { var t = this.temperature/100; var h = 54.724472; // as high as the whole range var y_bar = 41.176476 // pretend the scale is 1 to 100, so that the temperature is a precentage return(t*h) } }, template: '#thermometer-template' })
Ainsi, au lieu de représenter la température comme un élément de données. Il est représenté comme une propriété sous props
. Ensuite, il y a une nouvelle section, computed , qui fournit des variables qui sont des fonctions de la propriété. Nous voyons this.temperature
utilisé à la fois pour y
et height
. Ces variables calculées sont utilisées dans le SVG comme attributs d'un rectangle.
En SVG, y
croît de haut en bas. Ainsi, lorsque nous voulons que le rectangle soit petit au bas du thermomètre, le y
de la boîte rouge doit être inférieur et la hauteur doit être réduite de sorte que ( y + height
) reste au zéro du thermomètre.
Notez le champ de template
dans la définition des composants. Il s'agit en fait d'un identifiant d'élément de document. L'élément auquel il est fait référence est une section de script avec le type spécial : type="text/x-template"
. L'élément de script est l'endroit où se trouve le SVG pour les thermomètres. De plus, le SVG utilise des variables Vue et des termes de contrôle afin que la réactivité puisse être définie.
Voici quelques-uns des SVG :
<script type="text/x-template"> <svg xmlns:svg="https://www.w3.org/2000/svg" xmlns="https://www.w3.org/2000/svg" width="20" height="70" version="1.1" > <g transform="translate(0,-180)"> <g transform="matrix(2.0111869,0,0,1.0489665,-215.11053,144.5592)"> <rect stroke-linecap="null" stroke-linejoin="null" width="2.9665921" height="54.724472" x="111.90748" y="41.176476" /> <rect stroke-linecap="null" stroke-linejoin="null" width="2.9665921" x="111.90748" :height="height" :y="y" /> <g transform="matrix(0.76503813,0,0,1,26.586929,0)"> <line y2="57.306953" y1="57.306953" x2="113.15423" x1="107.22105" stroke-linejoin="null" stroke-linecap="null" /> <line y2="74.408356" y1="74.408356" x2="113.15423" x1="107.22105" stroke-linejoin="null" stroke-linecap="null"
Le lecteur peut trouver id="thermometer-template"
en haut, et en regardant plus bas vers les éléments rect
, les variables calculées peuvent être trouvées.
Ici, les utilisations variables sont séparées. La syntaxe abrégée de Vue pour v-bind
est utilisée, avec :height="height"
et la même chose pour y
:
x="111.90748" :height="height" :y="y"
Lorsque le parent des éléments SVG définit des variables qui servent d'entrée à la propriété temperature
, Vue recalcule height
et y
. En conséquence, la position et la hauteur de la boîte rouge changent.
Il est utile d'avoir une liste de l'application Vue qui utilise le thermomètre.
<body> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Set Temperature</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button @click="updateTemp(50,50)">mid</button> <button @click="updateTemp(20,80)">low</button> <button @click="updateTemp(80,20)">high</button> </div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> <script> var thermoApp = new Vue({ el: '#thermoApp', data: { temp1 : 30, temp2 : 60, queryToken : "HEAT" }, methods : { updateTemp: function (tval1,tval2) { this.temp1 = tval1; this.temp2 = tval2; } } }); </script> </body>
C'est tout. Trois boutons appellent la méthode updateTemp
de l'application thermoApp
Vue. La section des données a deux variables de température. Et, chaque thermometer
met à jour sa température lorsque les valeurs changent.
Le code des deux thermomètres mentionnés ci-dessous se trouve sur le code HTML attribué à l'application Vue.
<thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer>
Notez que l'application utilise le formalisme de la function
pour la définition de la méthode. Définir updateTemp
cette manière updateTemp: function (tval1,tval2)
permet d'accéder à la variable d'instance this
.
De plus, définir updateTemp
cette manière updateTemp: (tval1,tval2) =>
attribue this
à une structure de données interne qui ne réagit pas et ne met pas à jour la vue.
Assemblage d'un panneau
Chaque panneau IoT peut être un composant. Vue fournit un moyen de définir des composants avec des sous-composants. Alternativement, il existe un mécanisme de slot qui peut être utilisé pour produire un composant qui peut envelopper n'importe quel contenu HTML.
Dans les quelques paragraphes suivants, examinons comment créer un panneau à partir de sous-composants. Il existe deux formes qui découlent rapidement de nos exemples. Dans un cas, les thermomètres peuvent être des sous-composants appelés en JavaScript. Dans un autre cas, les composants sont définis indépendamment mais sont mentionnés dans le HTML.
Dans les deux cas, le même code HTML peut être utilisé pour le modèle. Voici notre panel comme modèle :
<script type="text/x-template"> <div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> </script>
La seule différence entre le premier détail de l'application est qu'un élément div
entoure les deux thermomètres. Vue lancera une erreur s'il manque un élément DOM de niveau supérieur au modèle. Le div
satisfait à l'exigence de Vue et les multiples éléments peuvent être inclus à l'intérieur de celui-ci.
Maintenant, nous pouvons voir les deux thermomètres côte à côte. Le passage des températures du haut au thermomètre final a des valeurs en cascade. Au niveau supérieur, le panneau rejoint l'application lorsqu'une seule ligne est incluse dans le DOM de l'application.
<themo-panel :temp1="temp1" :temp2="temp2" ></themo-panel>
Le gabarit du panneau, bien que simple, semble indiquer que les panneaux peuvent être facilement conçus en termes de composants. C'est comme si un langage pour les seuls composants IoT était possible.
Maintenant, la définition du modèle pour le panneau est assez simple. Le voici avec les sous-composants définis indépendamment :
Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template' });
C'est à peu près tout ce qui est nécessaire pour rendre le panneau fonctionnel. Il est vrai que cette version s'appuie sur une longue liste de propriétés pour définir les valeurs à mettre à jour au fur et à mesure que les messages arrivent dans la page. Mais c'est un bon début. La mise à jour de l'objet de data
au niveau supérieur permet d'animer les thermomètres. Cependant, à mesure que les panneaux deviennent compliqués, il peut être nécessaire d'avoir une autre méthode pour montrer le changement.
Après avoir mentionné les autres façons de spécifier les sous-composants, pour le panneau, nous devrions y jeter un coup d'œil. C'est ici:
Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template', components: { // a sub component for the labels 'thermometer': { props: { temperature: Number, }, template: '#thermometer-template', computed : { y: function() { var t = this.temperature/100; var h = 54.724472; var y_bar = 41.176476 // starts near the top // pretend the scale is 1 to 100, so that the temperature is a precentage return((1 - t)*h + y_bar) }, height : function() { var t = this.temperature/100; var h = 54.724472; // as high as the whole range var y_bar = 41.176476 // pretend the scale is 1 to 100, so that the temperature is a precentage return(t*h) } } } } });
Il y a certainement plus de code, mais c'est parce que le JavaScript du composant thermometer
est inclus dans la liste des composants de thermo-panel
. Les deux approches font le même travail, mais elles offrent différentes manières d'emballer les définitions de composants.
Pour le moment, ma préférence va à la première voie. Il devrait être considérablement plus facile de réviser les panneaux et de les récupérer dynamiquement si seule la modification du modèle et des propriétés est requise. A cette fin, les composants définis indépendamment forment une bibliothèque de composants. Mais, bien que cela semble mieux, dans ce qui suit, il devient plus pratique d'utiliser la deuxième méthode, apparemment plus verbeuse.
Étant donné que nous pouvons créer des panneaux réactifs à partir de composants de manière clairement définie, j'expliquerai comment nous pouvons les gérer comme une base de données pouvant effectuer des requêtes simples dans la prochaine partie de mon article.