Genera e modifica grafica SVG dei dati provenienti da sensori collegati all'IoT con JavaScript

Genera e modifica grafica SVG dei dati provenienti da sensori collegati all'IoT con JavaScript

Genera e modifica grafica SVG dei dati provenienti da sensori collegati all'IoT con JavaScript

In quest'ultima parte della serie di articoli sul disegno grafica con dati provenienti da sensori collegati all'Internet of Things, è tempo di parlare di come generare o modificare con JavaScript disegni in formato SVG e alcuni degli elementi HTML che fungono da contenitore o che presentano informazioni complementari alla grafica.

Sommario

    Grafici di dati provenienti da sensori collegati al contenitore Internet of Things (IoT) in HTMLGrafici di dati provenienti da sensori collegati alla definizione dell'aspetto dell'Internet delle cose (IoT) nei CSSGrafici di dati provenienti da sensori collegati al disegno Internet of Things (IoT) con SVGGrafici di dati provenienti da sensori connessi all'Internet of Things (IoT) Generazione e modifica con JavaScript

    Si suppone che gli utenti target di questo tutorial formino un profilo di programmazione elettronica e informatica. microcontrollori, potrebbero non avere familiarità HTML, CSS o SVG; Per questo motivo nelle puntate precedenti è stata fatta una breve introduzione al linguaggio o alla tecnologia corrispondente. In quest'ultima parte l'approccio è un po' diverso, poiché i lettori sicuramente sanno programmare, è possibile che utilizzino il linguaggio C++ cosa come JavaScript, condivide la sintassi di base con C e può essere utilizzato come riferimento per tralasciare la maggior parte dei concetti di programmazione di base e concentrarsi quindi sulle differenze e sull'uso specifico che ci interessa creare la grafica dei sensori nell'IoT.

    Il nome dà un indizio sulla prima differenza: JavaScript È un linguaggio di programmazione copione (trattino) e come tale lo è interpretato, non è necessario compilarlo; il contesto in cui il copione (un browser web, ad esempio) leggerà, tradurrà ed eseguirà gli ordini. Per essere precisi, nella maggior parte dei casi esiste a compilazione runtime (JIT), ma per il processo di scrittura del codice JavaScript Non ci riguarda, scriviamo semplicemente il codice e può funzionare.

    Il nome contiene anche la prima confusione: JavaScript non ha la minima relazione con Java. Inizialmente, quando è stato sviluppato Netscape per il suo browser si chiamava prima Mocha e poi il meno confuso LiveScript. Dopo la sua implementazione di successo nei browser, e trascendendoli, è stato standardizzato come ECMAScript (A ECMA-262, versione 6 al momento in cui scrivo) di divenire neutrale rispetto ai browser che lo implementano. Attualmente esiste anche uno standard ISO dalla versione 5, 2011 (ISO / IEC 16262: 2011 al momento della stesura dell'articolo)

    Variabili, tipi di dati di base e oggetti in JavaScript

    A differenza di quanto avviene, ad esempio, in C++, en JavaScript tipo di dati non incluso quando si dichiara una variabile ed inoltre il tipo associato ad una variabile non è fisso, è possibile assegnare un valore di tipo diverso durante l'esecuzione del programma.

    Nell'esempio precedente si dichiara la variabile "cosa" (senza indicare il tipo di dato), poi si assegnano dati di tipo diverso e si consultano con typeof il tipo quello JavaScript che ha interpretato. Per eseguire il debug del codice puoi scriverlo nella console di ispezione del browser web (che non influirà sulla presentazione del web) con console.log().

    Per forzare la conversione dei dati in un tipo specifico, in particolare da testo a numerico, è possibile utilizzare funzioni come parseInt() o parseFloat() che vengono convertiti rispettivamente in numeri interi o in virgola mobile. Si può fare la conversione opposta String(), anche se è improbabile che sia necessario poiché in genere è sufficiente la conversione automatica. Con parseFloat()Ad esempio, puoi ottenere il valore di una proprietà di una pagina web, come la larghezza o l'altezza di un oggetto, che include unità; In questo modo, l'espressione parseFloat("50px"); restituirà 50, un valore numerico, come risultato.

    En JavaScript non c'è distinzione tra virgolette doppie e singole; Il tipo di dati in entrambi i casi è stringe ciascuno di essi può includere l'altro senza la necessità di codici di escape.

    Nell'esempio precedente si può vedere che una variabile, quando è stata dichiarata (esiste) ma non le è stato assegnato alcun valore, contiene un tipo di dato non definito (undefined). Un oggetto non assegnato ha il valore null; Cioè l'oggetto esiste, ma senza valore; una variabile che fa riferimento ad esso non avrebbe a typeof undefined Sino object. Un oggetto può anche essere vuoto, cioè non nullo ma non avere alcuna proprietà.

    a definire un oggetto in JavaScript sono racchiusi tra parentesi graffe ({ y }) le proprietà o i metodi, separati dal segno dei due punti (:) nome della proprietà valore della proprietà e tramite virgola (,) le diverse proprietà. Puoi trovare maggiori informazioni su questo modo di esprimere un oggetto nell'articolo su Formato JSON.

    Anche se puoi usare una sintassi che potrebbe portarti a pensare diversamente, en JavaScript Non ci sono classi ma prototipiCioè, affinché un oggetto erediti proprietà e metodi, viene creato un altro oggetto (il prototipo) che gli altri (i figli) usano come riferimento. La sintassi più vicina allo stile di JavaScript utilizzare un prototipo è Object.create sebbene sia anche possibile (e talvolta utile) utilizzarlo new come in altri linguaggi orientati agli oggetti.

    a interrogare se un oggetto è un'istanza di un altro, se lo usi come prototipo, se ne erediti le proprietà, insomma, puoi usarlo instanceof (creato con new) O isPrototypeOf (creato con Object.create) che valuterà true quando l'oggetto utilizza il prototipo e false quando non lo fa.

    Una volta che un oggetto è stato creato utilizzandone un altro come prototipo, cioè una volta che un oggetto è stato istanziato, può esserlo aggiungere nuove proprietà o sovrascrivere le proprietà del prototipo utilizzando la sintassi del punto come in gato.peso=2.5.

    La array in JavaScript Sono diversi da quelli che probabilmente conosci C. Innanzitutto vengono dichiarati senza bisogno di indicarne la lunghezza, solo con i segni di parentesi quadre aperte e chiuse ([ y ]), i componenti possono essere eterogenei (diversi tipi di dati nello stesso array) e nuovi elementi possono essere aggiunti senza essere vincolati da un limite. Le matrici di JavaScript sono in realtà elenchi (raccolte) di elementi a cui referenziato da un indice numerico o da un nome. Un array può contenere contemporaneamente indici numerici e nomi di elementi, ma è comune utilizzare oggetti (proprietà) per sfruttare il secondo tipo.

    Come si può vedere nell'esempio precedente, per sapere se una variabile corrisponde ad un'istanza di un array (è un oggetto array) si può usare instanceof, come è già stato utilizzato con oggetti generici o, nelle versioni più recenti di JavaScript si può ricorrere Array.isArray()

    Per accedere agli elementi dell'array è possibile utilizzare il suo indice (matriz[7]) oppure dal nome della struttura con il nome tra parentesi quadre (matriz["nombre"]) o con la consueta sintassi del punto per gli oggetti (matriz.nombre). Poiché il nome è una stringa di testo, per comporlo è possibile utilizzare un'espressione, incluse le variabili. Per scorrere un array con proprietà, è possibile utilizzare un ciclo con il formato for(propiedad in matriz).

    È interessante trattare per il nostro obiettivo l'oggetto Date, con cui rappresentare e gestire data e ora in JavaScript. L'oggetto può essere istanziato senza dati, quindi prenderà la data e l'ora correnti, oppure può essere creato indicando una data come valore, in millisecondi dal 1 gennaio 1970 (come ad esempio Ora Unix o ora POSIX ma espresso in millisecondi invece che in secondi) o specificando valori separati di anno, mese, giorno, ora...

    L'oggetto comprende una serie completa di metodi per interrogare o impostare la data e l'ora:

    • now()
      Restituisce la data e l'ora correnti espresse in millisecondi dal 1 gennaio 1970

    • getTime() | setTime()
      Ottiene o modifica, rispettivamente, il valore temporale in millisecondi dal 1 gennaio 1970. Using valueOf(), che è un metodo presente nella maggior parte degli oggetti, si ottiene anche il valore dell'oggetto Date corrispondente, ad esempio getTime() con Ora Unix o ora POSIX espresso nel ms.

    • getMilliseconds() | setMilliseconds()
      Utilizzato per interrogare o impostare la parte frazionaria in millisecondi dell'oggetto Date su cui viene eseguito. Se consultato il valore ottenuto è compreso tra 0 e 999 ma si possono assegnare valori maggiori che si accumuleranno nel totale di data e ora quindi, come il resto dei metodi get, serve ad aumentare il valore dell'oggetto Date (o diminuirlo, se si utilizzano valori negativi).

    • getSeconds() | setSeconds()
      Restituisce o modifica, rispettivamente, il valore dei secondi dell'oggetto Date.

    • getMinutes() | setMinutes()
      Utilizzato per consultare o impostare i verbali dell'oggetto Date.

    • getHours() | setHours()
      Permette di consultare o modificare gli orari (da 0 a 23) dell'oggetto Date.

    • getDay()
      Restituisce il giorno della settimana per la data, espresso come valore compreso tra 0 e 6 (da domenica a sabato).

    • getDate() | setDate()
      Restituisce o modifica il giorno del mese dell'oggetto Date su cui viene applicato.

    • getMonth() | setMonth()
      Utilizzato per consultare o modificare il numero del mese dell'oggetto Date.

    • getFullYear() | setFullYear()
      Interroga o imposta il valore dell'anno sull'oggetto contenente la data e l'ora.

    I metodi precedenti di Date includere una versione UTC poter lavorare direttamente con il tempo universale senza dover fare calcoli intermedi. In tal senso, ad es. getHours() ha una versione getUTCHours() o getMilliseconds() un'alternativa getUTCMilliseconds() per lavorare alternativamente con l'ora ufficiale (legale) o universale. Con getTimezoneOffset() Puoi conoscere la differenza che esiste tra l'ora universale e l'ora ufficiale locale.

    Funzioni JavaScript

    Se stai leggendo questo articolo sicuramente sai come programmare. microcontrollori en C o su C++ e conoscere il concetto di funzione. Sebbene l'idea di base sia la stessa, in JavaScript Il modo in cui vengono definiti e utilizzati è leggermente diverso. Tanto per cominciare, è già stato detto: JavaScript Non utilizza esplicitamente i tipi di dati, quindi non è necessario indicarlo quando si definisce la funzione. Da seguire, Non è obbligatorio che una funzione abbia un nome, possono essere anonime. Si possono associare ad una variabile per invocarle ma può anche non essere necessario poiché, a volte, è utile invocarle subito, per cui le parentesi ed i parametri vengono aggiunti dopo la definizione della funzione.

    Per definire una funzione, prefisso function, se applicabile, scrivi il nome, gli argomenti (i parametri passati alla funzione) tra parentesi e il codice che verrà eseguito quando la funzione viene invocata tra parentesi graffe.

    Certamente nell’esempio precedente la variabile “risultato” non serviva affatto, ma è una buona scusa per ricordare il portata variabile, che funziona come previsto: la variabile "risultato" esiste solo all'interno della funzione "double". In JavaScript può anche essere utilizzato let, invece di var, per definire l'ambito di una variabile in un contesto di blocco di codice (racchiuso tra parentesi graffe, { y })

    Parlando degli oggetti nella sezione precedente mancava qualcosa di fondamentale: sono state definite le proprietà ma non sono stati definiti i metodi. Come previsto, i metodi degli oggetti sono funzioni, non hanno nome e vengono utilizzati (invocati) dal nome (proprietà) assegnato dalla definizione dell'oggetto.

    Nell'esempio precedente esiste già un metodo, "view_temperature", che visualizza il valore della proprietà "current_temperature" attraverso la console. Non è molto utile, ma dà un'idea più completa di come sia la definizione di un oggetto JavaScript.

    Per accedere ai metodi di un oggetto (funzioni) alle sue proprietà, utilizzare this, come nell'esempio precedente alla riga 11, quando si utilizza la proprietà “current_temperature”.

    Accedi al Document Object Model (DOM) con JavaScript

    Noi di JavaScript Hai accesso al contenuto della pagina web su cui viene eseguito, nonché ad alcuni aspetti del browser che visualizza quella pagina, ma non alle risorse di sistema. La struttura dati che supporta le proprietà e i metodi da cui si accede JavaScript parte dell'oggetto finestra, nello specifico, il contenuto dell'oggetto (il document HTML) corrisponde all'oggetto document. Anche se talvolta viene utilizzato per chiarezza, non è necessario precedere window ai metodi o alle proprietà per fare riferimento ad essi, è sufficiente, ad esempio, utilizzare document, non è necessario scrivere il nome dell'oggetto root come in window.document, purché si faccia riferimento alla finestra corrente.

    La forma più utilizzata di trovare un oggetto all'interno del documento HTML È attraverso il metodo getElementById(), a cui viene passato come argomento l'id indicato in fase di creazione del codice HTML. Da quanto spiegato nei paragrafi precedenti è facile supporre che sia possibile accedere anche ai componenti interni all'oggetto document utilizzando la sintassi del punto (document.componente) o parentesi utilizzando sia il nome (document["componente"]), quelli più utili, come l'indice numerico, difficile da usare e poco pratico quando si accede al contenuto di una pagina web composta manualmente.

    Con JavaScript possono essere ottieni l'elemento che contiene un altro elemento (elemento o nodo genitore) consultando il tuo immobile parentNode o la tua proprietà parentElement, la differenza è che l'elemento genitore (parentElement) dell'elemento finale della stringa DOM È nullo (null) e il nodo genitore (parentNode) è il documento stesso (document).

    a modificare il contenuto di un elemento HTML, ad esempio quello di un'etichetta <div>, Può essere usato innerHTML e per modificarne le proprietà puoi scegliere di assegnargli una classe diversa className o alterare le sue proprietà individualmente con style. Consultare lo stile visualizzato da un elemento nella pagina web non è necessariamente utile style poiché può dipendere da diversi fattori o semplicemente non essere stato esplicitamente specificato. Per verificare lo stile di un elemento finalmente visualizzato sulla pagina web, viene utilizzato il metodo getComputedStyle.

    A un elemento del documento HTML È possibile assegnargli diverse classi per determinarne l'aspetto e il comportamento gestire l'elenco delle classi di un oggetto da JavaScript si può ricorrere classList che offre i metodi add per aggiungere una nuova classe all'elenco, remove per rimuoverlo, toggle per sostituirlo o consultare il contenuto dell'elenco delle classi di un elemento con item e contains, che restituisce la classe che occupa una determinata posizione nell'elenco e un valore true o false se una determinata classe è o meno nell'elenco.

    Nell'esempio precedente si trova con getElementById l'oggetto che vuoi manipolare (un elemento <div> grazie alla id), prima di modificare l'aspetto, il contenuto viene eliminato assegnandolo con innerHTML una stringa di testo vuota, le viene assegnata una nuova classe className e il suo stile viene modificato con style a seconda del valore del contenuto (temperatura), cambiando il colore, se applicabile, attraverso la proprietà color. Una volta stabilito l'aspetto, il valore viene scritto utilizzando nuovamente innerHTML.

    Nella seconda parte dell'esempio precedente (righe da 9 a 19) si accede ad un elemento di codice HTML utilizzando la sintassi document[] e la proprietà id dell'elemento per modificare la sua lista di classi con il metodo classList.remove() e con il metodoclassList.add(), in base al risultato di diverse query eseguite in esecuzioni condizionali, che confrontano utilizzando classList.contains().

    Quando succederà fare riferimento ad un elemento HTML alcuni volte in tutto il codice JavaScript, è un po' più efficiente assegnarlo a una variabile oppure usa il suo indice al posto del nome poiché, altrimenti, il metodo che utilizzeresti JavaScript per ottenerlo ogni volta sarebbe necessario cercarne il nome, consumando un po' più tempo che se si accedesse a una variabile.

    a aggiungere nuovi oggetti al documento HTML, possono essere creati prima con il metodo createElement de document e successivamente incorporarli al resto degli elementi nel punto dell'albero necessario appendChild. Per creare un oggetto XML, come gli oggetti SVG che usiamo per disegnare il grafico dei sensori IoT, puoi utilizzare createElementNS (NS per spazio dei nomi). Come spiegato parlando del formato SVG, lo spazio dei nomi che corrisponde ad esso (per la versione corrente) è http://www.w3.org/2000/svg, a cui dovrebbe essere passato createElementNS come argomento insieme al tipo di elemento, svg, in questo caso.

    Un in alternativa a innerHTML per aggiungere testo come contenuto a un elemento del documento HTML è il metodo createTextNode() dell'oggetto document. Con questa alternativa puoi creare un nuovo testo (a cui si accede successivamente se assegnato a una variabile) che viene incorporato nell'albero degli oggetti con il metodo appendChild(). come in alternativa a appendChild(), che aggiunge il nuovo contenuto alla fine di quello già esistente nel nodo a cui viene aggiunto, puoi utilizzare il metodo insertBefore(), che aggiunge un nuovo oggetto davanti a uno esistente. Indossare insertBefore() al posto di appendChild() fornisce un metodo che serve, ad esempio, a ordinare i nuovi oggetti davanti a quelli esistenti quando un elemento deve stare davanti ad un altro (come in una lista) oppure coprire o essere coperto in una struttura grafica in cui sono presenti elementi più vicini al primo piano o allo sfondo.

    Reagire agli eventi con JavaScript

    Quando il modo di utilizzare una pagina web come contenitore per i grafici dei sensori connessi all'IoT è stato usato onload Nell'etichetta <body> per iniziare a disegnare il grafico. Questa proprietà, associata agli oggetti del codice HTML, si riferisce a Eventi JavaScript. Come già spiegato, esegue una funzione quando la pagina viene caricata. Sebbene sia stato associato al codice HTML per tenerlo più presente, avrebbe potuto essere scritto nel codice JavaScript come body.onload=dibujar; siendo dibujar il nome della funzione che dovrebbe essere avviata al caricamento della pagina web.

    Nelle versioni più recenti di JavaScript gli eventi possono essere associati alle funzioni utilizzando addEventListener con il formato objeto.addEventListener(evento,función); o utilizzando la sintassi objeto.evento=función; che funziona anche nelle implementazioni precedenti. Per scollegare la funzione associata all'evento, devi removeEventListener che ha lo stesso formato di addEventListener.

    JavaScript È in grado di reagire a una moltitudine di eventi che possono verificarsi su una pagina web. Ad esempio, può rilevare quando viene fatto clic su un elemento HTML con onmousedowno quando si fa clic con onclick, quando si preme un tasto con onkeydown, agendo sulla barra di scorrimento con onscroll. Per il nostro scopo ci basta farlo rilevare il caricamento della pagina con onload e il suo ridimensionamento con onresize. Associamo questi eventi agli oggetti body y window del DOM rispettivamente. Il primo può essere assegnato nel codice HTML, come visto e il secondo all'interno del codice JavaScript all'interno della funzione chiamata dal primo e con il formato window.onresize=redimensionar; siendo redimensionar la funzione che verrà chiamata ogni volta che la finestra cambia dimensione.

    Esegui dopo un intervallo di tempo

    JavaScript ha due risorse per esecuzione differita: setTimeout, che esegue una funzione dopo un intervallo di tempo e setInterval che eseguirà una funzione ogni determinato intervallo di tempo. Entrambi i metodi richiedono come parametri (1) la funzione invocata e (2) l'intervallo di tempo espresso in millisecondi. Per interrompere la loro operazione, puoi assegnare il risultato restituito da queste funzioni a variabili e passarle come argomento clearTimeout oppure a clearInterval quando non vuoi richiamarli nuovamente (o quando non vuoi che vengano eseguiti per la prima volta) setTimeout o setInterval rispettivamente.

    Nell'esempio precedente viene introdotto il metodo alert che serve per esporre un segnale di avvertimento. Sebbene fosse ampiamente utilizzato in passato, attualmente è quasi bandito dal codice JavaScript a causa di quanto sia aggressivo (intrusivo) coprire la pagina web con una finestra di dialogo.

    In un programma scritto per a microcontrollore di una piccola serie (come quella del piatto Arduino Uno) è comune utilizzare variabili globali, come nell'esempio precedente in JavaScript, poiché il codice è breve e non particolarmente confuso, perché molte volte le funzioni sono implementate ad hoc e perché l'utilizzo di variabili globali permette di prevedere in modo molto semplice ed intuitivo l'utilizzo della memoria, cosa fondamentale in sistemi con poche risorse . Invece, en JavaScript È prassi comune ridurre al minimo possibile l'uso delle variabili globali. perché non ha bisogno di affrettare l'utilizzo della memoria, poiché funziona normalmente su a CPU con risorse di gran lunga superiori a quelle di a MCU, perché è probabile che coesista con molto codice di terze parti con cui deve interagire senza interferire e poiché è un sistema aperto, non è possibile prevedere il futuro contesto di esecuzione (il programma di un microcontrollore small determina completamente il suo funzionamento senza aggiungere altro codice una volta in funzione) sia perché le dimensioni delle applicazioni potrebbero renderne difficoltosa la lettura se il codice non incapsula il suo funzionamento, rendendo i metodi quanto più autocontenuti possibile.

    Operazioni matematiche con l'oggetto JavaScript Math

    Nell'oggetto sono raggruppate le operazioni matematiche di calcolo matematico più complesse Math. Questo oggetto viene utilizzato direttamente, non è necessario istanziarlo per utilizzare i metodi o le proprietà (costanti) che incorpora.

    • Math.abs(n) Valore assoluto del parametro n
    • Math.acos(n) Arcocoseno del parametro n (risultato in radianti)
    • Math.asin(n) Arcoseno del parametro n (risultato in radianti)
    • Math.atan(n) Arcotangente del parametro n (risultato in radianti)
    • Math.atan2(n,m) Arcotangente di n/m (risultato in radianti)
    • Math.ceil(n) Arrotondare il parametro all'intero più vicino
    • Math.cos(α) Coseno del parametro α (α in radianti)
    • Math.E e numero (≃2.718281828459045)
    • Math.exp(n) e elevato al parametro n: en
    • Math.floor(n) Arrotonda per difetto il parametro n all'intero più vicino
    • Math.log(n) Logaritmo naturale (base e) del parametro n
    • Math.LN2 Logaritmo naturale (base e) di 2 (≃0.6931471805599453)
    • Math.LN10 Logaritmo naturale (base e) di 10 (≃2.302585092994046)
    • Math.LOG2E Logaritmo in base 2 di e (≃1.4426950408889634)
    • Math.LOG10E Logaritmo in base 10 di e (≃0.4342944819032518)
    • Math.max(a,b,c,…) Valore più grande dell'elenco di parametri passati
    • Math.min(a,b,c,…) Valore più piccolo dell'elenco di parametri passati
    • Math.PI Numero π (≃3.141592653589793)
    • Math.pow(n,m) Primo parametro n elevato a secondo parametro m: nm
    • Math.random() Numero (quasi) casuale compreso tra 0.0 e 1.0
    • Math.round(n) Arrotondare il parametro n all'intero più vicino
    • Math.sin(α) Seno del parametro α (α in radianti)
    • Math.sqrt(n) Radice quadrata del parametro n
    • Math.SQRT1_2 Radice quadrata di 1/2 (≃0.7071067811865476)
    • Math.SQRT2 Radice quadrata di 2 (≃1.4142135623730951)
    • Math.tan(α) Tangente del parametro α (α in radianti)

    Carica i dati dal server con AJAX

    Il metodo seguito per ricavare le informazioni archiviate nell'IoT consiste nel caricare di volta in volta i dati dal server e ridisegnare il grafico con cui vengono rappresentati. Per leggere i dati dal server, viene utilizzata la tecnologia AJAX (JavaScript asincrono e XML) attraverso un oggetto XMLHttpRequest de JavaScript. La tracciatura del grafico dei dati viene eseguita riutilizzando un oggetto SVG che è già nel codice HTML e che contiene un grafico le cui coordinate vengono modificate per farle corrispondere ai nuovi dati caricati.

    Nell'esempio di questa proposta, oltre ad aggiornare il disegno, viene aggiornato anche un testo nella pagina web che riporta per ogni grafico la data e il valore dell'ultimo dato misurato.

    Lato server c'è un database che contiene le informazioni che i sensori collegati all'IoT hanno monitorato. Questo database viene letto dalla richiesta dell'oggetto XMLHttpRequest rispondendo con le informazioni codificate nel file Formato JSON, sebbene il nome del metodo utilizzato suggerisca una relazione con il formato XML.

    Nel primo tutorial di polaridad.es sul Archiviazione dei dati dell'IoT Puoi vedere un esempio di infrastruttura per gestire, lato server, le informazioni fornite dai dispositivi connessi all'Internet of Things. In questa serie di articoli un server viene utilizzato come risorsa Apache da cui è possibile utilizzare il linguaggio di programmazione PHP per accedere ad un database MySQL o MariaDB. Sui server utilizzati per supportare l'IoT è molto comune trovare database MongoDB (NoSQL) e il linguaggio di programmazione JavaScript su Node.js come infrastruttura software.

    La funzione successiva è responsabile della richiesta dei dati più recenti da uno dei sensori al server. Nella chiamata di funzione, l'oggetto viene utilizzato come argomento JavaScript che supporta i dati disegnati. Se lo stesso grafico rappresenta più valori, ad esempio per cercare visivamente una correlazione, è possibile richiedere al server di restituirne più contemporaneamente, metodo più ottimale per il modo in cui funziona il server. Protocollo HTTP.

    Nella terza riga dell'esempio precedente viene preparata la query che verrà fatta al server, nella quale verrà passato l'argomento "zona", il cui valore sarà il nome o il codice del luogo monitorato poiché le informazioni sulla Nello stesso database possono coesistere sensori diversi (ad esempio termometri che misurano la temperatura in stanze diverse). Il parametro passato alla funzione precedente, l'oggetto con i dati del grafico, dovrebbe includere una proprietà con il nome della stanza ("name_suffix").

    Tra le righe 7 e 14 del codice precedente, l' oggetto XMLHttpRequest che è memorizzato nella variabile "ajax". Prima di scegliere come creare l'oggetto, si effettua una ricerca window Se XMLHttpRequest non era disponibile (cosa che accadeva nelle vecchie versioni di Explorer di Microsoft e sebbene sia molto indietro, serve come esempio di alternative per creare l'oggetto utilizzando la sintassi (più nativa)) Object.create o new, simile a quello di altri linguaggi orientati agli oggetti.

    Per poter gestire immediatamente la risposta, il codice che la gestisce viene preparato nelle righe da 15 a 26 prima di effettuare la richiesta al server.

    La forma di eseguire la query HTTP al server è costituito da aprire una connessione con open indicando tipologia e pagina (a scelta nome utente e password), preparare le intestazioni del protocollo con setRequestHeader y inviare la richiesta con send. L'intestazione HTTP Content-length dovrai conoscere la lunghezza della query (numero di caratteri) calcolata utilizzando length.

    Quando la richiesta AJAX è pronto, viene eseguita la funzione associata all'evento onreadystatechange. Invece di assegnare una funzione, nell'esempio precedente viene definita al volo una funzione anonima che gestirà la ricezione dei dati in arrivo dal server. Innanzitutto, alla riga 18, si verifica che lo stato della richiesta sia "finita", che corrisponde al valore 4 della proprietà readyState, che lo stato è "OK" del Protocollo HTTP (codice 200) ottenibile dalla proprietà status e che i dati che sono arrivati ​​lo sono Formato JSON, consultando la proprietà responseType.

    Una volta verificato che lo stato della risposta sia quello previsto, nella riga 20 dell'esempio precedente crea un oggetto con il risultato, convertendo il testo JSON. La risposta prevede che venga restituita una data, questo permette di vedere se il risultato che il server invia era già stato precedentemente rappresentato nel grafico, che viene verificato alla riga 21. Se il dato è nuovo, alla riga 23 La funzione che è responsabile di ridisegnare il grafico con le nuove informazioni.

    L'idea nel proporre questo metodo di lettura è che i dati verranno aggiornati molto frequentemente. Se le informazioni presentate corrispondono ad un lungo periodo (come ad esempio le temperature di un giorno o di una settimana), si può implementare una prima richiesta che raccolga tutti i dati disponibili e poi una, simile a quella dell'esempio, che li aggiorni entro il periodo corrispondente.

    Genera dati casuali per i test

    Quando tutta l'infrastruttura server e client sarà pronta, una funzione come quella della sezione precedente si occuperà di leggere i dati e di disegnare con essi il grafico, ma Nella fase di test potrebbe essere più pratico utilizzare numeri casuali all'interno di un intervallo controllato per vedere se il codice scritto è corretto. La seguente funzione può servire da esempio per ottenere dati durante la creazione dell'applicazione finale.

    Invece di leggere le informazioni da un database, l'esempio sopra le genera in modo casuale e le passa alla funzione incaricata di disegnare il grafico. Il dato inventato è un vettore formato da una data espressa come valore in millisecondi, il momento della registrazione delle informazioni del sensore, e il dato monitorato, che è compreso tra un valore massimo e un valore minimo.

    In questo esempio, quando si genera una data, questa può essere ritardata fino a un secondo (1000 millisecondi) rispetto alla data al momento dell'invenzione. COME Math.random() genera un numero compreso tra 0.0 e 1.0, moltiplicandolo per 1000 produce un numero compreso tra 0 e 1000 che viene poi convertito in un numero intero. Allo stesso modo, il valore si ottiene moltiplicando il numero casuale per l'intervallo (massimo meno minimo) e aggiungendo il minimo.

    Disegna il grafico dei sensori IoT con un grafico SVG

    Visto che abbiamo visto come possiamo ottenere i valori che vogliamo rappresentare (la temperatura, nell'esempio) e la loro collocazione temporale, che possono essere espressi insieme sotto forma di coordinate, nell'esempio seguente viene mostrata una funzione per disegnare un percorso che unisce quei punti ed eventualmente un'area colorata delimitata da quella linea in alto. Il risultato sarebbe come l'immagine seguente.

    Esempio di grafico generato con SVG e JavaScript per rappresentare i dati provenienti dai sensori IoT

    L'asse orizzontale (X) del grafico rappresenta il tempo e l'asse verticale (Y) i valori che i sensori collegati all'IoT hanno monitorato. L'intervallo orizzontale è di pochi secondi poiché in questa proposta il grafico viene aggiornato molto frequentemente (ogni secondo, ad esempio) per fornire informazioni quasi in tempo reale sullo stato dei sensori.

    Nel codice precedente ci sono due aspetti interessanti, in primo luogo il calcolo che permette adattare l'intervallo di valori rappresentati e in secondo luogo il costruzione di immobili d che indica le coordinate dei punti sul tracciato (path).

    Per adattare l'intervallo di valori rappresentati, questi vengono spostati da un minimo e scalati in modo che la grandezza visibile corrisponda alla dimensione del grafico. Nel caso dell'orario, l'offset si ottiene sottraendo l'intervallo che si vuole visualizzare all'orario più lungo (data e ora più vicine a quella attuale) (20 secondi nell'esempio). Lo spostamento dei valori di temperatura è quello dell'intervallo inferiore (un grado) meno il valore più basso, in modo che i dati riportati di seguito siano i più simili al valore più basso consentito ma lasciando un margine che ci permetta di apprezzare quanto passato

    Il coefficiente che moltiplica i valori temporali per ottenere le coordinate orizzontali del grafico si ottiene dividendo la larghezza totale del grafico (100 unità nell'esempio) per l'intervallo temporale rappresentato (20 secondi nell'esempio). Per ottenere il coefficiente con i valori scalari della temperatura occorre ricordare che l'intervallo rappresentato va da un margine inferiore al valore minimo ad un margine superiore al massimo, un grado in entrambi i casi. In questo modo il coefficiente di scala verticale risulta dividendo l'altezza del grafico (100 unità nell'esempio) per il valore massimo, meno il minimo più il margine superiore e inferiore. Poiché questi valori potrebbero svilupparsi completamente a temperature negative, utilizziamo Math.abs() utilizzare il valore assoluto della differenza.

    La proprietà d dell'oggetto path Si costruisce concatenando le coordinate dei punti in un testo. Ogni coppia di coordinate è preceduta da un codice SVG L, che traccia una linea dalla posizione corrente a un valore assoluto indicato dalle coordinate. I valori X e Y sono separati da virgole e ciascuna operazione SVG è separato da uno spazio dal successivo.

    Per avviare il layout, utilizzare il codice M (spostarsi su una coordinata assoluta). Nel caso del grafico chiuso e riempito si inizia in basso a destra, nel caso del grafico aperto che disegna il profilo dei dati si inizia dall'ultimo valore rappresentato (il più recente). Per completare il layout chiuso, viene utilizzato il codice Z aggiungendo come ultimo punto quello che ha lo stesso valore di coordinata X dell'ultimo punto della linea e come coordinata Y il valore più piccolo rappresentato.

    In questo esempio, la funzione dibujar_grafico(), che è la chiamata al caricamento della pagina, ottiene i valori iniziali da testare (non l'ultimo valore in tempo reale) e prepara l'intervallo in cui verranno visualizzati i dati: 20 secondi (20000 ms) in orizzontale e 15°C in verticale da -5°C a +10°C con margine superiore e inferiore di un grado. Fai due chiamate a actualizar_grafico(), al primo passaggio true come argomento, che indica che il grafico deve essere chiuso per rappresentare un'area piena, e alla seconda chiamata passa false per tracciare la linea. In ogni caso, l'oggetto path modificato è quello che ha l'aspetto corrispondente, con riempimento e senza bordo nel primo caso e con un certo spessore di linea e senza riempimento nel secondo.

    La funzione actualizar_grafico() lavorare su un oggetto SVG che utilizza il seguente codice come contenitore HTML. L'oggetto SVG contiene due percorsi, uno per disegnare la linea e un altro per disegnare l'area riempita. Quando si carica la pagina web, dall'elemento <body> la funzione precedente viene chiamata automaticamente, dibujar_grafico() grazie all'evento JavaScript onload.

    Alla riga 10 del codice HTML sopra, nello stile è stabilita una larghezza (per esempio) di 820 px e un'altezza di 150 px (cosa che, nella versione finale, sarà opportuno fare con una classe e un documento CSS). Sembra strano che le righe 13 e 14 definiscano la dimensione dell'oggetto SVG come larghezza e altezza al 100% (che corrisponde meglio alle dimensioni della finestra, 100×100). Come già accennato, lo scopo di ciò è lavorare sempre con dimensioni note e adattare ad esse i valori rappresentati. Le altre alternative sarebbero calcolare ogni volta lo spazio del grafico e poi riadattare i valori o forzare dimensioni fisse del grafico, alle quali il documento dovrà attenersi.

    Avendo optato per un grafico le cui dimensioni cambiano a seconda del codice HTML, è necessario includere l'immobile vector-effect con il valore non-scaling-stroke per evitare che gli spessori delle linee si deformino quando il grafico non mantiene le proporzioni 1:1 scelte nella pagina web in cui viene visualizzato, come avviene nella proposta precedente.

    Per "ritagliare" il grafico e mostrare solo l'area scelta, utilizza viewBox. In questo caso abbiamo scelto di vedere la parte del grafico che inizia da 0,0 (angolo in alto a sinistra) e misura 100x100 in basso e a destra. La parte del disegno situata in coordinate con valori negativi o superiori a 100 non verrà visualizzata nella pagina web anche se esistono nell'oggetto SVG

    Aggiungi nuovi elementi al disegno SVG

    Nell'esempio precedente, la funzione actualizar_grafico() utilizzare un layout SVG a cui viene cambiata la proprietà d, che è ciò che esprime la catena di coordinate. L'alternativa sarebbe creare l'intero oggetto ogni volta che viene ridisegnato. Il vantaggio della prima opzione è che l'aspetto grafico (come spessore o colore) è definito nel codice HTML, la limitazione è che gli oggetti devono essere creati precedentemente.

    Per creare oggetti SVG, utilizzare createElementNS(), che consente di includere il spazio dei nomi. Nell'esempio seguente viene creato un nuovo oggetto di testo (text) ed è associato a un elemento SVG che già esiste nel codice HTML del sito web. Una volta creato il nuovo elemento, le sue proprietà vengono assegnate con setAttribute() e viene aggiunto a SVG con appendChild().

    Modifica la proporzione degli elementi del disegno

    Se hai provato ad etichettare con la funzione dell'esempio della sezione precedente, avrai visto che il testo appare deformato quando la proporzione dell'oggetto sulla pagina web (width y height Di codice HTML) non è uguale a quella dell'area rappresentata (viewBox). Per adattare la proporzione è necessario conoscere le misure dell'oggetto SVG per cui puoi consultare lo stile dell'oggetto, ovvero del contenitore HTML, se l'oggetto SVG trasferire questa proprietà. Assegnazione della proprietà transform agli oggetti SVG che dipendono dalla proporzione, la deformazione può essere corretta applicando un'operazione di ridimensionamento scale() in cui il coefficiente in X è diverso da quello in Y.

    SVG consente di raggruppare più oggetti formando un nuovo elemento composito che supporta anche le proprietà, come oggetti semplici. Per applicare la stessa trasformazione a una serie di oggetti contemporaneamente invece che a ciascun oggetto separatamente, puoi raggrupparli in base a questa risorsa e applicare un'unica proprietà transform a tutti loro.

    Come spiegato quando si parla di Formato SVG, gli elementi di un gruppo sono racchiusi all'interno delle etichette <g> y </g>. Per aggiungere da JavaScript elementi ad un gruppo SVG viene utilizzato, come visto nell'esempio precedente, appendChild() una volta definito il nuovo oggetto.

    Per stabilire un'origine quando si applicano le trasformazioni, la proprietà può essere utilizzata sugli oggetti SVG transform-origin, il cui valore sono le coordinate X e Y del punto da cui inizia la trasformazione. Se non è espressamente indicato un valore per l'origine della trasformazione (nel browser web), viene utilizzato il centro delle coordinate. Sfortunatamente, al momento della stesura di questo articolo, la specifica del comportamento delle trasformazioni utilizzando una fonte diversa da quella predefinita non è omogenea tra i browser e deve essere utilizzata con cautela.

    Insieme alla trasformazione della scala con scale Ce ne sono altri, come la rotazione con rotation e il movimento con translate, che offrono a alternativa alla rappresentazione grafica: invece di ottenere nuove coordinate, puoi rappresentarle nel loro spazio e trasformare il grafico per adattarlo al formato in cui desideri rappresentarle.

    Aggiungi riferimenti al grafico

    Ora che la parte principale del grafico è risolta tracciando i valori con un profilo e un'area riempita, è possibile completarlo con dei riferimenti che ne aiutino la lettura. A titolo di esempio, iniziamo disegnando alcuni riferimenti orizzontali (linee) che segnano i valori massimi e minimi accettabili nonché un valore desiderato. Come spiegato, puoi scegliere di aggiungere gli oggetti al file SVG direttamente dal JavaScript oppure includerli manualmente nel codice HTML e modificarli successivamente con JavaScript.

    Sembra logico etichettare questi riferimenti orizzontali con un testo che chiarisca il valore che rappresentano. Per evidenziare il testo, puoi utilizzare dei rettangoli che risaltano rispetto allo sfondo e alla grafica. Poiché i testi dovranno essere scalati per compensare la deformazione, potranno essere tutti raggruppati in un oggetto a cui verrà applicata la scala; Il vantaggio principale di farlo in questo modo è quello di poterli modificare in un'unica operazione se il contenitore del grafico (la finestra del browser) viene ridimensionato e cambia quella proporzione che la scala corregge.

    Ci sono diversi aspetti interessanti nel codice di esempio sopra. Prima di tutto, commenta che le costanti (variabili globali) sono state utilizzate per rendere l'esempio più leggibile per gli utenti che provengono dalla programmazione. microcontrollori en C o su C++. Come si vedrà più avanti, il modo ottimale per programmarlo JavaScript Utilizzerebbero oggetti che conterrebbero questi valori e metodi che gestirebbero i riferimenti in questo esempio o il grafico, in generale, in un sistema di produzione.

    D'altra parte, anticipando quello che sarebbe il codice più generico, sono state sviluppate funzioni separate che calcolano i diversi coefficienti che correggono la proporzione del grafico per adattare il testo proporcion_grafico(), la scala dei valori a seconda del loro intervallo escala() e un fattore di correzione per le misurazioni note in valore assoluto, come le misurazioni nei riferimenti medida_grafico().

    La lettura di questo codice dovrebbe aiutare a chiarire il contesto in cui funziona un'applicazione come questa, che disegna grafici in tempo reale e deve essere flessibile per essere presentata in vari contesti grafici (almeno varie dimensioni e proporzioni). Prima di tutto bisogna generare gli oggetti SVG, o "manualmente" nel codice HTML, sia tramite codice JavaScript e in ogni caso è necessario successivamente ottenere riferimenti a questi oggetti per manipolarli JavaScript in modo che si possano disegnare nuovi grafici e la rappresentazione di un grafico già disegnato possa essere adattata a un cambiamento nel mezzo in cui viene presentato.

    Un altro riferimento che può aiutare a interpretare facilmente un grafico sono i punti che rappresentano valori specifici (i nodi della retta). In questo esempio, in cui rappresentiamo un'unica magnitudo, la scelta di un simbolo non è fondamentale, ma se si sovrappongono più valori diversi per cercare correlazione, è interessante distinguere, oltre ad utilizzare altre risorse come il colore , disegnando simboli diversi. La grafica utilizzata per il nodo linea deve essere modificata in dimensione e proporzione, come avviene, ad esempio, con i testi, in modo che le sue dimensioni siano assolute e in modo che le sue proporzioni siano mantenute anche se cambiano quelle della scatola che contiene.

    Nell'esempio precedente abbiamo già visto come calcolare i diversi coefficienti per riscalare e correggere la proporzione del disegno; Per quanto riguarda come implementare la gestione dei simboli dei nodi o dei vertici del grafo, una possibile soluzione potrebbe essere quella di memorizzare gli oggetti SVG in un vettore e modificarne la posizione quando il grafico viene aggiornato leggendo un nuovo valore, oppure quando viene ridisegnato ridimensionando il contenitore. Nel primo caso bisognerebbe modificare la sua posizione e nel secondo la sua proporzione con la proprietà transform e il valore di scale. Il codice seguente è una modifica della funzione actualizar_grafico() includere il riposizionamento dei simboli dei vertici del grafico.

    Modifiche apportate alla funzione actualizar_grafico() per ottenere la nuova funzione actualizar_grafico_puntos() Sono quelli evidenziati nel codice dell'esempio precedente. Innanzitutto, nella riga 5, prendiamo un vettore di oggetti SVG come parametro. Questo vettore conterrà i simboli che dovranno essere riposizionati nei nuovi nodi del grafico.

    Nelle righe 39 e 40 vengono assegnate le nuove coordinate del centro, cx y cy, a quelli dei valori che vengono rappresentati. Se il simbolo non fosse basato sul centro, probabilmente sarà necessario aggiungere un offset cx metà della larghezza e dentro cy di metà altezza per riposizionarli esattamente sul nodo del grafico.

    Nelle righe da 57 a 61, i punti che corrispondono a coordinate non disegnate perché tagliati dal bordo sinistro vengono riposizionati all'esterno del grafico. La coordinata di cy a zero e quello di cx a qualsiasi numero negativo (maggiore del punto stesso) in modo che non venga visualizzato quando tagliato, come la parte sinistra del grafico, dalla finestra del SVG.

    Gestisci il grafico da un oggetto con JavaScript

    Tutte le operazioni fin qui spiegate possono essere integrate in un oggetto per gestire il grafico con uno stile più tipico delle nuove versioni di JavaScript. Questa alternativa di implementazione ha l'ulteriore vantaggio di semplificare l'incorporazione di più grafici, di valori diversi, sulla stessa pagina web.

    Prima di discutere l'implementazione, esaminiamo i modi più comuni per creare oggetti con JavaScript e alcune peculiarità delle funzioni che interessano la proposta di disegno grafico dei sensori IoT.

    È stato già spiegato che il nuovo modo di creare oggetti in JavaScript (disponibile dalla versione 5 di ECMAScript) consiste nell'utilizzare Object.create, a cui bisognerebbe abituarsi al posto del "classico" new, che ovviamente funziona ancora correttamente, sebbene il suo scopo sia più quello di simulare lo stile dei linguaggi con oggetti basati su classi (JavaScript basa la creazione di oggetti su prototipi) piuttosto che un'alternativa funzionante.

    Il codice precedente consente di ricordare le differenze tra la creazione degli oggetti con Object.create oppure con new. Serve anche a sottolinearlo, pur con la funzione con cui viene creato l'oggetto new può essere ovunque nel codice, l'oggetto deve già esistere prima di poterne creare un'istanza Object.create (L'oggetto ES5_Object non è una funzione).

    Nelle righe 3 e 4, per impostare un valore predefinito per le proprietà nella funzione con cui crea l'oggetto new, a ciascuna proprietà viene assegnato il valore dell'argomento corrispondente o (||), se non sono stati passati argomenti, ovvero se non sono definiti (undefined), poiché tale circostanza viene valutata come false, viene assegnato il valore predefinito.

    Il contesto in cui viene eseguita una funzione JavaScript solleva due questioni che è importante tenere a mente e che possono anche creare confusione quando si utilizza questo linguaggio di programmazione dopo aver lavorato con altri, come ad esempio C o C++, nel nostro caso. Il contesto include le variabili definite nell'ambito della funzione (e quelle globali) che, tra l'altro, solleva un concetto interessante, le "chiusure" che stabiliscono un intero stile di programmazione in JavaScript. Detto questo, c'era da aspettarselo this, che fa riferimento all'oggetto quando utilizzato all'interno del codice che lo definisce, viene mantenuto il contesto di esecuzione in cui è stato definito ma quello che utilizza è il contesto da cui viene chiamata la funzione. Questo comportamento è trasparente nella maggior parte dei casi, ma ci sono due circostanze in cui può creare confusione: una funzione definita all'interno di un'altra funzione e un metodo chiamato da un oggetto evento. window.

    Quando si esegue il codice precedente, nella console viene visualizzato il testo commentato alla fine. Le due linee contrassegnate riflettono un comportamento che può creare confusione: il contesto di esecuzione della funzione probar_dentro() non probar(), come ci si potrebbe aspettare, ma window, che mostra le variabili globali e non le proprietà con lo stesso nome. Se non desideri questo comportamento, crea semplicemente una variabile nella funzione di livello più alto e assegnala a this, come nel codice seguente.

    Per controllare il contesto di esecuzione quando un metodo viene chiamato da un evento window, ad esempio ridimensionando la finestra del browser, altra peculiarità di JavaScript: la possibilità di programmare "fabbriche di funzioni", cioè funzioni che generano altre funzioni, restituendole con return.

    Nel codice di esempio sopra, il metodo llamar() degli oggetti Contexto Non fa il lavoro ma restituisce una funzione anonima che se ne occupa. Per verificare che tutto funzioni come previsto esiste una variabile globale con lo stesso nome della proprietà che la funzione visualizza nella console; Se il contesto è corretto verrà visualizzato il valore della proprietà e non quello della variabile globale.

    JavaScript Prova a correggere i segni del punto e virgola che omettiamo alla fine delle frasi. Ciò consente uno stile di scrittura rilassato ma è un’arma a doppio taglio che deve essere trattata con attenzione. Nella maggior parte dei casi, per evitare gli effetti indesiderati che ciò produce nelle espressioni che occupano più righe, è possibile utilizzare parentesi o precedere il modo in cui JavaScript interpreterà il codice; Ecco perché la riga 8 dell'esempio include function dietro return, se avessi usato un'altra riga il significato sarebbe molto diverso. A mio avviso la soluzione più leggibile è utilizzare una variabile intermedia (dispensabile) come nella versione seguente; Ovviamente, una volta compreso il comportamento, la decisione spetta al programmatore.

    Nello stesso senso di valutare un'espressione come una funzione, cioè restituire una funzione e non il valore che la funzione restituisce; alla riga 21 dell'ultimo esempio (era alla riga 19 del precedente) si ferma con clearInterval la funzione chiamata con setInterval. Affinché possa agire per 30 secondi, lo stop viene differito con setTimeout, che a sua volta necessita di una funzione come primo argomento; per fornire l'esecuzione come parametro clearInterval con la variabile che contiene la chiamata periodica (e non la funzione clearInterval) è lo scopo per cui viene creata la funzione anonima nell'ultima riga.

    La scelta tra scrivere il codice integrando la definizione della funzione, più compatto (come alla riga 21) o utilizzando una variabile ausiliaria, a mio avviso, più leggibile (come alle righe 19 e 20) varia poco nelle prestazioni e dipende più dallo stile e dalla leggibilità per manutenzione.

    Per testare il codice, prima di avere i dati sul server, si può utilizzare un generatore di valori casuali nell'intervallo desiderato oppure preparare tabelle con valori controllati che simulano il funzionamento nelle condizioni desiderate. L'esempio seguente utilizza un semplice generatore di dati sull'intera gamma, motivo per cui appaiono un po' esagerati.

    Per testare, puoi scarica il codice completo dell'esempio formato da una pagina web scritta in HTML, lo stile CSS e il codice JavaScript. Quest'ultima è la più rilevante, poiché le altre componenti sono solo un supporto minimo, molto semplificate e sono molto più sviluppate negli articoli delle sezioni corrispondenti.

    Invia commento

    Potresti aver perso