Generera och modifiera SVG-grafik av data från sensorer anslutna till IoT med JavaScript

Generera och modifiera SVG-grafik av data från sensorer anslutna till IoT med JavaScript

Generera och modifiera SVG-grafik av data från sensorer anslutna till IoT med JavaScript

I denna sista del av artikelserien om teckning grafik med data från sensorer anslutna till Internet of Things, är det dags att prata om hur man genererar eller modifierar med JavaScript ritningar i format SVG och några av elementen html som fungerar som en behållare eller som presenterar kompletterande information till grafiken.

Innehållsförteckning

    Datagrafer från sensorer anslutna till Internet of Things (IoT)-behållare i HTMLGrafer över data från sensorer anslutna till Internet of Things (IoT) definition av utseende i CSSDatagrafer från sensorer anslutna till Internet of Things (IoT) ritning med SVGDatagrafer från sensorer anslutna till Internet of Things (IoT) Generering och modifiering med JavaScript

    Målanvändarna av denna handledning är tänkta att bilda en elektronik- och datorprogrammeringsprofil. mikrokontroller, kanske de inte är bekanta med html, CSS o SVG; Av denna anledning gjordes i de tidigare avsnitten en kort introduktion till språket eller motsvarande teknik. I denna sista del är tillvägagångssättet lite annorlunda, eftersom läsarna säkert vet hur man programmerar, är det möjligt att använda språket C + + det, liksom JavaScript, delar grundläggande syntax med C och det kan användas som referens för att hoppa över de flesta av de grundläggande programmeringskoncepten och därmed fokusera på skillnaderna och den specifika användningen som intresserar oss för att skapa sensorgrafik i IoT.

    Namnet ger en ledtråd till den första skillnaden: JavaScript Det är ett programmeringsspråk skript (bindestreck) och som sådan är det tolkas, det finns inget behov av att kompilera det; det sammanhang i vilket skript (en webbläsare, till exempel) kommer att läsa, översätta och utföra beställningarna. För att vara exakt finns det i de flesta fall en runtime compilation (JIT), men för kodskrivningsprocessen JavaScript Det påverkar oss inte, vi skriver helt enkelt koden och det kan fungera.

    Namnet innehåller också den första förvirringen: JavaScript har inte det minsta förhållande till java. Inledningsvis när det utvecklades Netscape för sin webbläsare kallades den först Mocha och sedan det mindre förvirrande LiveScript. Efter dess framgångsrika implementering i webbläsare, och överskridande av dem, standardiserades den som ECMAScript (Vid ECMA-262, version 6 i skrivande stund) för att bli neutral med avseende på webbläsare som implementerar det. För närvarande finns det också en standard ISO från version 5, 2011 (ISO / IEC 16262: 2011 vid tidpunkten för att skriva artikeln)

    Variabler, grundläggande datatyper och objekt i JavaScript

    Till skillnad från vad som händer till exempel i C + +, en JavaScript datatyp som inte ingår när en variabel deklareras och även typen som är associerad med en variabel inte är fixerad, är det möjligt att tilldela ett värde av en annan typ under hela programmets körning.

    I det föregående exemplet har variabeln "sak" deklarerats (utan att ange datatyp) sedan tilldelas data av en annan typ och den konsulteras med typeof typen som JavaScript som han har tolkat. För att felsöka koden kan du skriva den i webbläsarens inspektörskonsol (vilket inte kommer att påverka presentationen av webben) med console.log().

    För att tvinga fram konvertering av data till en specifik typ, speciellt text till numerisk, kan du använda funktioner som t.ex parseInt() o parseFloat() som omvandlas till heltal respektive flyttal. Den motsatta konverteringen kan göras med String(), även om det är osannolikt att det är nödvändigt eftersom automatisk konvertering vanligtvis räcker. Med parseFloat()Du kan till exempel få värdet på en webbsideegenskap, som bredd eller höjd på ett objekt, som inkluderar enheter; På detta sätt uttrycket parseFloat("50px"); kommer att returnera 50, ett numeriskt värde, som ett resultat.

    En JavaScript det finns ingen skillnad mellan dubbla och enkla citattecken; Datatypen i båda fallen är string, och var och en av dem kan inkludera den andra utan behov av escape-koder.

    I föregående exempel kan man se att en variabel, när den har deklarerats (finns) men inte har tilldelats något värde, innehåller en odefinierad datatyp (undefined). Ett otilldelat objekt har värdet null; Det vill säga objektet existerar, men utan värde; en variabel som refererade till den skulle inte ha en typeof undefined men object. Ett objekt kan också vara tomt, det vill säga inte null men inte ha några egenskaper.

    till definiera ett objekt i JavaScript är inneslutna i hängslen ({ y }) egenskaperna eller metoderna, åtskilda av kolontecknet (:) egenskapens namn egenskapens värde och med kommatecken (,) de olika egenskaperna. Du kan hitta mer information om detta sätt att uttrycka ett objekt i artikeln om JSON-format.

    Även om du kan använda syntax som kan få dig att tänka annorlunda, en JavaScript Det finns inga klasser utan prototyperDet vill säga för att ett objekt ska ärva egenskaper och metoder skapas ett annat objekt (prototypen) som de andra (barnen) använder som referens. Syntaxen närmast stilen av JavaScript att använda en prototyp är Object.create även om det också är möjligt (och ibland användbart) att använda new som i andra objektorienterade språk.

    till fråga om ett objekt är en instans av ett annat, om du använder den som en prototyp, om du ärver dess egenskaper, kort sagt, du kan använda instanceof (skapat med new) Eller isPrototypeOf (skapat med Object.create) som kommer att utvärderas till sant när objektet använder prototypen och till falskt när det inte gör det.

    När ett objekt väl har skapats med ett annat som prototyp, det vill säga när ett objekt har instansierats, kan det vara lägga till nya egenskaper eller åsidosätta prototypegenskaper använder punktsyntax som i gato.peso=2.5.

    La arrayer i JavaScript De skiljer sig från dem du förmodligen känner i C. Till att börja med deklareras de utan att deras längd behöver anges, endast med tecknen på att öppna och stänga hakparenteser ([ y ]), kan komponenter vara heterogena (olika datatyper i samma array) och nya element kan läggas till utan att begränsas till en gräns. Matriserna för JavaScript är faktiskt listor (samlingar) av element till vilka refereras av ett numeriskt index eller med ett namn. En array kan samtidigt innehålla numeriska index och elementnamn, men det är vanligt att använda objekt (egenskaper) för att utnyttja den andra typen.

    Som kan ses i föregående exempel, för att veta om en variabel motsvarar en instans av en array (det är ett array-objekt) kan du använda instanceof, som redan har använts med generiska objekt eller, i nyare versioner av JavaScript du kan ta till Array.isArray()

    För att komma åt elementen i arrayen kan du använda dess index (matriz[7]) eller av egenskapens namn med namnet inom hakparenteser (matriz["nombre"]) eller med den vanliga punktsyntaxen för objekt (matriz.nombre). Eftersom namnet är en textsträng kan ett uttryck, inklusive variabler, användas för att komponera det. För att gå igenom en array med egenskaper kan en loop med formatet användas for(propiedad in matriz).

    Det är intressant för vårt mål att behandla objektet Date, för att representera och hantera datum och tid i JavaScript. Objektet kan instansieras utan data, så det kommer att ta aktuellt datum och tid, eller så kan det skapas genom att ange ett datum som ett värde, antingen i millisekunder sedan 1 januari 1970 (t.ex. Unix-tid eller POSIX-tid men uttryckt i millisekunder istället för sekunder) eller ange separata värden för år, månad, dag, timme...

    Objektet innehåller en komplett serie av metoder för att fråga eller ställa in datum och tid:

    • now()
      Returnerar aktuellt datum och tid uttryckt i millisekunder sedan 1 januari 1970

    • getTime() | setTime()
      Hämtar respektive ändrar tidsvärdet i millisekunder sedan 1 januari 1970. Använda valueOf(), vilket är en metod som finns i de flesta objekt, erhålls också värdet av motsvarande Date-objekt, som t.ex getTime() med Unix-tid eller POSIX-tid uttryckt i ms.

    • getMilliseconds() | setMilliseconds()
      Används för att fråga eller ställa in bråkdels millisekundsdelen av objektet Date på vilken den utförs. Om det konsulteras är det erhållna värdet mellan 0 och 999 men större värden kan tilldelas som kommer att ackumuleras i det totala datumet och tiden så, liksom resten av get-metoderna, tjänar det till att öka värdet på objektet Date (eller minska den om negativa värden används).

    • getSeconds() | setSeconds()
      Returnerar respektive ändrar värdet på objektets sekunder Date.

    • getMinutes() | setMinutes()
      Används för att konsultera eller ställa in protokollet för objektet Date.

    • getHours() | setHours()
      Låter dig konsultera eller ändra timmarna (från 0 till 23) för objektet Date.

    • getDay()
      Returnerar veckodagen för datumet, uttryckt som ett värde från 0 till 6 (söndag till lördag).

    • getDate() | setDate()
      Returnerar eller ändrar dagen i månaden för objektet Date på vilken den tillämpas.

    • getMonth() | setMonth()
      Används för att konsultera eller ändra objektets månadsnummer Date.

    • getFullYear() | setFullYear()
      Frågar eller ställer in årsvärdet på objektet som innehåller datum och tid.

    De tidigare metoderna för Date inkludera en version UTC att direkt kunna arbeta med universell tid utan att behöva göra mellanberäkningar. I den meningen har t.ex. getHours() har en version getUTCHours() o getMilliseconds() ett alternativ getUTCMilliseconds() att arbeta alternativt med den officiella (lagliga) eller universella tiden. Med getTimezoneOffset() Du kan känna till skillnaden som finns mellan universell tid och lokal officiell tid.

    JavaScript-funktioner

    Om du läser detta vet du säkert hur man programmerar. mikrokontroller en C in C + + och känna till funktionsbegreppet. Även om grundidén är densamma, i JavaScript Sättet de definieras och används på är lite annorlunda. Till att börja med har det redan sagts, JavaScript Den använder inte explicit datatyper så du behöver inte ange det när du definierar funktionen. Att följa, Det är inte obligatoriskt för en funktion att ha ett namn, de kan vara anonyma. De kan associeras med en variabel för att anropa dem, men det kanske inte heller är nödvändigt eftersom det ibland är användbart att anropa dem omedelbart, för vilka parenteser och parametrar läggs till efter definitionen av funktionen.

    För att definiera en funktion, prefix function, om tillämpligt, skriv namnet, argumenten (parametrarna som skickas till funktionen) inom parentes och koden som kommer att köras när funktionen anropas inom klammerparenteser.

    Visst, i det föregående exemplet behövdes inte variabeln "resultat", men det är en bra ursäkt för att komma ihåg varierande omfattning, vilket fungerar som du förväntar dig: "resultat"-variabeln finns bara inom "dubbel"-funktionen. I JavaScript kan också användas letistället för var, för att omfånga en variabel till en kodblockskontext (omsluten av hängslen, { y })

    När man pratade om objekt i föregående avsnitt saknades något grundläggande: egenskaper har definierats men metoder har inte definierats. Som förväntat, objektmetoder är funktioner, de har inget namn och används (anropas) från (egenskaps)namnet som tilldelas av objektdefinitionen.

    I det föregående exemplet finns det redan en metod, "view_temperature", som visar värdet för egenskapen "current_temperature" genom konsolen. Det är inte särskilt användbart, men det ger en mer komplett uppfattning om hur definitionen av ett objekt är JavaScript.

    För att komma åt metoderna för ett objekt (funktioner) till dess egenskaper, använd this, som i föregående exempel på rad 11, när du använder egenskapen "current_temperature".

    Få åtkomst till Document Object Model (DOM) med JavaScript

    från JavaScript Du har tillgång till innehållet på webbsidan som den körs på, samt vissa aspekter av webbläsaren som visar den sidan, dock inte till systemresurser. Datastrukturen som stöder egenskaperna och metoderna som nås från JavaScript del av fönsterobjektet, specifikt innehållet i objektet (dokumentet html) motsvarar objektet document. Även om det ibland används för tydlighetens skull, är det inte nödvändigt att föregå fönster till metoderna eller egenskaperna för att referera till dem, det räcker till exempel att använda document, det finns inget behov av att skriva namnet på rotobjektet som i window.document, så länge det aktuella fönstret refereras.

    Den mest använda formen av hitta ett objekt i dokumentet html Det är genom metoden getElementById(), till vilket det id som angavs när koden skapades skickas som ett argument html. Av det som förklarats i tidigare avsnitt är det lätt att anta att du även kan komma åt komponenterna inuti objektet document använder punktsyntax (document.componente) eller parenteser med både namnet (document["componente"]), den mest användbara, såsom det numeriska indexet, svår att använda och opraktisk när du kommer åt innehållet på en manuellt sammansatt webbsida.

    med JavaScript kan hämta elementet som innehåller ett annat element (element eller överordnad nod) konsultera din fastighet parentNode eller din egendom parentElement, skillnaden är att det överordnade elementet (parentElement) av det sista elementet i strängen DOM Den är null (null) och föräldernoden (parentNode) är själva dokumentet (document).

    till ändra innehållet i ett element htmlt.ex. en etikett <div>, Det kan användas innerHTML och för att ändra dess egenskaper kan du välja att tilldela den en annan klass className eller ändra dess egenskaper individuellt med style. Att konsultera stilen som visas av ett element på webbsidan är inte nödvändigtvis användbart style eftersom det kan bero på flera faktorer eller helt enkelt inte har specificerats uttryckligen. För att kontrollera stilen på ett element som slutligen visas på webbsidan, används metoden getComputedStyle.

    Till ett dokumentelement html Flera klasser kan tilldelas den för att bestämma dess utseende och beteende hantera listan med klasser för ett objekt från JavaScript du kan ta till classList som erbjuder metoderna add för att lägga till en ny klass till listan, remove att ta bort det, toggle för att ersätta den eller konsultera innehållet i klasslistan för ett element med item och contains, som returnerar klassen som har en viss position i listan och ett värde true o false om en viss klass finns på listan eller inte.

    I föregående exempel är den placerad med getElementById objektet du vill manipulera (ett element <div> för hans id), innan du ändrar utseende, raderas innehållet genom att tilldela med innerHTML en tom textsträng, den tilldelas en ny klass med className och dess stil är modifierad med style beroende på innehållets värde (temperatur), ändra färgen, om tillämpligt, genom fastigheten color. När aspekten är etablerad skrivs värdet med igen innerHTML.

    I den andra delen av exemplet ovan (rad 9 till 19) nås ett kodelement html använder syntaxen document[] och fastigheten id av elementet för att ändra dess klasslista med metoden classList.remove() och med metodenclassList.add(), baserat på resultatet av flera frågor som utförs i villkorliga körningar, som de jämför med classList.contains().

    När kommer det att hänvisa till ett element html flera gånger genom hela koden JavaScript, det är lite mer effektivt att tilldela den till en variabel eller använd dess index istället för namnet eftersom annars metoden du skulle använda JavaScript För att få det varje gång skulle det krävas att man sökte efter dess namn, vilket skulle ta lite mer tid än om en variabel hade åtkomst.

    till lägga till nya objekt i dokumentet html, kan de skapas först med metoden createElement de document och senare införliva dem med resten av elementen vid den punkt av trädet som är nödvändigt med appendChild. Att skapa ett objekt XML, som föremål SVG som vi använder för att rita grafen över IoT-sensorerna kan du använda createElementNS (NS för namnutrymme). Som förklarat när vi pratar om formatet SVG, namnutrymmet som motsvarar det (för den aktuella versionen) är http://www.w3.org/2000/svg, som bör skickas till createElementNS som ett argument tillsammans med elementtypen, svg, I detta fall.

    en alternativ till innerHTML för att lägga till text som innehåll i ett dokumentelement html är metoden createTextNode() av objektet document. Med detta alternativ kan du skapa ny text (som senare nås om den tilldelas en variabel) som införlivas i objektträdet med metoden appendChild(). som alternativ till appendChild(), som lägger till det nya innehållet i slutet av det som redan finns i noden som det läggs till, kan du använda metoden insertBefore(), som lägger till ett nytt objekt framför ett befintligt. ha på sig insertBefore() istället för appendChild() tillhandahåller en metod som tjänar till att t.ex sortera nya objekt framför befintliga när ett element måste vara framför ett annat (som i en lista) eller täcka eller vara täckt i en grafisk struktur där det finns element närmare förgrunden eller bakgrunden.

    Reagera på händelser med JavaScript

    När sättet att använd en webbsida som en behållare för IoT-anslutna sensorgrafer den användes onload I etiketten <body> för att börja rita grafen. Denna egenskap, associerad med kodobjekten html, hänvisar till Händelser JavaScript. Som redan förklarats kör den en funktion när sidan har laddats. Även om det har associerats med koden html för att ha det mer i åtanke kunde det ha skrivits i koden JavaScript som body.onload=dibujar; vara dibujar namnet på funktionen som ska startas när webbsidan laddas.

    I de senaste versionerna av JavaScript händelser kan associeras med funktioner som använder addEventListener med formatet objeto.addEventListener(evento,función); eller använda syntaxen objeto.evento=función; som fungerar även i äldre implementeringar. För att ta bort länken till funktionen som är kopplad till händelsen har du removeEventListener som har samma format som addEventListener.

    JavaScript Det är kapabelt att reagera på en mängd händelser som kan inträffa på en webbsida. Till exempel kan den upptäcka när ett element klickas html med onmousedown, eller när du klickar med onclick, när en tangent trycks ned med onkeydown, genom att manövrera rullningslisten med onscroll. För vårt syfte räcker det för oss upptäcka sidladdning med onload och dess storleksändring med onresize. Vi kommer att associera dessa händelser med objekten body y window del DOM respektive. Den första kan tilldelas i koden html, som sett och den andra i koden JavaScript inuti funktionen som anropas av den första och med formatet window.onresize=redimensionar; vara redimensionar funktionen som kommer att anropas varje gång fönstret ändrar storlek.

    Kör efter ett tidsintervall

    JavaScript har två resurser för uppskjuten utförande: setTimeout, som utför en funktion efter ett tidsintervall och setInterval som kommer att utföra en funktion varje visst tidsintervall. Båda metoderna kräver som parametrar (1) den anropade funktionen och (2) tidsintervallet uttryckt i millisekunder. För att stoppa deras operation kan du tilldela resultatet som returneras av dessa funktioner till variabler och skicka dem som ett argument till clearTimeout honom clearInterval när du inte vill anropa dem igen (eller när du inte vill att de ska köras för första gången) setTimeout o setInterval respektive.

    I det föregående exemplet introduceras metoden alert som tjänar till att visa en varningsskylt. Även om det användes flitigt tidigare, är det för närvarande nästan förbjudet från koden JavaScript på grund av hur aggressivt (påträngande) det är att täcka webbsidan med en dialogruta.

    I ett program skrivet för en mikrokontroller av en liten serie (som den på tallriken Arduino Uno) är det vanligt att använda globala variabler, som i föregående exempel i JavaScript, eftersom koden är kort och inte särskilt förvirrande, eftersom funktionerna många gånger implementeras ad hoc och för att användningen av globala variabler gör att minnesanvändningen kan förutsägas på ett mycket enkelt och intuitivt sätt, vilket är avgörande i system med få resurser. Istället, en JavaScript Det är vanligt att minska användningen av globala variabler till ett minimum. eftersom det inte behöver skynda på minnesanvändningen, eftersom det körs normalt på en CPU med resurser som är mycket överlägsna en MCU, eftersom det sannolikt kommer att samexistera med mycket tredjepartskod som det måste fungera med utan att störa och eftersom det är ett öppet system kan det framtida exekveringskontextet inte förutsägas (programmet för en mikrokontroller small bestämmer helt dess funktion utan att lägga till mer kod när den väl är i bruk) och eftersom dimensionerna på applikationerna kan göra läsning svår om koden inte kapslar in dess funktion, vilket gör metoderna så fristående som möjligt.

    Matematiska operationer med JavaScript Math-objektet

    De matematiska operationerna för mer komplicerade matematiska beräkningar är grupperade i objektet Math. Detta objekt används direkt, det är inte nödvändigt att instansiera det för att använda metoderna eller egenskaperna (konstanter) som det innehåller.

    • Math.abs(n) Absolutvärde för parameter n
    • Math.acos(n) Arccosinus för parameter n (resultat i radianer)
    • Math.asin(n) Arcsinus för parameter n (resultat i radianer)
    • Math.atan(n) Arktangens för parameter n (resultat i radianer)
    • Math.atan2(n,m) Arktangens av n/m (resultat i radianer)
    • Math.ceil(n) Avrunda parametern till närmaste heltal uppåt
    • Math.cos(α) Cosinus för parameter α (α i radianer)
    • Math.E e-nummer (≃2.718281828459045)
    • Math.exp(n) e höjt till parametern n: en
    • Math.floor(n) Avrunda parameter n till närmaste heltal nedåt
    • Math.log(n) Naturlig logaritm (bas e) för parameter n
    • Math.LN2 Naturlig logaritm (bas e) av 2 (≃0.6931471805599453)
    • Math.LN10 Naturlig logaritm (bas e) av 10 (≃2.302585092994046)
    • Math.LOG2E Bas 2-logaritm av e (≃1.4426950408889634)
    • Math.LOG10E Bas 10-logaritm av e (≃0.4342944819032518)
    • Math.max(a,b,c,…) Största värdet i listan över parametrar som har passerats
    • Math.min(a,b,c,…) Det minsta värdet i listan med parametrar som skickats
    • Math.PI Nummer π (≃3.141592653589793)
    • Math.pow(n,m) Första parametern n höjd till den andra parametern m: nm
    • Math.random() (Nästan) slumptal mellan 0.0 och 1.0
    • Math.round(n) Avrunda parameter n till närmaste heltal
    • Math.sin(α) Sinus för parameter α (α i radianer)
    • Math.sqrt(n) Kvadratroten av parameter n
    • Math.SQRT1_2 Kvadratroten av 1/2 (≃0.7071067811865476)
    • Math.SQRT2 Kvadratroten ur 2 (≃1.4142135623730951)
    • Math.tan(α) Tangent för parameter α (α i radianer)

    Ladda data från servern med AJAX

    Metoden som följs för att rita informationen som lagras i IoT består av att då och då ladda data från servern och rita om grafen som de representeras med. För att läsa data från servern används teknik AJAX (asynkron JavaScript och XML) genom ett föremål XMLHttpRequest de JavaScript. Att plotta datagrafen görs genom att återanvända ett objekt SVG som redan finns i koden html och som innehåller en plot vars koordinater är modifierade för att få dem att motsvara den nya data som laddas.

    I exemplet med detta förslag uppdateras, förutom uppdatering av ritningen, även en text på webbsidan som visar datum och värde för senast uppmätta data för varje graf.

    På serversidan finns en databas som innehåller informationen att sensorer kopplade till IoT har övervakat. Denna databas läses av objektbegäran XMLHttpRequest svarar med information kodad i JSON-format, även om namnet på den använda metoden antyder ett samband med formatet XML.

    I den första polaridad.es handledning om IoT-datalagring Du kan se ett exempel på en infrastruktur för att hantera, från serversidan, informationen som tillhandahålls av enheter anslutna till Internet of Things. I denna artikelserie används en server som en resurs Apache där du kan använda programmeringsspråket PHP för att komma åt en databas MySQL o mariadb. På servrar som används för att stödja IoT är det mycket vanligt att hitta databaser MongoDB (NoSQL) och programmeringsspråket JavaScriptnode.js som mjukvaruinfrastruktur.

    Nästa funktion ansvarar för att begära de senaste data från en av sensorerna från servern. I funktionsanropet används objektet som ett argument JavaScript som stöder den data som ritas. Om samma graf representerar flera värden, till exempel för att visuellt söka efter en korrelation, kan en begäran göras till servern att returnera flera samtidigt, en mer optimal metod på grund av hur servern fungerar. HTTP-protokoll.

    I den tredje raden i föregående exempel förbereds frågan som kommer att göras till servern, där "zon"-argumentet kommer att skickas, vars värde kommer att vara namnet eller koden för den övervakade platsen eftersom information om område kan samexistera i samma databas olika sensorer (till exempel termometrar som mäter temperaturen i olika rum). Parametern som skickas till föregående funktion, objektet med diagramdata, förväntas inkludera en egenskap med namnet på rummet ("namnsuffix").

    Mellan raderna 7 och 14 i den föregående koden visas objekt XMLHttpRequest som lagras i variabeln "ajax". Innan du väljer hur du ska skapa objektet söker du window om XMLHttpRequest var inte tillgänglig (något som hände i gamla versioner av Microsofts explorer och även om det ligger långt efter, fungerar det som ett exempel på alternativ för att skapa objektet med hjälp av (mer inbyggd) syntax) Object.create o new, liknande det för andra objektorienterade språk.

    För att kunna hantera svaret omedelbart förbereds koden som hanterar det på rad 15 till 26 innan begäran görs till servern.

    Vägen till utföra frågan HTTP till servern består av öppna en anslutning med open anger typ och sida (valfritt användarnamn och lösenord), förbereda rubrikerna av protokollet med setRequestHeader y skicka förfrågan med send. Rubriken HTTP Content-length du måste veta längden på frågan (antal tecken) som beräknas med hjälp av length.

    När begäran AJAX är klar, exekveras funktionen som är kopplad till händelsen onreadystatechange. Istället för att tilldela en funktion, definieras i föregående exempel en anonym funktion i farten som kommer att hantera mottagningen av data som kommer från servern. Först och främst, på rad 18, verifieras att statusen för begäran är "klar", vilket motsvarar värdet 4 av fastigheten readyState, att statusen är "OK" för HTTP-protokoll (koda 200) som kan erhållas från fastigheten status och att de uppgifter som har kommit är JSON-format, konsultera fastigheten responseType.

    När du har verifierat att statusen för svaret är som förväntat, i rad 20 i föregående exempel skapar ett objekt med resultatet och konverterar texten JSON. Svaret tillhandahåller ett datum som ska returneras, detta gör att vi kan se om resultatet som servern skickar redan tidigare varit representerat i grafen, som verifieras på rad 21. Om data är ny, på rad 23 Funktionen som ansvarar för att rita om grafen med den nya informationen kallas.

    Tanken när man föreslår denna läsmetod är att uppgifterna kommer att uppdateras mycket ofta. Om informationen som presenteras motsvarar en lång sikt (som temperaturerna för en dag eller en vecka), kan en första begäran implementeras som samlar in all tillgänglig data och sedan en, liknande den i exemplet, som uppdaterar den i periodkorrespondenten.

    Generera slumpmässiga data för testning

    När all server- och klientinfrastruktur är klar kommer en funktion som den i föregående avsnitt att ansvara för att läsa data och rita grafen med den, men I testfasen kan det vara mer praktiskt att använda slumptal inom ett kontrollerat område för att se om koden som skrivs är korrekt. Följande funktion kan fungera som ett exempel för att hämta data när du bygger den slutliga applikationen.

    Istället för att läsa informationen från en databas genererar exemplet ovan dem slumpmässigt och skickar dem till funktionen som ansvarar för att rita grafen. Den uppfunna datan är en vektor som bildas av ett datum uttryckt som ett värde i millisekunder, ögonblicket för registrering av sensorinformationen och den övervakade datan, som ligger mellan ett maxvärde och ett minimivärde.

    I det här exemplet, när ett datum genereras kan det fördröjas upp till en sekund (1000 millisekunder) i förhållande till datumet vid tidpunkten för uppfinningen. Som Math.random() genererar ett tal mellan 0.0 och 1.0, multiplicera det med 1000 ger ett tal mellan 0 och 1000 som sedan omvandlas till ett heltal. På samma sätt erhålls värdet genom att multiplicera slumptalet med intervallet (max minus minimum) och lägga till minimum.

    Rita grafen för IoT-sensorer med ett SVG-diagram

    Eftersom vi har sett hur vi kan erhålla de värden som vi vill representera (temperatur, i exemplet) och deras tidsmässiga läge, som kan uttryckas tillsammans i form av koordinater, visar exemplet nedan en funktion för att rita en bana som förenar dessa punkter och eventuellt ett färgat område avgränsat av den linjen längst upp. Resultatet skulle bli som på följande bild.

    Exempel på en graf som genereras med SVG och JavaScript för att representera data från IoT-sensorer

    Den horisontella axeln (X) i grafen representerar tid och den vertikala axeln (Y) de värden som sensorerna anslutna till IoT har övervakat. Det horisontella intervallet är några sekunder eftersom grafen i detta förslag uppdateras mycket ofta (till exempel varje sekund) för att ge nästan realtidsinformation om sensorernas status.

    I föregående kod finns två intressanta aspekter, för det första beräkningen som tillåter anpassa intervallet av värden som är representerade och för det andra fastighetsbyggande d som anger koordinaterna för punkterna på layouten (path).

    För att anpassa intervallet av representerade värden flyttas de från ett minimum och skalas så att den synliga storleken motsvarar storleken på grafen. När det gäller tid erhålls förskjutningen genom att subtrahera det intervall som du vill visa från den längsta tiden (datumet och tiden närmast den aktuella) (20 sekunder i exemplet). Förskjutningen av temperaturvärdena är den för det lägre intervallet (en grad) minus det lägsta värdet, så att data som visas nedan är mest lik det lägsta tillåtna värdet men lämnar en marginal som gör att vi kan uppskatta vad som är passerat

    Koefficienten som multiplicerar tidsvärdena för att erhålla grafens horisontella koordinater erhålls genom att dividera den totala bredden på grafen (100 enheter i exemplet) med tidsintervallet som representeras (20 sekunder i exemplet). För att erhålla koefficienten med de skalära temperaturvärdena måste man komma ihåg att det representerade området går från en marginal under minimivärdet till en marginal över maximum, en grad i båda fallen. På detta sätt resulterar den vertikala skalkoefficienten från att dividera höjden på grafen (100 enheter i exemplet) med maxvärdet, minus minimum plus övre och nedre marginalen. Eftersom dessa värden kan utvecklas helt vid negativa temperaturer använder vi Math.abs() att använda skillnadens absoluta värde.

    Egendomen d av objektet path Den är konstruerad genom att sammanfoga punkternas koordinater i en text. Varje koordinatpar föregås av en kod SVG L, som drar en linje från den aktuella positionen till ett absolut värde som indikeras av koordinaterna. X- och Y-värdena separeras med kommatecken och varje operation SVG separeras med ett mellanslag från nästa.

    För att starta layouten, använd koden M (flytta till en absolut koordinat). När det gäller den stängda och fyllda tomten börjar man längst ner till höger, vid den öppna tomten som ritar dataprofilen börjar man med det sist representerade värdet (det senaste). För att avsluta den stängda layouten används koden Z lägga till som sista punkt den som har samma X-koordinatvärde som den sista punkten på linjen och som Y-koordinat det minsta representerade värdet.

    I det här exemplet är funktionen dibujar_grafico(), som är anropet vid sidladdning, får de initiala värdena att testa (inte det sista realtidsvärdet) och förbereder intervallet inom vilket data kommer att renderas: 20 sekunder (20000 ms) horisontellt och 15°C i vertikal från -5°C till +10°C med en grads topp- och bottenmarginal. Ring två samtal till actualizar_grafico(), i första passet true som ett argument, som indikerar att diagrammet ska stängas för att representera ett fyllt område, och vid det andra anropet passerar det false att dra gränsen. I varje fall objektet path modifierad är den som har motsvarande utseende, med en fyllning och ingen kant i det första fallet och med en viss linjetjocklek och ingen fyllning i det andra.

    Funktionen actualizar_grafico() arbeta på ett föremål SVG som använder följande kod som en behållare html. Objektet SVG innehåller två banor, en för att rita linjen och en annan för att rita det fyllda området. När du laddar webbsidan, från elementet <body> föregående funktion anropas automatiskt, dibujar_grafico() tack vare evenemanget JavaScript onload.

    På rad 10 i koden html ovan har en bredd (som ett exempel) på 820 px och en höjd av 150 px fastställts i stilen (något som i den slutliga versionen kommer att vara tillrådligt att göra med en klass och ett dokument CSS). Det verkar konstigt att raderna 13 och 14 definierar storleken på föremålet SVG som 100% bredd och höjd (som bäst matchar fönstermåtten, 100×100). Som redan nämnts är anledningen till att göra detta att alltid arbeta med kända dimensioner och anpassa de representerade värdena till det. De andra alternativen skulle vara att beräkna utrymmet på grafen varje gång och justera värdena senare eller tvinga fasta dimensioner för grafen, som dokumentet måste följa.

    Efter att ha valt en graf vars dimensioner ändras enligt koden html, är det nödvändigt att inkludera fastigheten vector-effect med värdet non-scaling-stroke för att förhindra att linjetjocklekar deformeras när grafen inte bibehåller de valda proportionerna 1:1 på webbsidan som den visas på, vilket inträffade i det tidigare förslaget.

    För att "beskära" grafen och visa endast det område du väljer, använd viewBox. I det här fallet har vi valt att se den del av grafen som börjar på 0,0 (övre vänstra hörnet) och mäter 100x100 ner och till höger. Den del av ritningen som ligger i koordinater med negativa värden eller större än 100 kommer inte att visas på webbsidan även om de finns i objektet SVG

    Lägg till nya element till SVG-ritning

    I föregående exempel, funktionen actualizar_grafico() använda en layout SVG till vilket ägandet ändras d, vilket är det som uttrycker koordinatkedjan. Alternativet skulle vara att skapa hela objektet varje gång det ritas om. Fördelen med det första alternativet är att det grafiska utseendet (som tjocklek eller färg) definieras i koden html, begränsningen är att objekten måste skapas tidigare.

    För att skapa SVG-objekt, använd createElementNS(), vilket gör det möjligt att inkludera namnutrymme. I exemplet nedan skapas ett nytt textobjekt (text) och är associerad med ett element SVG som redan finns i koden html av webbplatsen. När det nya elementet har skapats tilldelas dess egenskaper setAttribute() och läggs till SVG med appendChild().

    Ändra andelen ritningselement

    Om du har provat att märka med funktionen i exemplet i föregående avsnitt har du sett att texten ser deformerad ut när objektets andel på webbsidan (width y height Av kod html) är inte lika med det representerade området (viewBox). För att anpassa proportionen är det nödvändigt att känna till objektets mått SVG för vilken du kan konsultera stilen på objektet eller behållaren html, om objektet SVG överlåta denna egendom. Tilldela ägande transform till föremål SVG som beror på proportionen kan deformationen korrigeras genom att tillämpa en skalningsoperation scale() där koefficienten i X skiljer sig från den i Y.

    SVG gör att flera objekt kan grupperas och bilda ett nytt sammansatt element som också stöder egenskaper, som enkla föremål. För att tillämpa samma transformation på en serie objekt samtidigt istället för varje objekt separat, kan du gruppera dem enligt denna resurs och tillämpa en enskild egenskap transform till dem alla.

    Som förklarat när man pratar om SVG-format, är elementen i en grupp inneslutna i etiketterna <g> y </g>. Att lägga till från JavaScript element till en grupp SVG används, som sett i föregående exempel, appendChild() när det nya objektet har definierats.

    För att fastställa ett ursprung vid tillämpning av transformationer kan egenskapen användas på objekt SVG transform-origin, vars värde är X- och Y-koordinaterna för den punkt från vilken transformationen börjar. Om ett värde för ursprunget för transformationen inte uttryckligen anges (i webbläsaren), används koordinatcentrum. Tyvärr, i skrivande stund, är det inte homogent mellan olika webbläsare att specificera beteendet för transformationer med en annan källa än standardkällan och bör användas med försiktighet.

    Tillsammans med skalomvandlingen med scale Det finns andra, såsom rotation med rotation och rörelsen med translate, som erbjuder en alternativ till grafrepresentation: istället för att få nya koordinater kan du representera dem i deras eget utrymme och transformera grafen så att den passar formatet som du vill representera dem i.

    Lägg till referenser till diagrammet

    Nu när huvuddelen av grafen är löst genom att plotta värdena med en profil och ett ifyllt område, kan den kompletteras med referenser som hjälper dess läsning. Som ett exempel, låt oss börja med att rita några horisontella referenser (linjer) som markerar de högsta och lägsta acceptabla värdena samt ett önskat värde. Som förklarat kan du välja att lägga till objekten i SVG direkt från JavaScript eller inkludera dem manuellt i koden html och ändra dem senare med JavaScript.

    Det verkar logiskt att märka dessa horisontella referenser med text som tydliggör värdet de representerar. För att markera texten kan du använda rektanglar som sticker ut från bakgrunden och grafiken. Eftersom texterna måste skalas för att kompensera för deformationen, kan de alla grupperas i ett objekt som skalan ska appliceras på; Den största fördelen med att göra det på detta sätt är att kunna modifiera dem i en enda operation om grafbehållaren (webbläsarfönstret) ändras och ändrar den proportion som skalan korrigerar.

    Det finns flera intressanta aspekter i ovanstående exempelkod. Kommentera först och främst att konstanter (globala variabler) har använts för att göra exemplet mer läsbart för användare som kommer från programmering. mikrokontroller en C in C + +. Som kommer att ses senare, det optimala sättet att programmera in den JavaScript Det skulle vara att använda objekt som skulle innehålla dessa värden och metoder som skulle hantera referenserna i detta exempel eller grafen i allmänhet i ett produktionssystem.

    Å andra sidan, för att avancera vad den mer generiska koden skulle vara, har separata funktioner utvecklats som beräknar de olika koefficienterna som korrigerar proportionen av grafen för att justera texten proporcion_grafico(), skalan för värdena beroende på deras intervall escala() och en korrektionsfaktor för mätningar som är kända i absoluta värden, såsom mätningar i referenser medida_grafico().

    Att läsa den här koden bör hjälpa till att förtydliga i vilket sammanhang en applikation som denna fungerar, som ritar grafik i realtid och måste vara flexibel för att kunna presenteras i olika grafiska sammanhang (åtminstone olika storlekar och proportioner). Först och främst måste objekten genereras SVG, antingen "manuellt" i koden html, antingen genom kod JavaScript och i alla fall måste hänvisningar till dessa objekt senare erhållas för att manipulera dem från JavaScript så att nya grafer kan ritas och representationen av en redan ritad graf kan anpassas till en förändring i mediet där den presenteras.

    En annan referens som kan hjälpa till att enkelt tolka en graf är punkterna som representerar specifika värden (linjens noder). I det här exemplet, där vi representerar en enstaka magnitud, är valet av en symbol inte kritiskt, men om flera olika värden är överlagrade för att leta efter korrelation är det intressant att särskilja, förutom att använda andra resurser som färg , genom att rita olika symboler. Grafiken som används för linjenoden måste modifieras i storlek och proportion, vilket sker till exempel med texter, så att dess dimensioner är absoluta och så att dess proportioner bibehålls även om de i rutan den innehåller ändrar grafiken.

    I det föregående exemplet såg vi redan hur man beräknar de olika koefficienterna för att skala om och korrigera andelen av ritningen; När det gäller hur man implementerar hanteringen av symbolerna för grafens noder eller hörn, kan en möjlig lösning vara att lagra objekten SVG in i en vektor och ändra dess position när grafen uppdateras genom att läsa ett nytt värde, eller när den ritas om genom att ändra storlek på behållaren. I det första fallet skulle dess position behöva ändras och i det andra dess proportion till fastigheten transform och värdet av scale. Följande kod är en modifiering av funktionen actualizar_grafico() att inkludera ompositionering av grafens vertexsymboler.

    Ändringar gjorda i funktionen actualizar_grafico() för att få den nya funktionen actualizar_grafico_puntos() Det är de som är markerade i koden i föregående exempel. Först, på rad 5, tar vi en vektor av objekt SVG som en parameter. Denna vektor kommer att innehålla de symboler som behöver flyttas om i de nya noderna i grafen.

    På raderna 39 och 40 tilldelas centrumets nya koordinater, cx y cy, till de av de värden som representeras. Om symbolen inte var baserad på mitten, kommer det förmodligen att vara nödvändigt att lägga till en offset cx halva bredden och in cy av halva höjden för att flytta dem exakt på grafnoden.

    På raderna 57 till 61 flyttas de punkter som motsvarar koordinater som inte är ritade eftersom de är avskurna av vänsterkanten utanför grafen. Koordinaten för cy till noll och att av cx till ett negativt tal (större än själva punkten) så att det inte visas när det skärs, som den vänstra delen av grafen, av fönstret i SVG.

    Hantera diagrammet från ett objekt med JavaScript

    Alla operationer som har förklarats hittills kan integreras i ett objekt för att hantera grafen med en stil som är mer typisk för de nya versionerna av JavaScript. Detta implementeringsalternativ har den extra fördelen att det förenklar införlivandet av flera grafer, med olika värden, på samma webbsida.

    Innan vi diskuterar implementeringen, låt oss se över de vanligaste sätten att skapa objekt med JavaScript och några av särdragen hos funktionerna som påverkar förslaget att rita IoT-sensorgrafik.

    Det var redan förklarat att det nya sättet att skapa objekt i JavaScript (tillgänglig sedan version 5 av ECMAScript) består av att använda Object.create, som borde vänja sig vid att använda istället för "klassikern" new, vilket naturligtvis fortfarande fungerar korrekt, även om dess syfte är mer att simulera språkens stil med klassbaserade objekt (JavaScript baserar skapandet av objekt på prototyper) än ett fungerande alternativ.

    Den tidigare koden låter dig komma ihåg skillnaderna mellan att skapa objekten med Object.create med new. Det tjänar också till att betona det, medan den funktion som objektet skapas med new kan finnas var som helst i koden måste objektet redan existera innan det kan instansieras med Object.create (ES5_Object-objekt är inte en funktion).

    På rad 3 och 4, för att ställa in ett standardvärde för egenskaperna i funktionen som skapar objektet med new, tilldelas varje egenskap till värdet av motsvarande argument eller (||), om inga argument har skickats, det vill säga om de är odefinierade (undefined), som den omständigheten bedöms som false, tilldelas standardvärdet.

    Kontexten i vilken en funktion exekveras JavaScript tar upp två frågor som är viktiga att tänka på och som också kan vara förvirrande när man använder detta programmeringsspråk efter att ha arbetat med andra, som t.ex. C o C + +, i vårat fall. Kontexten inkluderar de variabler som definieras i omfånget av funktionen (och de globala) som för övrigt väcker ett intressant koncept, "stängningarna" som etablerar en hel programmeringsstil i JavaScript. Som sagt, det kunde man förvänta sig this, som refererar till objektet när det används inom koden som definierar det, exekveringskontexten i vilken det har definierats bibehålls, men den som används är kontexten från vilken funktionen anropas. Detta beteende är transparent i de flesta fall, men det finns två omständigheter där det kan vara förvirrande: en funktion definierad i en annan funktion och en metod som anropas från en händelse av objektet. window.

    När den föregående koden körs visas den kommenterade texten i slutet i konsolen. De två markerade linjerna återspeglar beteende som kan vara förvirrande: funktionsexekveringskontexten probar_dentro() inte probar(), som man kan förvänta sig, men window, som visar de globala variablerna och inte egenskaperna med samma namn. Om du inte vill ha detta beteende, skapa helt enkelt en variabel i funktionen på högsta nivån och tilldela den till this, som i följande kod.

    För att styra exekveringskontexten när en metod anropas från en händelse window, till exempel genom att ändra storlek på webbläsarfönstret, en annan egenhet med JavaScript: möjligheten att programmera "funktionsfabriker", det vill säga funktioner som genererar andra funktioner, returnera dem med return.

    I exempelkoden ovan, metoden llamar() av föremålen Contexto Den gör inte jobbet utan returnerar en anonym funktion som tar hand om det. För att verifiera att allt fungerar som förväntat finns det en global variabel med samma namn som egenskapen som funktionen visar i konsolen; Om sammanhanget är korrekt kommer värdet på egenskapen att visas och inte för den globala variabeln.

    JavaScript Försök att korrigera semikolontecknen som vi utelämnar i slutet av meningarna. Detta möjliggör en avslappnad skrivstil men är ett tveeggat svärd som måste behandlas varsamt. I de flesta fall, för att undvika de oönskade effekter som detta ger i uttryck som upptar flera rader, kan du använda parenteser eller föregå sättet som JavaScript kommer att tolka koden; Det är därför rad 8 i exemplet innehåller function på baksidan av return, om jag hade använt en annan rad skulle betydelsen vara väldigt annorlunda. Enligt min mening är den mest läsbara lösningen att använda en intermediär (dispenserbar) variabel som i följande version; Uppenbarligen, när beteendet är förstått, motsvarar beslutet programmeraren.

    I samma mening som att utvärdera ett uttryck som en funktion, det vill säga returnera en funktion och inte värdet som funktionen returnerar; på rad 21 i det senaste exemplet (det var på rad 19 i det föregående) slutar det med clearInterval funktionen som kallas med setInterval. För att den ska agera i 30 sekunder skjuts stoppet upp med setTimeout, som i sin tur behöver en funktion som första argument; att leverera exekveringen som en parameter clearInterval med variabeln som innehåller det periodiska anropet (och inte funktionen clearInterval) är vad den anonyma funktionen i sista raden skapas för.

    Valet mellan att skriva koden som integrerar funktionsdefinitionen, mer kompakt (som i rad 21) eller att använda en hjälpvariabel, enligt min mening, mer läsbar (som på rad 19 och 20) varierar lite i prestanda och beror på mer stil och läsbarhet för underhåll.

    För att testa koden, innan du har data på servern, kan du använda en generator av slumpmässiga värden i det önskade intervallet eller förbereda tabeller med kontrollerade värden som simulerar drift under önskade förhållanden. Följande exempel använder en enkel datagenerator över hela intervallet, vilket är anledningen till att de verkar lite överdrivna.

    För att testa kan du ladda ner hela koden för exemplet bildas av en webbsida skriven i html, stilen CSS och koden JavaScript. Det senare är det mest relevanta, eftersom de andra komponenterna endast är minimalt med stöd, mycket förenklade och är mycket mer utvecklade i artiklarna i motsvarande avsnitt.

    Post kommentar

    Du kanske har missat