Componenti della pagina Web SVG per IoT e Maker (Parte 1)

Pubblicato: 2022-03-10
Riepilogo rapido ↬ L' IoT sta crescendo per includere molti dispositivi con molti proprietari. Gli sviluppatori Web dovranno affrontare il problema di trovare modi per consentire ai proprietari di interagire con i loro dispositivi. Ma questo problema dà origine a una grande quantità di affari. Esaminiamo alcuni aspetti dello sviluppo di pagine Web per l'Internet of Things (IoT) che sono già richiesti.

Il mercato dell'IoT è ancora nelle sue fasi iniziali, ma sta prendendo piede. Siamo a un culmine nella storia dell'IoT. I mercati quadruplicano nel corso di cinque anni, dal 2015 al 2020. Per gli sviluppatori web, questa crescita dell'IoT è significativa. C'è già una grande richiesta di tecniche web IoT.

Molti dispositivi saranno distribuiti geospazialmente e i suoi proprietari desidereranno il controllo e la gestione remoti. È necessario creare stack web completi per creare canali per la teleoperazione. Inoltre, l'interazione avverrà con uno o più dispositivi IoT alla volta. L'interazione deve avvenire nel tempo reale del mondo fisico.

Questa discussione approfondisce i requisiti dell'interfaccia utilizzando Vue.js come catalizzatore e illustra un metodo di comunicazione tra pagina Web e dispositivo in molte sostituzioni.

Ecco alcuni degli obiettivi previsti per questa discussione:

  1. Creare un'app Web SPWA a pagina singola che ospita gruppi di interfacce uomo-macchina IoT (che potremmo chiamare "gruppi di pannelli");
  2. Visualizza elenchi di identificatori di gruppi di pannelli a seguito di query su un server;
  3. Visualizza i pannelli di un gruppo selezionato a seguito di una query;
  4. Assicurati che il display del pannello sia caricato pigramente e si anima rapidamente;
  5. Assicurati che i pannelli si sincronizzino con i dispositivi IoT.
Altro dopo il salto! Continua a leggere sotto ↓

IoT e la rapida crescita delle pagine Web

La presentazione della grafica per la visualizzazione e il controllo remoto dell'hardware insieme alla sincronizzazione delle pagine Web con i processi fisici in tempo reale rientrano nell'ambito della risoluzione dei problemi delle pagine Web inerenti a questo futuro dell'IoT.

Molti di noi stanno iniziando la ricerca di tecniche di presentazione IoT, ma ci sono alcuni standard web insieme ad alcune tecniche di presentazione che possiamo iniziare a utilizzare ora. Mentre esploriamo insieme questi standard e tecniche, possiamo unirci a questa ondata di IoT.

Sono richiesti dashboard e visualizzazione dei dati. Inoltre, la richiesta di andare oltre le pagine Web che forniscono moduli o elenchi di visualizzazione o contenuto testuale è elevata. I dashboard per l'IoT devono essere pittografici, animati. Le animazioni devono essere sincronizzate con i processi fisici in tempo reale per fornire agli utenti una visione veritiera dello stato della macchina. Lo stato della macchina, ad esempio una fiamma accesa o meno, prevale sullo stato dell'applicazione e fornisce informazioni critiche agli operatori, forse anche informazioni sulla sicurezza.

Le dashboard richiedono più della visualizzazione dei dati. Dobbiamo tenere a mente che le cose che fanno parte dell'IoT sono i dispositivi che non hanno solo sensori ma anche interfacce di controllo. Nelle implementazioni hardware, gli MCU sono estesi con interruttori, interruttori di soglia, impostazioni dei parametri e altro ancora. Tuttavia, le pagine Web possono prendere il posto di quei componenti di controllo hardware .

Niente di nuovo. Le interfacce per computer per hardware esistono da molto tempo, ma la rapida crescita dell'uso delle pagine Web per queste interfacce fa parte della nostra esperienza attuale. WebRTC e Speech API stanno seguendo un percorso di sviluppo iniziato nel 2012. WebSockets si è sviluppato in un arco di tempo simile.

L'IoT è nelle nostre menti da molto tempo. L'IoT fa parte del dialogo umano dal 1832. Ma l'IoT e il wireless, come stiamo scoprendo, sono stati immaginati da Tesla intorno al 1926. Forbes 2018 State of Iot ci dice l'attuale focus del mercato per l'IoT. Interessante per gli sviluppatori web, l'articolo richiama i dashboard:

"I primi utenti o sostenitori dell'IoT danno priorità a dashboard, reportistica e casi d'uso IoT che forniscono flussi di dati integrati per analisi, visualizzazione avanzata e data mining".

Il mercato dell'IoT è enorme. Questo articolo Market Size fornisce una previsione per il numero di dispositivi che appariranno: 2018: 23,14 miliardi ⇒ 2025: 75,44 miliardi. E tenta di dare una cifra finanziaria: 2014: \$ 2,99 trilioni ⇒ 2020: $ 8,90 trilioni. La domanda di competenze IoT sarà quella in più rapida crescita: IoT in Demand.

Man mano che sviluppiamo interfacce chiare per il controllo e il monitoraggio dei dispositivi, incontriamo un nuovo problema per lo sviluppo delle nostre interfacce. Tutti i molti miliardi di dispositivi saranno di proprietà di molte persone (o organizzazioni). Inoltre, ogni persona può possedere un numero qualsiasi di dispositivi. Forse anche alcuni dei dispositivi saranno condivisi.

Le moderne interfacce che sono state realizzate per i controlli delle macchine hanno spesso un layout ben definito specifico per una macchina particolare o l'installazione di poche macchine. Ad esempio, in una casa intelligente, un sistema di fascia alta avrà un display LCD con pannelli per dispositivi posizionati con cura. Ma, man mano che cresciamo con la versione web di IoT, ci sarà un numero qualsiasi di pannelli per un flusso di dispositivi dinamico e persino mobile.

La gestione dei pannelli per i dispositivi diventa simile alla gestione delle connessioni social sui siti web social.

"Le nostre interfacce utente dovranno essere dinamiche nella gestione di quale pannello in tempo reale altamente animato deve essere visualizzato in qualsiasi momento per ogni particolare utente".

La dashboard è un'app Web a pagina singola SPWA. E possiamo immaginare un database di pannelli. Quindi, se un singolo utente ha intenzione di accedere a una serie di pannelli e configurazioni per i suoi dispositivi sparsi per il pianeta, l'SPWA deve accedere ai componenti del pannello su richiesta. I pannelli e alcuni dei loro JavaScript di supporto dovranno essere caricati pigramente.

"Le nostre interfacce dovranno funzionare con framework di pagine Web che possono consentire di incorporare collegamenti di componenti asincroni senza reinizializzare i loro framework".

Usiamo Vue.js, WebSockets, MQTT e SVG per fare il nostro passo nel mercato IoT.

Letture consigliate : Costruire un'infografica interattiva con Vue.js

Architettura di alto livello per un'app Web IoT

Quando si progetta l'interfaccia per la pagina Web IoT, si hanno sempre molte opzioni. Un'opzione potrebbe essere quella di dedicare una singola pagina a un singolo dispositivo. La pagina potrebbe anche essere visualizzata sul lato server. Il server avrebbe il compito di interrogare il dispositivo per ottenere i valori del sensore e quindi di inserire i valori nelle posizioni appropriate nella stringa HTML.

Molti di noi hanno familiarità con gli strumenti che consentono di scrivere modelli HTML con marcatori speciali che indicano dove inserire i valori delle variabili. La visualizzazione di {{temperature}} in un tale modello indica a noi e al motore di visualizzazione di prendere la temperatura richiesta da un dispositivo e di sostituire il simbolo {{temperature}} con essa. Quindi, dopo aver atteso che il server interroghi il dispositivo, che il dispositivo risponda, visualizzi la pagina e consegni la pagina, l'utente potrà finalmente vedere la temperatura riportata dal dispositivo.

Per questa pagina per architettura del dispositivo, l'utente potrebbe quindi voler inviare un comando al dispositivo. Nessun problema, può compilare un modulo HTML e inviare. Il server potrebbe anche avere un percorso solo per il dispositivo, o forse un po' più intelligentemente, un percorso per il tipo di dispositivo e l'ID dispositivo. Il server tradurrà quindi i dati del modulo in un messaggio da inviare al dispositivo, lo scriverà a un gestore di dispositivo e attenderà un riconoscimento. Quindi, il server potrebbe finalmente rispondere alla richiesta di post e dire all'utente che tutto va bene con il dispositivo.

Un'architettura di pagina Web per trattare l'IoT come un server di moduli, alla ricerca di qualcosa di meglio.
Un'architettura di pagina Web per trattare l'IoT come un server di moduli, alla ricerca di qualcosa di meglio. (Grande anteprima)

Molti CMS funzionano in questo modo per aggiornare i post di blog e simili. Niente sembra strano. Sembra che HTML su HTTP abbia sempre avuto il design per ottenere le pagine che sono state renderizzate e per inviare i dati dei moduli che devono essere gestiti dal server web. Inoltre, ci sono migliaia di CMS tra cui scegliere. Quindi, per far funzionare il nostro sistema IoT, sembra ragionevole esaminare quelle migliaia di CMS per vedere quale è giusto per il lavoro. Oppure, per cominciare, potremmo applicare un filtro sui CMS.

Dobbiamo prendere in considerazione la natura in tempo reale di ciò con cui abbiamo a che fare. Quindi, mentre l'HTML nella sua forma originale è abbastanza buono per molte attività aziendali, ha bisogno di un piccolo aiuto per diventare il meccanismo di consegna per la gestione dell'IoT. Quindi, abbiamo bisogno di un CMS o di un server Web personalizzato che aiuti HTML a svolgere questo lavoro IoT. Possiamo anche solo pensare al server poiché supponiamo che i CMS forniscano funzionalità del server. Dobbiamo solo tenere a mente che il server deve fornire un'animazione basata sugli eventi, quindi la pagina non può essere una stampa statica finalizzata al 100%.

Ecco alcuni parametri che potrebbero guidare le scelte per la nostra pagina Web collegata al dispositivo, cose che dovrebbe fare:

  1. Ricevere i dati del sensore e altri messaggi di stato del dispositivo in modo asincrono ;
  2. Rendere i dati del sensore per la pagina nel client (quasi corollario a 1);
  3. Pubblica i comandi su un particolare dispositivo o gruppo di dispositivi in ​​modo asincrono ;
  4. Facoltativamente inviare comandi tramite il server o ignorarlo.
  5. Mantenere in modo sicuro il rapporto di proprietà tra il dispositivo e l'utente;
  6. Gestisci il funzionamento dei dispositivi critici senza interferire o sovrascrivere.

L'elenco viene in mente quando si pensa a una sola pagina che funge da interfaccia per un dispositivo selezionato . Vogliamo poter comunicare liberamente con il dispositivo quando si tratta di comandi e dati.

Per quanto riguarda la pagina, è sufficiente chiederla al server web una sola volta. Ci si aspetterebbe che il server web (o l'applicazione associata) fornisse un percorso di comunicazione sicuro. Inoltre, il percorso non deve necessariamente passare attraverso il server, o forse dovrebbe evitare del tutto il server poiché il server potrebbe avere attività con priorità più elevate oltre a prendersi cura della comunicazione di una pagina per i dati provenienti dai sensori.

In effetti, possiamo immaginare i dati provenienti da un sensore una volta al secondo e non ci aspetteremmo che il server Web stesso fornisca un secondo costante entro il secondo aggiornamento per migliaia di flussi di sensori individuali moltiplicati per migliaia di spettatori. Naturalmente, un server Web può essere partizionato o configurato in un framework di bilanciamento del carico, ma ci sono altri servizi personalizzati per la consegna dei sensori e il marshalling dei comandi sull'hardware.

Il server web dovrà fornire alcuni pacchetti in modo che la pagina possa stabilire canali di comunicazione sicuri con il dispositivo. Dobbiamo stare attenti all'invio di messaggi su canali che non forniscono una gestione dei tipi di messaggi che passano. È necessario sapere se un dispositivo è in una modalità che può essere interrotta o se può essere richiesta un'azione da parte dell'utente se un dispositivo è fuori controllo. Quindi, il server web può aiutare il client a ottenere le risorse appropriate che possono saperne di più sul dispositivo. La messaggistica potrebbe essere eseguita con qualcosa come un server MQTT. Inoltre, potrebbero esserci alcuni servizi per la preparazione del server MQTT che possono essere avviati quando l'utente accede al proprio pannello tramite il server web.

A causa del mondo fisico con i suoi requisiti in tempo reale e per ulteriori considerazioni sulla sicurezza, il nostro diagramma diventa leggermente diverso dall'originale.

Un'app a pagina singola che comunica con un MCU.
Un'app a pagina singola che comunica con un MCU. Ora interagisce in modo asincrono con l'MCU indipendentemente dal server della pagina web. (Grande anteprima)

Non possiamo fermarci qui. Configurare una singola pagina per dispositivo, anche se è reattivo e gestisce bene la comunicazione, non è quello che abbiamo chiesto. Dobbiamo presumere che un utente accederà al suo account e accederà alla sua dashboard. Da lì, chiederà un elenco di progetti di contenuti (molto probabilmente progetti su cui sta lavorando). Ciascun elemento dell'elenco farà riferimento a un numero di risorse. Quando seleziona un elemento facendo clic o toccando, avrà accesso a una raccolta di pannelli, ognuno dei quali conterrà alcune informazioni su una particolare risorsa o dispositivo IoT.

Un numero qualsiasi di pannelli consegnati in risposta alla query generata a seguito dell'azione dell'interfaccia utente può essere quei pannelli che interagiscono con i dispositivi attivi. Quindi, non appena viene visualizzato un pannello, ci si aspetta che mostri l'attività in tempo reale e che sia in grado di inviare un comando a un dispositivo.

Il modo in cui i pannelli vengono visualizzati sulla pagina è una decisione progettuale. Potrebbero essere finestre mobili o potrebbero essere caselle su uno sfondo scorrevole. Comunque sia presentato, i pannelli segneranno tempo, temperatura, pressione, velocità del vento o qualsiasi altra cosa tu possa immaginare. Ci aspettiamo che i pannelli siano animati rispetto a varie scale grafiche. La temperatura può essere presentata come un termometro, la velocità come un indicatore di velocità semicircolare, il suono come una forma d'onda in streaming e così via.

Il server web ha il compito di consegnare i pannelli giusti all'utente giusto in base alle query su un database di pannelli e dato che i dispositivi devono essere fisicamente disponibili. Inoltre, dato che ci saranno molti tipi diversi di dispositivi, i pannelli per ciascun dispositivo saranno probabilmente diversi. Quindi, il server web dovrebbe essere in grado di fornire le informazioni pittografiche necessarie per il rendering di un pannello. Tuttavia, la pagina HTML per la dashboard non dovrebbe essere caricata con tutti i possibili pannelli. Non si ha idea di quanti saranno.

Ecco alcuni parametri che potrebbero guidare le scelte per la nostra pagina dashboard, cose che dovrebbe fare:

  1. Presentare un modo per selezionare gruppi di pannelli di dispositivi correlati;
  2. Utilizzare meccanismi di comunicazione simultanea del dispositivo per un certo numero di dispositivi;
  3. Attivare i pannelli dei dispositivi quando l'utente li richiede;
  4. Incorpora grafica caricata pigramente per design di pannelli unici;
  5. Utilizzare token e parametri di sicurezza rispetto a ciascun pannello;
  6. Mantenere la sincronia con tutti i dispositivi sotto ispezione dell'utente.
Un'app a pagina singola che comunica con più MCU, in modo asincrono e indipendentemente dal server della pagina web.
Un'app a pagina singola che comunica con più MCU, in modo asincrono e indipendentemente dal server della pagina web. (Grande anteprima)

Possiamo iniziare a vedere come cambia il gioco, ma nel mondo del design della dashboard, il gioco sta cambiando un po' qua e là da un po' di tempo. Dobbiamo solo restringerci ad alcuni strumenti di sviluppo delle pagine aggiornati e utili per alzarci e andare avanti.

Cominciamo con come possiamo renderizzare i pannelli. Questo sembra già un grande lavoro. Stiamo immaginando molti diversi tipi di pannelli. Ma, se hai mai usato una DAW musicale, vedresti come hanno usato la grafica per far sembrare i pannelli come i dispositivi analogici usati dalle band di molto tempo fa. Tutti i pannelli nelle DAW sono disegnati dai plugin che operano sul suono. In effetti, molti di quei plug-in DAW potrebbero utilizzare SVG per eseguire il rendering delle loro interfacce. Quindi, ci limitiamo a gestire le interfacce SVG, che a loro volta possono essere qualsiasi grafica possiamo immaginare.

Scelta di SVG per i pannelli

Ovviamente, mi piacciono le DAW e le userei per un esempio, ma SVG è uno standard per le pagine web. SVG è uno standard del W3C. Serve per portare i disegni al tratto sulle pagine web. SVG era un cittadino di seconda classe sulla pagina Web, richiesto per vivere in iFrames. Ma, da HTML5, è stato un cittadino di prima classe. Forse, quando uscirà SVG2, sarà in grado di utilizzare gli elementi del modulo. Per ora, gli elementi del modulo sono oggetti estranei in SVG. Ma ciò non dovrebbe impedirci di rendere SVG il substrato per i pannelli.

SVG può essere disegnato, memorizzato per la visualizzazione e può essere caricato pigramente. Infatti, mentre esploriamo il sistema dei componenti, vedremo che SVG può essere utilizzato per i modelli dei componenti. In questa discussione, utilizzeremo Vue.js per creare componenti per i pannelli.

Disegnare SVG non è difficile, perché ci sono molti programmi per disegnare linee facili da ottenere. Se spendi i soldi, puoi ottenere Adobe Illustrator, che esporta SVG. Inkscape è da tempo un punto di riferimento per la creazione di SVG. È open source e funziona bene su Linux, ma può essere eseguito anche su Mac e Windows. Quindi, ci sono diversi programmi di modifica SVG di pagine Web open source e anche alcune versioni SaaS.

Ho cercato un editor SVG basato sul Web open source. Dopo aver guardato intorno, mi sono imbattuto in SVG-Edit. Puoi includerlo nelle tue pagine web, magari se stai creando un blog basato su SVG o qualcosa del genere.

Schema elettrico in SVG pronto per l'animazione.
Uno schema elettrico è abbastanza dettagliato, ma possiamo ottenerlo facilmente in SVG e animarlo con un piccolo codice. (Grande anteprima)

Quando salvi il tuo lavoro in un file, SVG-Edit lo scarica nel tuo browser e puoi prelevare il file dalla tua directory di download.

L'immagine che ho disegnato mostra una porta AND che controlla un integratore. Non è quello che ci si aspetterebbe di solito di vedere in un pannello per un MCU. Il pannello potrebbe avere un pulsante per alimentare uno degli ingressi del gate AND, forse. Quindi potrebbe avere un display da un ADC che legge l'output dell'integratore. Forse sarà un grafico a linee su un asse temporale. La maggior parte dei pannelli avrà una grafica che consentirà all'utente di relazionarsi con ciò che sta accadendo all'interno dell'MCU. E, se il nostro circuito vivrà da qualche parte, sarà all'interno dell'MCU.

Tuttavia, il nostro diagramma elettronico può essere utilizzato per discutere di animazione. Quello che vogliamo fare è dare un'occhiata all'SVG e vedere dove possiamo ottenere alcuni dei tag DOM che vorremmo cambiare in qualche modo. Possiamo quindi animare l'SVG usando un po' di JavaScript vanilla e un timer. Facciamo lampeggiare il cancello AND in diversi colori.

L'SVG che stiamo cercando si trova nella seguente casella di codice. Non sembra molto amichevole per il programmatore, anche se l'utente sarà abbastanza felice. Tuttavia, ci sono ancora alcuni spunti da seguire per trovare su quale elemento DOM vogliamo operare. Innanzitutto, la maggior parte degli strumenti di disegno SVG ha un modo per ottenere le proprietà degli oggetti, in particolare l'attributo id . Anche SVG-Edit ha un modo. Nell'editor, seleziona la porta AND e osserva la barra degli strumenti. Vedrai anche un campo per l' id e la class CSS.

Uno degli strumenti di disegno SVG con un modo per acquisire l'ID oggetto utilizzando l'interfaccia fornita.
Uno degli strumenti di disegno SVG con un modo per acquisire l'ID oggetto utilizzando l'interfaccia fornita. (Grande anteprima)

Se per qualche motivo non riesci ad accedere a uno strumento di modifica, puoi aprire l'SVG in un browser e ispezionare il DOM. In ogni caso, abbiamo riscontrato che il nostro gate aveva 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>

Tutto ciò di cui abbiamo bisogno ora è un po' di JavaScript. Prendiamo prima nota che l'attributo dell'elemento "riempimento" è presente. Poi c'è solo il semplice programma che segue:

 <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>

Si noti che ciò che abbiamo è una pagina HTML minima. Puoi tagliare e incollare il codice nel tuo editor preferito. E poi non dimenticare di tagliare e incollare l'SVG per sostituire il commento. La mia versione di Chrome richiede che la pagina sia HTML per avere la sezione JavaScript. Quindi, questo è un browser che tratta ancora SVG come qualcosa di separato. Ma è molto lontano dai giorni di <iframe> .

Se tagli e incolli correttamente, puoi visualizzare la pagina e vedere il cancello AND passare dal rosso al verde più e più volte.

Letture consigliate : SVG Circle Decomposition To Paths

Costruire pannelli da componenti VUE

Siamo già sulla buona strada per dare vita a ogni singolo pannello, ma se vogliamo gestire grandi raccolte di pannelli in modo sensato, avremmo il nostro lavoro ritagliato per noi. Ciò sarebbe particolarmente vero se ci limitassimo a basarci sul nostro primo esempio.

Mentre il primo esempio ci mostra come possiamo modificare in modo asincrono una vista di un oggetto, non ci mostra come legare la vista allo stato di qualsiasi oggetto dati per non parlare di uno che gestisce una macchina. Possiamo certamente capire come la dimostrazione setInterval possa essere sostituita da un gestore di fetch , ma potremmo anche non ottenere lo stato di una macchina dal server web che serve la pagina contenente SVG. Inoltre, quando otteniamo i dati, i nostri programmi ora devono conoscere la struttura DOM della pagina specificata.

Fortunatamente, framework come Vue sono diventati popolari e possono risparmiarci molto lavoro.

È facile scoprire Vue. La documentazione Vue è molto accessibile. Quindi, se questa discussione va troppo avanti, potresti dedicare un po' di tempo a conoscere Vue sul proprio sito web. Ma ci sono ottime discussioni all'interno delle pagine Smashing. Krutie Patel ha scritto un articolo straordinario sulla creazione di un'infografica. Souvik Sarkar ci spiega come costruire una dashboard meteo con Vue.

Selezione di gruppo di pannelli correlati

Per il primo passaggio, dovremmo affrontare la ricerca di gruppi di pannelli. Una delle ragioni per farlo prima è che si trova a livello di struttura delle nostre interazioni umane.

L'utente cerca qualcosa che gli interessa. Forse è interessato a tutti i dispositivi nelle posizioni di una città. Forse ha molti lotti di prodotti liquidi e vuole restringere il campo a un tipo di prodotto con ogni lotto governato da una piccola raccolta di dispositivi IoT. Quindi, l'utente cercherà prima per ottenere un piccolo elenco.

Ecco il processo:

  1. Cerca gruppi di pannelli per caratteristiche/parametri.
  2. Visualizza un elenco di icone che rappresentano i gruppi.
  3. Seleziona un'icona (clicca/tocca).
  4. Inizia a utilizzare i pannelli identificati con l'icona quando vengono visualizzati.

Un altro motivo per cui questo è un buon primo passo è che possiamo usare Vue nella sua forma più semplice. Non sono necessari strumenti di costruzione. Includeremo solo vue.js con un tag di script in HTML. In effetti, non dobbiamo nemmeno scaricarlo. Esiste un sito in cui viene pubblicata una copia funzionante di vue.js

Tutto ciò di cui abbiamo bisogno è il seguente tag:

 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

Ho copiato il tag dello script direttamente dalla documentazione di Vue sull'installazione.

Ora, abbiamo bisogno di una pagina web in grado di caricare le icone e trasformarle in qualcosa che scatta. Vue lo rende molto facile. In effetti, ho appena scritto una piccola app per gestire un elenco di Twitter utilizzando Vue. Gestisce solo i campi di testo. Poiché è un po' più semplice di un SPWA che utilizza le icone, possiamo dargli un'occhiata e quindi cambiarlo in modo che sia il framework dell'app a pagina singola desiderato.

Ecco una parte di come appare la pagina:

Una pagina di testo da utilizzare come punto di partenza per la creazione di un'applicazione grafica.
Una pagina di testo da utilizzare come punto di partenza per la creazione di un'applicazione grafica. (Grande anteprima)

Questa sembra una pagina abbastanza semplice. Ogni voce numerica esterna è una fascia oraria con uno o due tweet al suo interno. Il secondo tweet è facoltativo. Se modifichi un tweet, i meccanismi di Vue aggiornano un oggetto JavaScript. Questa pagina lascia all'utente la possibilità di fare clic sul pulsante "aggiorna voci" per dire al server che qualcosa è cambiato, tramite la sua funzione di gestione dei pulsanti.

Affinché il gestore del pulsante possa inoltrare i dati al server, deve modificare l'oggetto dati Vue in una stringa JSON. Ora, potresti chiederti quanto sarà difficile tradurre un oggetto Vue in JSON. Risulta essere una riga di codice. Puoi trovare la riga nel seguente codice sorgente, ma se vuoi trovarla più velocemente, è evidenziata nel paragrafo dopo il codice sorgente.

La pagina sembra semplice. L'apparenza inganna. Naturalmente, la pagina sembra semplice, ma il codice è semplice? Sì, in effetti lo è! Utilizzando Vue, la pagina gestisce quasi magicamente i contenuti dei campi. Ecco il codice:

 <!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>

Quindi, solo per evidenziare le linee sorprendenti che parlano della potenza del framework, ripetiamo qui:

R. Questo sta estraendo i dati.

 postOptionsObject.body = JSON.stringify(twtApp.tweets);

B. Questo sta inserendo i dati in Vue e vedendo l'aggiornamento dello schermo:

 twtApp.tweets = JSON.parse(text) // text is the server response

Quanto lavoro è?

Sembra che ci sarà un bel modo per esprimere come i dati aggiorneranno i pannelli per l'IoT.

Ora, trasformiamo i tweet in icone cliccabili progettate per recuperare i componenti dal server web.

Dai Tweet alle icone di recupero del pannello

Alla gente piace usare SVG per le icone. A loro piace quell'uso per SVG più che per altre cose per quanto posso dire. Sto solo andando sul numero di siti Web che vendono o regalano icone realizzate in SVG. Il punto di forza è che la grafica al tratto ha meno byte delle immagini. E, se avessi chiesto elenchi di immagini con un comportamento simile a un pulsante, avrei potuto afferrare PNG o JPEG nei giorni in cui SVG era negli iframe. 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.

Vue will quote the HTML an insert it as text.
Vue will quote the HTML an insert it as text. (Grande anteprima)

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> 
Using the right directive, Vue inserts DOM, resulting in the rendering of desired graphics.
Using the right directive, Vue inserts DOM, resulting in the rendering of desired graphics. (Grande anteprima)

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:

Icons that might be returned from a search for MCU groups.
An artistic idea suggesting how search could return icons indicating certain groups of MCU's to interact with. (Grande anteprima)

The data being sent is an array with the following kind of structure:

{ "style" : { "color" : "red", "backgroundColor" : "yellow" }, "icon" : svg1, "name" : "thermos" },

Qui, svg1 è SVG preso da un file. Naturalmente, un server corretto avrebbe preso la struttura da un database, in cui l'SVG sarebbe stato archiviato nella struttura.

Ecco uno snippet del codice sopra. Questo è il codice che recupera il JSON e inserisce l'array di strutture nell'app Vue. Puoi vedere la struttura della promessa di fetch in uso. Il testo viene analizzato e nella riga successiva l'SVG codificato viene decodificato. Ancora una riga e Vue aggiorna la pagina. Il numero di pulsanti nella barra dei pulsanti sarà uguale alla lunghezza dell'array 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; }); });

Ora, solo altri due frammenti. L'app Vue. Il lettore noterà che la direttiva @click è stata inclusa nei pulsanti. L'elemento dati, iconEntry.name , viene passato a un metodo tra virgolette.

Il metodo è definito all'interno dell'app Vue:

 <div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div>

Ecco lo snippet per la definizione dei metodi. L'oggetto methods viene aggiunto subito dopo l'oggetto data all'interno dell'oggetto parametro app:

 , methods: { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } }

Il lettore dovrebbe trovare la definizione di goGetPanel e il suo utilizzo è stato indicato per il gestore @click . Nella nostra applicazione finale, la chiamata di alert può essere sostituita da una funzione che recupera i pannelli dal server.

Una libreria di componenti per i pannelli IoT

Potremmo semplicemente decidere che i pannelli che recuperiamo dal server possono essere HTML o solo disegni SVG, ma se ci saranno molti tipi di pannelli, ci auguriamo che il lavoro di creazione dei pannelli possa essere semplificato disponendo di librerie di componenti per scegli da. Possiamo immaginare che gli editor SVG potrebbero essere migliorati per consentire ai componenti della libreria di essere rilasciati sulle immagini come parte della modifica. Quindi, se l'editor SVG potesse produrre una versione dell'immagine con tag componente, l'uso di Vue consentirebbe di creare l'immagine assicurando che l'automazione e l'animazione JavaScript siano ben intrecciate insieme. Per la nostra discussione, alcune modifiche manuali possono aiutarci ad arrivarci.

Se vogliamo creare pannelli dai componenti Vue, allora è meglio capire come realizzare i componenti e poi raccoglierli insieme in qualcosa di utile. Dovremo passare all'utilizzo degli strumenti da riga di comando forniti da Vue e organizzare il nostro flusso di lavoro.

Componenti

La documentazione Vue sottolinea che la sezione dei data del componente (oggetto secondario) della definizione del componente deve essere una funzione che restituisce dati. Il motivo è che Vue deve mantenere i dati separati tra le istanze. Quindi, passando dall'inizializzazione di un'applicazione Vue alla definizione di un componente, c'è un'altra piccola modifica al codice.

In questo primo frammento di codice viene inizializzata un'applicazione Vue:

 var iconApp = new Vue({ el: '#iconApp', data: { // this is the data field that can be easily updated }, methods : { ... } });

In questo nuovo frammento di codice, un componente viene definito e registrato. Innanzitutto, nota che invece di creare una new Vue , viene registrato un componente denominato iconic . Quindi, il campo data restituisce dati personalizzati per qualsiasi istanza iconic creata dall'app Vue. Infine, il campo template è presente al termine della registrazione del componente. Qualsiasi codice HTML che potrebbe essere stato scritto nella pagina Web per visualizzare il componente può far parte del 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>' });

Quindi, possiamo immaginare un pannello con termometri. Quindi, se qualcuno fornisse un componente thermometer , ci aspetteremmo una definizione di componente da qualche parte nel nostro codice. Come tale:

 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>' });

Stiamo cercando di creare qualcosa che assomigli a questo:

Applicazione termometro animata in Vue prima di esplorare i componenti.
Applicazione termometro animata in Vue prima di esplorare i componenti. (Grande anteprima)

Il componente termometro è molto simile ai primi componenti che incontrerai nei tutorial di Vue. Ma è un po' complicato capire come aggiornarlo. Esiste un modo migliore per definire il componente per la reattività utilizzando le proprietà. E questo è quanto segue:

 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' })

Quindi, invece di rappresentare la temperatura come elemento di dati. È rappresentato come una proprietà sotto props di scena. Quindi, c'è una nuova sezione, computed , che fornisce variabili che sono funzioni della proprietà. Vediamo this.temperature utilizzato sia per y che per height . Queste variabili calcolate vengono utilizzate nell'SVG come attributi per un rettangolo.

In SVG, y cresce dall'alto verso il basso. Quindi, quando vogliamo che il rettangolo nella parte inferiore del termometro sia piccolo, la y del riquadro rosso deve essere inferiore e l'altezza deve essere ridotta in modo che ( y + height ) rimanga allo zero del termometro.

Notare il campo template nella definizione dei componenti. Si tratta infatti di un ID elemento del documento. L'elemento a cui si fa riferimento è una sezione di script con il tipo speciale: type="text/x-template" . L'elemento script è dove si trova l'SVG per i termometri. Inoltre, l'SVG utilizza variabili Vue e termini di controllo in modo da poter definire la reattività.

Ecco alcuni degli 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"

Il lettore può trovare id="thermometer-template" in alto, e guardando più in basso agli elementi rect , si possono trovare le variabili calcolate.

Qui gli usi delle variabili sono separati. La sintassi abbreviata Vue per v-bind è in uso, con :height="height" e lo stesso per y :

 x="111.90748" :height="height" :y="y"

Quando il genitore degli elementi SVG imposta le variabili che fungono da input per la temperature della proprietà del termometro, Vue ricalcola l' height e y . Di conseguenza, la posizione e l'altezza del riquadro rosso cambiano.

Aiuta ad avere un elenco dell'app Vue che utilizza il termometro.

 <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>

Questo è tutto. Ci sono tre pulsanti che chiamano il metodo updateTemp dell'applicazione thermoApp Vue. La sezione dati ha due variabili di temperatura. Inoltre, ogni thermometer aggiorna la sua temperatura quando i valori cambiano.

Il codice per i due termometri richiamati di seguito si trova nell'HTML assegnato all'app Vue.

 <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer>

Si noti che l'applicazione utilizza il formalismo della function per la definizione del metodo. Definire updateTemp questo modo updateTemp: function (tval1,tval2) consente di accedere alla variabile di istanza this .

Inoltre, definendo updateTemp questo modo updateTemp: (tval1,tval2) => assegna this a una struttura dati interna che non reagisce e aggiorna la vista.

Assemblaggio di un pannello

Ogni pannello IoT può essere un componente. Vue fornisce un modo per definire i componenti con i sottocomponenti. In alternativa, esiste un meccanismo di slot che può essere utilizzato per produrre un componente che può avvolgere qualsiasi contenuto HTML.

Nei paragrafi seguenti, diamo un'occhiata alla creazione di un pannello con i sottocomponenti. Ci sono due forme che seguono rapidamente dai nostri esempi. In un caso, i termometri possono essere sottocomponenti richiamati in JavaScript. In un altro caso, i componenti sono definiti indipendentemente ma sono menzionati nell'HTML.

In entrambi i casi, è possibile utilizzare lo stesso HTML per il modello. Ecco il nostro pannello come modello:

 <script type="text/x-template"> <div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> </script>

L'unica differenza tra i primi dettagli dell'applicazione è che un elemento div circonda i due termometri. Vue genererà un errore se nel modello manca un elemento DOM di livello superiore. Il div supera il requisito Vue e gli elementi multipli possono essere inclusi al suo interno.

Ora possiamo vedere i due termometri fianco a fianco. Passare le temperature dall'alto al termometro finale ha valori che scendono a cascata. Al livello superiore, il pannello si unisce all'applicazione quando una singola riga è inclusa nel DOM dell'applicazione.

 <themo-panel :temp1="temp1" :temp2="temp2" ></themo-panel>

Il modello per il pannello, sebbene semplice, sembra indicare che i pannelli possono essere facilmente progettati in termini di componenti. È come se fosse possibile un linguaggio solo per i componenti IoT.

Ora, la definizione del modello per il pannello è abbastanza semplice. Eccolo con i sottocomponenti definiti indipendentemente:

 Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template' });

Questo è più o meno quanto è necessario per rendere funzionale il pannello. È vero che questa versione si basa su un lungo elenco di proprietà per definire i valori da aggiornare man mano che i messaggi entrano nella pagina. Ma questo è un buon inizio. L'aggiornamento dell'oggetto data al livello superiore svolge il compito di animare i termometri. Tuttavia, poiché i pannelli si complicano, potrebbe essere necessario un altro metodo per mostrare il cambiamento.

Dopo aver menzionato gli altri modi di specificare i sottocomponenti, per il pannello, dovremmo dargli un'occhiata. Ecco qui:

 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) } } } } });

C'è sicuramente più codice, ma è perché il JavaScript per il componente thermometer è incluso nell'elenco dei componenti di thermo-panel . I due approcci svolgono lo stesso lavoro, ma offrono modi diversi di confezionare le definizioni dei componenti.

Al momento, la mia preferenza è per il primo modo. Dovrebbe essere notevolmente più semplice rivedere i pannelli e farli recuperare dinamicamente se è richiesta solo la modifica del modello e delle proprietà. A tal fine, i componenti definiti in modo indipendente formano una libreria di componenti. Ma, sebbene ciò sembri migliore, nel seguito diventa più conveniente usare il secondo modo, apparentemente più dettagliato.

Dato che possiamo creare pannelli reattivi dai componenti in modi chiaramente definiti, spiegherò come gestirli come database in grado di eseguire semplici query nella parte successiva del mio articolo.