Ustvarite in spremenite grafiko SVG podatkov iz senzorjev, povezanih z IoT z JavaScriptom
V tem zadnjem delu serije člankov o risanju grafike s podatki senzorjev, povezanih z internetom stvari, je čas za pogovor o tem, kako ustvariti ali spremeniti z JavaScript risbe v formatu SVG in nekaj elementov HTML ki služijo kot vsebnik ali predstavljajo dopolnilne informacije k grafiki.
Ciljni uporabniki te vadnice naj bi imeli profil elektronike in računalniškega programiranja. mikrokrmilniki, morda ne poznajo HTML, CSS o SVG; Zato je bil v prejšnjih delih narejen kratek uvod v jezik ali ustrezno tehnologijo. V tem zadnjem delu je pristop nekoliko drugačen, ker bralci zagotovo znajo programirati, je možno, da z uporabo jezika C + + kaj kako JavaScript, ima skupno sintakso z C in ga lahko uporabimo kot referenco, da preskočimo večino osnovnih konceptov programiranja in se tako osredotočimo na razlike in specifično uporabo, ki nas zanima za ustvarjanje senzorske grafike v IoT.
Ime daje namig o prvi razliki: JavaScript Je programski jezik script (vezaj) in kot tak je interpretirano, ga ni treba prevajati; kontekst, v katerem je script (na primer spletni brskalnik) bo prebral, prevedel in izvršil naročila. Če smo natančni, v večini primerov obstaja a izvajalno prevajanje (JIT), ampak za postopek pisanja kode JavaScript Ne vpliva na nas, preprosto napišemo kodo in lahko deluje.
Ime vsebuje tudi prvo zmedo: JavaScript nima niti najmanjšega razmerja do Java. Sprva, ko je bil razvit Netscape za svoj brskalnik se je najprej imenoval Mocha in nato manj zmeden LiveScript. Po uspešni implementaciji v brskalnike in njihovem preseganju je bil standardiziran kot ECMAscript (Če želite ECMA-262, različica 6 v času pisanja), da postane nevtralen glede na brskalnike, ki ga izvajajo. Trenutno obstaja tudi standard ISO od različice 5, 2011 (ISO / IEC 16262: 2011 v času pisanja članka)
Spremenljivke, osnovni tipi podatkov in objekti v JavaScriptu
Za razliko od tega, kar se dogaja na primer v C + +, en JavaScript podatkovni tip ni vključen pri deklaraciji spremenljivke in tudi tip, povezan s spremenljivko, ni fiksen, je možno med izvajanjem programa dodeliti vrednost drugačnega tipa.
1
2
3
4
5
6
7
|
var cosa;
cosa=“texto”;
console.log(typeof cosa); // Debería mostrar string en la consola
cosa=123;
console.log(typeof cosa); // Debería mostrar number en la consola
cosa={temperatura:22,corriente:1.5};
console.log(typeof cosa); // Debería mostrar object en la consola
|
V prejšnjem primeru je bila deklarirana spremenljivka "stvar" (brez navedbe podatkovnega tipa), nato pa so dodeljeni podatki drugega tipa in se posvetujejo z typeof
tip, ki JavaScript ki ga je interpretiral. Za odpravljanje napak v kodi jo lahko napišete v inšpektorsko konzolo spletnega brskalnika (kar ne bo vplivalo na predstavitev spleta) z console.log()
.
Če želite vsiliti pretvorbo podatkov v določeno vrsto, zlasti besedila v številke, lahko uporabite funkcije, kot je parseInt()
o parseFloat()
ki se pretvorijo v cela števila ali števila s plavajočo vejico. Nasprotno pretvorbo lahko izvedete z String()
, čeprav je malo verjetno, da bo potrebno, saj običajno zadostuje samodejna pretvorba. z parseFloat()
Dobite lahko na primer vrednost lastnosti spletne strani, kot je širina ali višina predmeta, ki vključuje enote; Na ta način izražanje parseFloat("50px");
bo kot rezultat vrnil 50, številsko vrednost.
En JavaScript ni razlike med dvojnimi in enojnimi narekovaji; Tip podatkov v obeh primerih je string
in vsak od njih lahko vključuje drugega brez potrebe po ubežnih kodah.
1
2
3
4
5
6
7
8
9
10
|
var texto;
console.log(typeof texto); // Debería mostrar string en la undefined
texto=“esto es un texto”;
console.log(typeof texto); // Debería mostrar string en la consola
texto=‘A’;
console.log(typeof texto); // Debería mostrar string en la consola
texto=“esto es un ‘texto'”;
console.log(typeof texto); // Debería mostrar string en la consola
texto=‘”A”‘;
console.log(typeof texto); // Debería mostrar string en la consola
|
V prejšnjem primeru je razvidno, da spremenljivka, ko je bila deklarirana (obstaja), vendar ji ni bila dodeljena nobena vrednost, vsebuje nedefiniran podatkovni tip (undefined
). Nedodeljen objekt ima vrednost null
; To pomeni, da predmet obstaja, vendar brez vrednosti; spremenljivka, ki se sklicuje nanjo, ne bi imela a typeof
undefined
ampak object
. Objekt je lahko tudi prazen, to pomeni, da ni nič, vendar nima nobenih lastnosti.
za določite predmet v JavaScript so v oklepajih ({
y }
) lastnosti ali metode, ločene z dvopičjem (:
) ime lastnosti vrednost lastnosti in z vejico (,
) različne lastnosti. Več informacij o tem načinu izražanja predmeta najdete v članku o Format JSON.
Čeprav lahko uporabite sintakso, ki bi vas lahko napeljala na drugačen način razmišljanja, en JavaScript Ni razredov, ampak prototipiTo pomeni, da objekt podeduje lastnosti in metode, se ustvari drug objekt (prototip), ki ga drugi (otroci) uporabljajo kot referenco. Sintaksa, ki je najbližja slogu JavaScript uporabiti prototip je Object.create
čeprav je tudi možno (in včasih koristno) uporabiti new
kot v drugih objektno usmerjenih jezikih.
1
2
3
4
|
var perro=new Mamifero(); // Esto funciona, pero no es exactamente el nuevo estilo JavaScript
console.log(perro instanceof Mamifero);
var gato=Object.create(Mamifero); // Crear un objeto usando un prototipo al estilo JavaScript
console.log(Mamifero.isPrototypeOf(gato));
|
za poizvedba, če je en objekt primerek drugega, če ga uporabite kot prototip, če podedujete njegove lastnosti, skratka, lahko uporabite instanceof
(ustvarjeno z new
) o isPrototypeOf
(ustvarjeno z Object.create
), ki bo ovrednoten kot true, ko objekt uporablja prototip, in kot false, če ga ne uporablja.
Ko je bil objekt ustvarjen z uporabo drugega kot prototipa, to je, ko je bil objekt instanciran, ga je mogoče dodajte nove lastnosti ali preglasite lastnosti prototipa z uporabo sintakse pik kot v gato.peso=2.5
.
La nizi v JavaScript So drugačni od tistih, ki jih verjetno poznate C. Za začetek so deklarirani, ne da bi bilo treba navesti njihovo dolžino, le z znaki odpiranja in zapiranja oglatih oklepajev ([
y ]
), so lahko komponente heterogene (različni tipi podatkov v istem nizu) in novi elementi se lahko dodajajo, ne da bi bili omejeni na omejitev. Matrike iz JavaScript so pravzaprav seznami (zbirke) elementov, do katerih na katerega se sklicuje numerični indeks ali ime. Matrika lahko istočasno vsebuje številske indekse in imena elementov, vendar je običajno uporabiti objekte (lastnosti) za izkoriščanje druge vrste.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
// Declarar matrices (arrays)
var preparada=[]; // La matriz ha sido declarada pero (todavía) no contiene valores
var cosas=[“silla”,“mesa”,“caja”]; // Matriz declarada con componentes formada por cadenas de texto
var valores=[200,“lleno”,0.5,true,“simple”,false,false,10]; // Matriz declarada con componentes heterogéneos
var ramas=[20,“abc”,[1,2,3],false,[10,20,[“uno”,“dos”]]]; // Matriz que contiene matrices
var demode=new Array(10,20,30,4,3,2,1); // La sintaxis con new no es la preferida de JavaScript aunque funciona…
var peligrosa=new Array(10); // …pero con el riesgo de confundir índices con elementos: la matriz peligrosa tiene 10 elementos, no un elemento de valor 10
// Acceder a los valores de la matriz
preparada.push(33.33); // Añade un nuevo valor al final de la matriz
console.log(“La matriz ‘preparada’ contiene “+preparada.length+” elementos”); // Ahora contine 1 elemento
console.log(cosas[0]); // Muestra en la consola el primer valor de la matriz (las matrices empiezan en el índice cero)
cosas[2]=“tarro”;
preparada[10]=50; // Los índices no tienen que ser consecutivos
console.log(“La matriz ‘preparada’ contiene “+preparada.length+” elementos”); // Ahora contine 11 elementos
console.log(“Elemento sexto: “+preparada[5]); // undefined
// Verificar si una variable es (apunta a) una matriz
console.log(Array.isArray(cosas)); // Nuevas versiones de JavaScript (ECMAScript versión 5 o superior)
console.log(cosas instanceof Array); // Implementaciones de JavaScript (ECMAScript) más viejas
// Para esto es mejor usar objetos
var frutas=[];
frutas[“peras”]=20;
frutas[“manzanas”]=30;
frutas[4]=10;
console.log(frutas.peras);
console.log(frutas[“manzanas”]);
console.log(frutas[4]);
console.log(frutas[3]); // undefined
|
Kot je razvidno iz prejšnjega primera, če želite vedeti, ali spremenljivka ustreza primerku matrike (to je matrični objekt), lahko uporabite instanceof
, kot je bilo že uporabljeno z generičnimi predmeti ali v novejših različicah JavaScript se lahko zatečete Array.isArray()
Za dostop do elementov matrike lahko uporabite njen indeks (matriz[7]
) ali z imenom lastnosti z imenom v oglatih oklepajih (matriz["nombre"]
) ali z običajno sintakso pik za predmete (matriz.nombre
). Ker je ime besedilni niz, se lahko za njegovo sestavljanje uporabi izraz, vključno s spremenljivkami. Za zanko skozi matriko z lastnostmi lahko uporabite zanko z obliko for(propiedad in matriz)
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
var matriz=[];
matriz[“color”]=“verde”;
matriz[“grosor”]=10;
matriz[“estado”]=“nuevo”;
matriz[0]=25.0;
matriz[1]=“uno”;
for(propiedad in matriz)
{
console.log(propiedad+” valor “+matriz[propiedad]);
}
/* El resultado en la consola será:
0 valor 25
1 valor uno
color valor verde
grosor valor 10
estado valor nuevo
*/
|
Za naš cilj je zanimiv za zdravljenje objekta Date
, s katerim lahko predstavljate in upravljate datum in uro v JavaScript. Objekt je mogoče instancirati brez podatkov, tako da bo vzel trenutni datum in uro, lahko pa ga ustvarite tako, da kot vrednost navedete datum, bodisi v milisekundah od 1. januarja 1970 (kot npr. Čas Unix ali čas POSIX vendar izraženo v milisekundah namesto v sekundah) ali podajanje ločenih vrednosti leta, meseca, dneva, ure ...
Objekt vključuje celotno serijo metode za poizvedovanje ali nastavitev datuma in ure:
-
now()
Vrne trenutni datum in čas, izražen v milisekundah od 1. januarja 1970 -
getTime()
|setTime()
Pridobi oziroma spremeni časovno vrednost v milisekundah od 1. januarja 1970. UporabavalueOf()
, ki je metoda, ki je prisotna v večini objektov, se pridobi tudi vrednost ustreznega predmeta Datum, kot nprgetTime()
z Čas Unix ali čas POSIX izraženo v ms. -
getMilliseconds()
|setMilliseconds()
Uporablja se za poizvedovanje ali nastavitev delčka milisekunde predmetaDate
na katerem se izvaja. Če se posvetujete, je dobljena vrednost med 0 in 999, vendar je mogoče dodeliti večje vrednosti, ki se bodo zbrale v skupnem datumu in času, tako da, tako kot ostale metode pridobivanja, služi povečanju vrednosti predmeta.Date
(ali zmanjšajte, če so uporabljene negativne vrednosti). -
getSeconds()
|setSeconds()
Vrne oziroma spremeni vrednost sekund objektaDate
. -
getMinutes()
|setMinutes()
Uporablja se za ogled ali nastavitev minut predmetaDate
. -
getHours()
|setHours()
Omogoča ogled ali spreminjanje ur (od 0 do 23) predmetaDate
. -
getDay()
Vrne dan v tednu za datum, izražen kot vrednost od 0 do 6 (od nedelje do sobote). -
getDate()
|setDate()
Vrne ali spremeni dan v mesecu predmetaDate
na katerem se nanaša. -
getMonth()
|setMonth()
Uporablja se za ogled ali spreminjanje številke meseca predmetaDate
. -
getFullYear()
|setFullYear()
Poizveduje ali nastavi vrednost leta za objekt, ki vsebuje datum in čas.
Prejšnje metode Date
vključite različico UTC da lahko neposredno delate z univerzalnim časom, ne da bi morali delati vmesne izračune. V tem smislu je npr. getHours()
ima različico getUTCHours()
o getMilliseconds()
alternativa getUTCMilliseconds()
alternativno delo z uradnim (pravnim) ali univerzalnim časom. z getTimezoneOffset()
Lahko poznate razliko, ki obstaja med univerzalnim in lokalnim uradnim časom.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
var dia_semana=[“domingo”,“lunes”,“martes”,“miércoles”,“jueves”,“viernes”,“sábado”];
var nombre_mes=[“enero”,“febrero”,“marzo”,“abril”,“mayo”,“junio”,“julio”,“agosto”,“septiembre”,“octubre”,“noviembre”,“diciembre”];
var digitos_hora;
var hoy=new Date();
var texto_hoy=“”;
texto_hoy+=“Hoy es “;
texto_hoy+=dia_semana[hoy.getDay()];
texto_hoy+=“, “;
texto_hoy+=hoy.getDate();
texto_hoy+=” de “;
texto_hoy+=nombre_mes[hoy.getMonth()];
texto_hoy+=” de “;
texto_hoy+=hoy.getFullYear();
texto_hoy+=” y son las “;
digitos_hora=hoy.getHours();
texto_hoy+=digitos_hora>9?digitos_hora:“0”+digitos_hora;
texto_hoy+=“:”;
digitos_hora=hoy.getMinutes();
texto_hoy+=digitos_hora>9?digitos_hora:“0”+digitos_hora;
texto_hoy+=“:”;
digitos_hora=hoy.getSeconds();
texto_hoy+=digitos_hora>9?digitos_hora:“0”+digitos_hora;
|
funkcije JavaScript
Če to berete, zagotovo znate programirati. mikrokrmilniki en C o en C + + in poznajo koncept funkcije. Čeprav je osnovna ideja enaka, v JavaScript Način njihove opredelitve in uporabe je nekoliko drugačen. Za začetek je bilo že rečeno, JavaScript Podatkovnih tipov ne uporablja izrecno, zato vam jih pri definiranju funkcije ni treba navesti. Slediti, Ni obvezno, da ima funkcija ime, lahko je anonimna. Lahko jih povežete s spremenljivko, da jih prikličete, vendar morda tudi ni potrebno, saj jih je včasih koristno priklicati takoj, za kar so oklepaji in parametri dodani po definiciji funkcije.
Če želite definirati funkcijo, vnesite predpono function
, če je primerno, zapišite ime, argumente (parametre, posredovane funkciji) v oklepajih in kodo, ki bo izvedena, ko bo funkcija priklicana, v oklepajih.
1
2
3
4
5
|
function doble(numero)
{
var resultado=numero*2;
return resultado;
}
|
Seveda v prejšnjem primeru spremenljivka "rezultat" sploh ni bila potrebna, vendar je dober izgovor, da si zapomnite spremenljiv obseg, ki deluje, kot pričakujete: spremenljivka "result" obstaja le znotraj funkcije "double". notri JavaScript se lahko uporablja tudi let
, namesto da var
, za obseg spremenljivke v kontekstu bloka kode (zaključen v zavite oklepaje, {
y }
)
Ko smo govorili o objektih v prejšnjem razdelku, je nekaj temeljnega manjkalo: lastnosti so bile definirane, metode pa niso bile definirane. Kot je bilo pričakovano, objektne metode so funkcije, nimajo imena in se uporabljajo (prikličejo) iz imena (lastnosti), ki ga dodeli definicija objekta.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var
termostato=
{
temperatura_actual:0.0,
temperatura_frio:18.5,
temperatura_calor:22.0,
consumo:0,
ver_temperatura:
function()
{
console.log(“Temperatura actual: “+this.temperatura_actual+” °C”);
}
}
|
V prejšnjem primeru že obstaja metoda, "view_temperature", ki prikazuje vrednost lastnosti "current_temperature" prek konzole. Ni zelo uporabno, vendar daje popolnejšo predstavo o tem, kakšna je definicija predmeta JavaScript.
Za dostop do metod predmeta (funkcij) do njegovih lastnosti uporabite this
, kot v prejšnjem primeru v vrstici 11, pri uporabi lastnosti “current_temperature”.
Dostopite do Document Object Model (DOM) z JavaScriptom
iz JavaScript Imate dostop do vsebine spletne strani, na kateri se izvaja, kot tudi do nekaterih vidikov brskalnika, ki prikazuje to stran, vendar ne do sistemskih virov. Podatkovna struktura, ki podpira lastnosti in metode, iz katerih se dostopa JavaScript del okenskega objekta, natančneje vsebino predmeta (dokument HTML) ustreza predmetu document
. Čeprav se včasih uporablja zaradi jasnosti, pred oknom ni treba pisati metode ali lastnosti, da se sklicujete nanje, dovolj je na primer, da uporabite document
, ni treba pisati imena korenskega predmeta kot v window.document
, dokler se sklicuje na trenutno okno.
Najbolj uporabljena oblika poiščite predmet v dokumentu HTML To je skozi metodo getElementById()
, ki mu je ID, ki je bil naveden pri ustvarjanju kode, posredovan kot argument HTML. Iz tega, kar je bilo razloženo v prejšnjih razdelkih, je enostavno domnevati, da lahko dostopate tudi do komponent znotraj predmeta document
z uporabo pikčaste sintakse (document.componente
) ali oklepaji z uporabo obeh imen (document["componente"]
), najbolj uporabne, kot je numerični indeks, težke za uporabo in nepraktične pri dostopu do vsebine ročno sestavljene spletne strani.
z JavaScript lahko pridobite element, ki vsebuje drug element (element ali nadrejeno vozlišče) svetovanje o vaši lastnini parentNode
ali vaše lastnine parentElement
, razlika je v tem, da nadrejeni element (parentElement
) končnega elementa niza DOM Nič je (null
) in nadrejeno vozlišče (parentNode
) je sam dokument (document
).
za spremenite vsebino elementa HTML, na primer etikete <div>
, Lahko se uporablja innerHTML
in če želite spremeniti njegove lastnosti, mu lahko dodelite drug razred className
ali spremeniti njegove lastnosti posamično z style
. Pregledovanje sloga, ki ga prikazuje element na spletni strani, ni nujno koristno style
ker je lahko odvisno od več dejavnikov ali preprosto ni bilo izrecno določeno. Za preverjanje sloga elementa, ki je končno prikazan na spletni strani, se uporablja metoda getComputedStyle.
Na element dokumenta HTML Lahko mu dodelite več razredov, da določite njegov videz in vedenje upravljanje seznama razredov predmeta iz JavaScript se lahko zatečete classList
ki ponuja metode add
da dodate nov razred na seznam, remove
da ga odstranim, toggle
da ga zamenjate ali si ogledate vsebino seznama razredov elementa item
in contains
, ki vrne razred, ki zaseda določeno mesto na seznamu in vrednost true
o false
ali je določen razred na seznamu ali ne.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
var contenedor_temperatura=document.getElementById(“temperatura”); // Encontrar el div con id=”temperatura”
contenedor_temperatura.innerHTML=“”; // Eliminar el contenido provisionalmente para que no se vean los cambios
contenedor.className=“bloque_temperatura”; // Asignar una nueva clase
if(temperatura>20) // Si la temperatura es mayor que 20 °C…
{
contenedor.style.color=“#FF6666”; // …usar el color rojo en lugar del color normal de la clase
}
contenedor_temperatura.innerHTML=“La temperatura es “+temperatura+” °C”; // Cuando el aspecto esté preparado mostrar el valor
if(document[“titulo”].classList.contains(“estilo_titulo”)) // Si el objeto “titulo” tiene la clase “estilo_titulo”…
{
if(document[“titulo”].classList.contains(“general”)) // …y la clase “general”…
{
document[“titulo”].classList.remove(“general”); // …quitar la clase “general”
}
}
else // Si el objeto “titulo” no tiene la clase “estilo_titulo”…
{
document[“titulo”].classList.add(“estilo_titulo”); // …añadir la clase “estilo_titulo” (da igual que tenga o no la clase “general”)
}
|
V prejšnjem primeru se nahaja z getElementById
predmet, s katerim želite manipulirati (element <div>
za njegovo id
), pred spremembo videza se vsebina izbriše z dodelitvijo z innerHTML
prazen besedilni niz, mu je dodeljen nov razred z className
in njegov slog je spremenjen z style
glede na vrednost vsebine (temperatura), spreminjanje barve, če je primerno, preko lastnosti color
. Ko je vidik vzpostavljen, se vrednost znova zapiše z uporabo innerHTML
.
V drugem delu zgornjega primera (vrstice od 9 do 19) se dostopa do elementa kode HTML z uporabo sintakse document[]
in lastnino id
elementa, da z metodo spremeni njegov seznam razredov classList.remove()
in z metodoclassList.add()
, ki temelji na rezultatu več poizvedb, ki se izvajajo v pogojnih izvedbah, ki jih primerjajo z uporabo classList.contains()
.
Kdaj bo se nanašajo na element HTML več krat v celotni kodi JavaScript, malo je bolj učinkovito, če ga dodelite spremenljivki ali uporabite njegov indeks namesto imena, saj bi drugače uporabili metodo, ki bi jo uporabili JavaScript da bi ga vsakič pridobili, bi bilo treba poiskati njegovo ime, kar bi porabilo malo več časa, kot če bi dostopali do spremenljivke.
za dodajte nove predmete v dokument HTML, jih je mogoče najprej ustvariti z metodo createElement
de document
in jih kasneje vključite v preostale elemente na točki drevesa, ki je potrebna z appendChild
. Za ustvarjanje predmeta XML, kot predmeti SVG ki jih uporabljamo za risanje grafa senzorjev IoT, lahko uporabite createElementNS
(NS za imenski prostor). Kot je razloženo, ko govorimo o formatu SVG, je imenski prostor, ki mu ustreza (za trenutno različico). http://www.w3.org/2000/svg
, ki ga je treba posredovati createElementNS
kot argument skupaj z vrsto elementa, svg
, v tem primeru.
A alternativa innerHTML
za dodajanje besedila kot vsebine elementu dokumenta HTML je metoda createTextNode()
objekta document
. S to alternativo lahko ustvari novo besedilo (do katerega se pozneje dostopa, če je dodeljen spremenljivki), ki je vključen v drevo objektov z metodo appendChild()
. Kako alternativa appendChild()
, ki doda novo vsebino na konec tistega, kar že obstaja v vozlišču, v katerega je dodana, lahko uporabite metoda insertBefore()
, ki doda nov objekt pred obstoječega. Nosite insertBefore()
namesto appendChild()
zagotavlja metodo, ki služi na primer za razvrsti nove predmete pred obstoječimi ko mora biti element pred drugim (kot na seznamu) ali pokrivati ali biti pokrit v grafični strukturi, v kateri so elementi bližje ospredju ali ozadju.
Odziv na dogodke z JavaScriptom
Ko je način uporabite spletno stran kot vsebnik za senzorske grafe, povezane z internetom stvari je bilo uporabljeno onload
V nalepki <body>
da začnete risati graf. Ta lastnost, povezana s predmeti kode HTML, se nanaša na dogodki JavaScript. Kot že pojasnjeno, izvede funkcijo, ko se stran naloži. Čeprav je bil povezan s kodo HTML da bi to bolj upoštevali, bi lahko bilo zapisano v kodi JavaScript kot body.onload=dibujar;
biti dibujar
ime funkcije, ki naj se zažene, ko se spletna stran naloži.
V najnovejših različicah JavaScript dogodke je mogoče povezati s funkcijami z uporabo addEventListener
z obliko objeto.addEventListener(evento,función);
ali z uporabo sintakse objeto.evento=función;
ki deluje tudi v starejših izvedbah. Če želite prekiniti povezavo s funkcijo, povezano z dogodkom, imate removeEventListener
ki ima enako obliko kot addEventListener
.
JavaScript Sposoben se je odzvati na množico dogodkov, ki se lahko zgodijo na spletni strani. Na primer, lahko zazna, kdaj je element kliknjen HTML z onmousedown
, ali ko kliknete z onclick
, ko pritisnete tipko z onkeydown
, tako da upravljate drsni trak z onscroll
. Za naš namen je dovolj, da zazna nalaganje strani z onload
in njegovo spreminjanje velikosti z onresize
. Te dogodke bomo povezali s predmeti body
y window
od DOM oz. Prvo lahko dodelite v kodi HTML, kot je razvidno in drugo znotraj kode JavaScript znotraj funkcije, ki jo kliče prvi, in s formatom window.onresize=redimensionar;
biti redimensionar
funkcija, ki bo poklicana vsakič, ko okno spremeni velikost.
Zaženite po časovnem intervalu
JavaScript ima dva vira za odložena izvedba: setTimeout
, ki izvrši funkcijo po časovnem intervalu in setInterval
ki bo izvajal funkcijo vsak določen časovni interval. Obe metodi kot parametra zahtevata (1) priklicano funkcijo in (2) časovni interval, izražen v milisekundah. Če želite ustaviti njihovo delovanje, lahko spremenljivkam dodelite rezultat, ki ga vrnejo te funkcije, in jih posredujete kot argument clearTimeout
oa clearInterval
ko jih ne želite ponovno priklicati (ali ko ne želite, da se izvedejo prvič) setTimeout
o setInterval
oz.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
var cuenta_atras=setTimeout(descansar,1000*60*20); // Recordar que hay que descansar cuando pasen 20 minutos
var repeticion=setInterval(consultar_correo,1000*60*5); // Revisar el correo cada 5 minutos
function descansar()
{
alert(“Puedes descansar un rato”); // Esto solamente aparecerá una vez
}
function consultar_correo()
{
alert(“Revisa el correo electrónico”); // Esto aparecerá cada cinco minutos
}
function detener_cuenta_atras() // No utiliza argumentos sino la variable global
{
clearTimeout(cuenta_atras); // Detener la cuenta atrás para avisar a los 20 minutos
}
function no_avisar_lectura_correo() // No utiliza argumentos sino la variable global
{
clearInterval(repeticion); // Dejar de avisar cada 5 minutos
}
|
V prejšnjem primeru je metoda predstavljena alert
ki služi za prikaz opozorilnega znaka. Čeprav se je v preteklosti pogosto uporabljal, je trenutno v kodi skoraj prepovedan JavaScript zaradi tega, kako agresivno (vsiljivo) je prekriti spletno stran s pogovornim oknom.
V programu, napisanem za a mikrokrmilnik majhne serije (kot je na plošči Arduino Uno) je običajna uporaba globalnih spremenljivk, kot v prejšnjem primeru v JavaScript, ker je koda kratka in ni posebej zmedena, ker so funkcije velikokrat implementirane ad hoc in ker uporaba globalnih spremenljivk omogoča napovedovanje uporabe pomnilnika na zelo preprost in intuitiven način, kar je ključnega pomena v sistemih z malo viri . Namesto tega en JavaScript Običajno je zmanjšati uporabo globalnih spremenljivk na najmanjšo možno mero. ker mu ni treba pospeševati porabe pomnilnika, saj deluje normalno na a CPU z viri, ki so veliko boljši od tistih v a MCU, ker bo verjetno obstajal skupaj z veliko kodo tretjih oseb, s katero mora delovati brez vmešavanja, in ker je odprt sistem, prihodnjega konteksta izvajanja ni mogoče predvideti (program mikrokrmilnik small popolnoma določa njegovo delovanje, ne da bi dodal več kode, ko je v delovanju) in ker bi lahko dimenzije aplikacij otežile branje, če koda ne zajame njegovega delovanja, zaradi česar so metode čim bolj samostojne.
Matematične operacije z objektom JavaScript Math
V predmetu so združene matematične operacije zahtevnejšega matematičnega računanja Math
. Ta objekt se uporablja neposredno, ni ga treba instancirati za uporabo metod ali lastnosti (konstant), ki jih vključuje.
Math.abs(n)
Absolutna vrednost parametra nMath.acos(n)
Arkosinus parametra n (rezultat v radianih)Math.asin(n)
Arkusin parametra n (rezultat v radianih)Math.atan(n)
Arktangens parametra n (rezultat v radianih)Math.atan2(n,m)
Arktangens n/m (rezultat v radianih)Math.ceil(n)
Zaokrožite parameter na najbližje celo število navzgorMath.cos(α)
Kosinus parametra α (α v radianih)Math.E
e število (≃2.718281828459045)Math.exp(n)
e dvignjen na parameter n: enMath.floor(n)
Zaokrožite parameter n na najbližje celo število navzdolMath.log(n)
Naravni logaritem (osnova e) parametra nMath.LN2
Naravni logaritem (osnova e) od 2 (≃0.6931471805599453)Math.LN10
Naravni logaritem (osnova e) od 10 (≃2.302585092994046)Math.LOG2E
Logaritem z osnovo 2 od e (≃1.4426950408889634)Math.LOG10E
Logaritem z osnovo 10 od e (≃0.4342944819032518)Math.max(a,b,c,…)
Največja vrednost seznama posredovanih parametrovMath.min(a,b,c,…)
Najmanjša vrednost seznama posredovanih parametrovMath.PI
Število π (≃3.141592653589793)Math.pow(n,m)
Prvi parameter n dvignjen na drugi parameter m: nmMath.random()
(Skoraj) naključno število med 0.0 in 1.0Math.round(n)
Zaokrožite parameter n na najbližje celo številoMath.sin(α)
Sinus parametra α (α v radianih)Math.sqrt(n)
Kvadratni koren parametra nMath.SQRT1_2
Kvadratni koren iz 1/2 (≃0.7071067811865476)Math.SQRT2
Kvadratni koren iz 2 (≃1.4142135623730951)Math.tan(α)
Tangens parametra α (α v radianih)
Nalaganje podatkov s strežnika z AJAX
Metoda za risanje informacij, shranjenih v IoT, je sestavljena iz občasnega nalaganja podatkov s strežnika in ponovnega risanja grafa, s katerim so predstavljeni. Za branje podatkov s strežnika se uporablja tehnologija AJAX (asinhroni JavaScript in XML) skozi predmet XMLHttpRequest
de JavaScript. Izris podatkovnega grafa poteka s ponovno uporabo predmeta SVG ki je že v kodi HTML in ki vsebuje graf, katerega koordinate so spremenjene, da ustrezajo novim naloženim podatkom.
V primeru tega predloga se poleg posodobitve risbe posodobi tudi besedilo na spletni strani, ki prikazuje datum in vrednost zadnjega izmerjenega podatka za posamezen graf.
Na strani strežnika je zbirka podatkov, ki vsebuje informacije ki so jih nadzorovali senzorji, povezani z IoT. To bazo podatkov bere objektna zahteva XMLHttpRequest
odzivanje z informacijami, kodiranimi v Format JSON, čeprav ime uporabljene metode nakazuje povezavo s formatom XML.
V prvi vadnici polaridad.es o IoT shranjevanje podatkov Ogledate si lahko primer infrastrukture za upravljanje informacij s strani strežnika, ki jih zagotavljajo naprave, povezane z internetom stvari. V tej seriji člankov je strežnik uporabljen kot vir Apache iz katerega lahko uporabljate programski jezik PHP za dostop do baze podatkov MySQL o MariaDB. Na strežnikih, ki se uporabljajo za podporo IoT, je zelo pogosto najti baze podatkov MongoDB (NoSQL) in programski jezik JavaScript na Node.js kot programska infrastruktura.
Naslednja funkcija je odgovorna za zahtevanje najnovejših podatkov enega od senzorjev s strežnika. Pri klicu funkcije se objekt uporablja kot argument JavaScript ki podpira narisane podatke. Če isti graf predstavlja več vrednosti, na primer za vizualno iskanje korelacije, lahko strežniku pošljete zahtevo, da vrne več hkrati, kar je bolj optimalna metoda zaradi načina delovanja strežnika. protokol HTTP.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
function consultar_ultimo_valor_sensores(objeto_grafico)
{
var consulta=‘zona=”+objeto_grafico.sufijo_nombre;
var pagina=“ultimo_valor_sensor.php”;
var resultado;
var ajax;
if(window.XMLHttpRequest)
{
ajax=new XMLHttpRequest(); // ajax=Object.create(XMLHttpRequest);
}
else // Versiones antiguas de MS Internet Explorer
{
ajax=new ActiveXObject(“Microsoft.XMLHTTP”);
}
ajax.onreadystatechange=
function()
{
if(ajax.readyState==4&&ajax.status==200&&ajax.responseType==“json”)
{
resultado=JSON.parse(ajax.responseText);
if(resultado.fecha>objeto_grafico.fecha[objeto_grafico.fecha.length–1])
{
// Normalmente se gestionará la respuesta utilizando el objeto
redibujar_grafico(objeto_grafico,resultado);
// Si los datos son sencillos y tienen una estructura clara puede ser más práctico usarla directamente
// redibujar_grafico(objeto_grafico,[resultado.fecha,resultado.temperatura]);
}
}
}
ajax.open(“POST”,pagina);
ajax.setRequestHeader(“Method”,“POST “+pagina+” HTTP/1.1″);
ajax.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);
ajax.setRequestHeader(“Content-length”,consulta.length);
ajax.setRequestHeader(“Connection”,“close”);
ajax.send(consulta);
}
|
V tretji vrstici prejšnjega primera je pripravljena poizvedba, ki bo poslana strežniku, v kateri bo posredovan argument »cona«, katerega vrednost bo ime ali koda opazovanega mesta, saj informacije o območje lahko soobstajajo v isti bazi podatkov različni senzorji (na primer termometri, ki merijo temperaturo v različnih prostorih). Parameter, posredovan prejšnji funkciji, objektu s podatki grafikona, naj bi vključeval lastnost z imenom sobe (»pripona_ime«).
Med vrsticama 7 in 14 prejšnje kode je objekt XMLHttpRequest
ki je shranjen v spremenljivki "ajax". Preden izberete, kako ustvariti predmet, iščete window
samo po sebi XMLHttpRequest
ni bil na voljo (nekaj, kar se je zgodilo v starih različicah Microsoftovega raziskovalca in čeprav je daleč zadaj, služi kot primer možnosti za ustvarjanje predmeta z uporabo (bolj domače) sintakse) Object.create
o new
, podobno kot pri drugih objektno usmerjenih jezikih.
Da bi lahko odgovor takoj upravljali, je koda, ki ga obravnava, pripravljena v vrsticah 15 do 26, preden pošlje zahtevo strežniku.
Način izvedite poizvedbo HTTP do strežnika sestavljajo odprite povezavo z open
navedbo vrste in strani (po želji uporabniško ime in geslo), pripravite glave protokola z setRequestHeader
y pošlji zahtevo z send
. Glava HTTP Content-length
poznati boste morali dolžino poizvedbe (število znakov), ki se izračuna z uporabo length
.
Ko zahteva AJAX je pripravljen, se izvede funkcija, povezana z dogodkom onreadystatechange
. Namesto dodelitve funkcije se v prejšnjem primeru sproti definira anonimna funkcija, ki bo upravljala s sprejemom podatkov, ki prihajajo s strežnika. Najprej se v vrstici 18 preveri, ali je status zahteve "končano", kar ustreza vrednosti 4
lastnine readyState
, da je stanje "V redu" za protokol HTTP (Koda 200
), ki jih je mogoče pridobiti od nepremičnine status
in da so prispeli podatki Format JSON, svetovanje nepremičnine responseType
.
Ko preverite, ali je status odgovora pričakovan, v vrstici 20 prejšnjega primera ustvari predmet z rezultatom in pretvori besedilo JSON. Odgovor zagotavlja datum, ki ga je treba vrniti, kar nam omogoča, da vidimo, ali je bil rezultat, ki ga pošlje strežnik, že prej predstavljen v grafu, kar je preverjeno v vrstici 21. Če so podatki novi, v vrstici 23 funkcija, ki je odgovoren za ponovno risanje grafa z novimi informacijami.
Ideja pri predlaganju te metode branja je, da se bodo podatki zelo pogosto osveževali. Če predstavljene informacije ustrezajo dolgoročnemu obdobju (kot so dnevne ali tedenske temperature), se lahko izvede začetna zahteva, ki zbere vse razpoložljive podatke, nato pa zahteva, podobna tisti v primeru, ki jih posodobi v dopisnik obdobja.
Ustvarite naključne podatke za testiranje
Ko bo vsa strežniška in odjemalska infrastruktura pripravljena, bo funkcija, kot je tista v prejšnjem razdelku, zadolžena za branje podatkov in risanje grafa z njimi, vendar V fazi testiranja je morda bolj praktično uporabiti naključna števila znotraj nadzorovanega obsega da preverite, ali je zapisana koda pravilna. Naslednja funkcija lahko služi kot primer za pridobivanje podatkov med gradnjo končne aplikacije.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
function consultar_ultimo_valor_sensores
(
objeto_grafico,// Objeto dentro del elemento SVG que representa el trazado
valor_maximo, // Valor máximo
valor_minimo, // Valor mínimo
margen_valor // Cantidad extra que se representa sobre/bajo el valor máximo/mínimo
)
{
// La forma más genérica es usar objetos
/*
var nuevo_valor_inventado=
{
fecha:Math.round(Date.now()+Math.random()*1000),
temperatura:Math.random()*Math.abs(valor_maximo-valor_minimo)+valor_minimo
};
*/
// En este caso concreto, como son pocos datos y con una estructura concreta es más práctico usar un vector
var nuevo_valor_inventado=
[
Math.round(Date.now()+Math.random()*1000),
Math.random()*Math.abs(valor_maximo–valor_minimo)+valor_minimo
];
redibujar_grafico(objeto_grafico,nuevo_valor_inventado);
}
|
Namesto branja informacij iz baze podatkov jih zgornji primer naključno generira in posreduje funkciji, ki je zadolžena za risanje grafa. Izmišljeni podatek je vektor, ki ga tvori datum, izražen kot vrednost v milisekundah, trenutek zapisa senzorske informacije in spremljani podatek, ki je med največjo vrednostjo in najmanjšo vrednostjo.
V tem primeru se lahko pri generiranju datuma zakasni do ene sekunde (1000 milisekund) glede na datum v času izuma. Kot Math.random()
ustvari število med 0.0 in 1.0, če ga pomnožimo s 1000, dobimo število med 0 in 1000, ki se nato pretvori v celo število. Na enak način dobimo vrednost tako, da naključno število pomnožimo z obsegom (največ minus najmanj) in dodamo najmanj.
Narišite graf senzorjev IoT z risbo SVG
Ker smo videli, kako lahko pridobimo vrednosti, ki jih želimo predstaviti (temperatura, v primeru) in njihovo časovno lokacijo, ki jo lahko izrazimo skupaj v obliki koordinat, spodnji primer prikazuje funkcijo za risanje poti ki združuje te točke in neobvezno barvno območje, razmejeno s tisto črto na vrhu. Rezultat bi bil podoben naslednji sliki.
Vodoravna os (X) grafa predstavlja čas, navpična os (Y) pa vrednosti, ki so jih spremljali senzorji, povezani z IoT. Horizontalni interval je nekaj sekund, saj se v tem predlogu graf posodablja zelo pogosto (na primer vsako sekundo), da zagotovi informacije o stanju senzorjev skoraj v realnem času.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
function actualizar_grafico
(
grafico, // Objeto SVG con el que se dibuja la gráfico
coordenada, // Matriz con las coordenadas del trazado formada por pares [tiempo,valor] ordenados primero el más antiguo (tiempo menor) último el más nuevo
tiempo_total_representado, // Tiempo total representado por la gráfico (en milisegundos)
valor_maximo, // Valor máximo aceptable antes de emitir una alarma
valor_minimo, // Valor mínimo aceptable antes de emitir una alarma
margen_valor, // Cantidad extra que se representa sobre/bajo el valor máximo/mínimo
parametro_cerrado, // Valor booleano que indica si el trazado se cierra o no (por defecto false)
parametro_ancho_caja, // Ancho de la caja que contiene la gráfico (por defecto 100.0)
parametro_alto_caja // Alto de la caja que contiene la gráfico (por defecto 100.0)
)
{
var cerrado=parametro_cerrado||false; // Valor booleano que indica si el trazado se cierra o no (por defecto false)
var ancho_caja=parametro_ancho_caja||100.0; // Ancho de la caja que contiene la gráfico (por defecto 100.0)
var alto_caja=parametro_alto_caja||100.0; // Alto de la caja que contiene la gráfico (por defecto 100.0)
var coordenadas_trazado=“M “; // Cadena de texto que representa la propiedad “d” del trazado SVG
var desplazamiento=[]; // Desplazamientos X e Y para posicionar el tiempo y el valor representado dentro del rango del gráfico
var escala=[]; // Coeficientes X e Y para calcular el tamaño al representar el gráfico
var sin_recortar=true; // False si la gráfico se sale de la caja (si se sale, si recorta, se hace false para no seguir dibujando puntos)
var contador_valor=coordenada.length–1; // Variable para recorrer los valores (índice)
var posicion=[]; // Variable intermedia (para hacer más legible el código) con la que calcular la posición horizontal y vertical de un punto del trazado
escala[0]=ancho_caja/tiempo_total_representado; // Coeficiente que multiplica a los valores horizontales (tiempo) para calcular las coordenadas X
escala[1]=alto_caja/(Math.abs(valor_maximo–valor_minimo)+margen_valor*2); // Coeficiente que multiplica a los valores (vertical) para calcular las coordenadas Y
desplazamiento[0]=coordenada[coordenada.length–1][0]–tiempo_total_representado; // Valor desde el que se empieza a contar el tiempo: el valor mayor (último) menos el rango de tiempo representado
desplazamiento[1]=margen_valor–valor_minimo; // Valor menor mostrado (al menor se le añade un margen para visualizar el principio de los valores fuera del rango permitido)
if(cerrado) // Si se dibuja un path (trazado) cerrado…
{
coordenadas_trazado+=ancho_caja+“,”+alto_caja+” L “; // …se empieza por la parte inferior de la caja
}
while(contador_valor>=0&&sin_recortar) // Mientras queden valores por representar y no se haya llegado al borde izquierdo del gráfico…
{
posicion[0]=(coordenada[contador_valor][0]–desplazamiento[0])*escala[0]; // Calcular la X restando al tiempo el desplazamiento y convirtiéndolo a la escala del gráfico con el coeficiente horizontal
posicion[1]=alto_caja–(coordenada[contador_valor][1]+desplazamiento[1])*escala[1]; // Calcular la Y restando del alto de la caja (la Y crece hacia abajo en SVG)
coordenadas_trazado+=posicion[0]+“,”+posicion[1]; // Formar la coordenada con la X y la Y
if(posicion[0]>0) // Si no se ha rebasado el margen izquierdo…
{
coordenadas_trazado+=contador_valor>0?” L “:“”; // …y quedan valores que represntar, añadir una nueva línea (código L) para el próximo
contador_valor—; // Pasar al siguiente valor
}
else // Si se ha rebasado el margen izquierdo…
{
sin_recortar=false; // …abandonar el modo sin recorte (lo que terminará de calcular coordenadas)
}
}
if(cerrado) // Si se dibuja un trazado (path) cerrado…
{
coordenadas_trazado+=” L “+posicion[0]+“,”+alto_caja+” Z”; // …se termina por la parte inferior de la caja y se añade Z para cerrarlo en SVG
}
grafico.setAttribute(“d”,coordenadas_trazado); // Cambiar las coordenadas del trazado (propiedad “d”) por las que se han calculado
}
|
V prejšnji kodi sta dva zanimiva vidika, najprej izračun, ki omogoča prilagodi obseg vrednosti, ki so predstavljene in drugič gradnja lastnine d
ki označuje koordinate točk na postavitvi (path
).
Za prilagoditev obsega predstavljenih vrednosti se le-te premaknejo z minimuma in pomanjšajo tako, da vidna velikost ustreza velikosti grafa. V primeru časa dobimo zamik tako, da od najdaljšega časa (datum in čas, ki sta najbližje trenutnemu) (20 sekund v primeru) odštejemo obseg, ki ga želimo prikazati. Zamik temperaturnih vrednosti je spodnji razpon (ena stopinja) minus najnižja vrednost, tako da so spodaj prikazani podatki najbolj podobni najnižji dovoljeni vrednosti, vendar puščajo rob, ki nam omogoča, da ocenimo, kaj je prešlo
Koeficient, ki pomnoži časovne vrednosti za pridobitev vodoravnih koordinat grafa, dobimo tako, da skupno širino grafa (100 enot v primeru) delimo s predstavljenim časovnim obsegom (20 sekund v primeru). Za pridobitev koeficienta s skalarnimi temperaturnimi vrednostmi si je treba zapomniti, da gre predstavljeni razpon od roba pod najmanjšo vrednostjo do roba nad največjo, eno stopinjo v obeh primerih. Na ta način navpični koeficient lestvice izhaja iz deljenja višine grafa (v primeru 100 enot) z največjo vrednostjo, zmanjšano za najmanjšo ter zgornji in spodnji rob. Ker bi se te vrednosti lahko popolnoma razvile pri negativnih temperaturah, uporabljamo Math.abs()
uporabiti absolutno vrednost razlike.
Premoženje d
objekta path
Konstruira se z združevanjem koordinat točk v besedilu. Pred vsakim parom koordinat je koda SVG L
, ki nariše črto od trenutnega položaja do absolutne vrednosti, ki jo označujejo koordinate. Vrednosti X in Y sta ločeni z vejicami in vsako operacijo SVG je s presledkom ločen od naslednjega.
Za začetek postavitve uporabite kodo M
(premakni se na absolutno koordinato). V primeru zaprtega in zapolnjenega grafa začnete spodaj desno, v primeru odprtega grafa, ki riše profil podatkov, začnete z zadnjo predstavljeno vrednostjo (najnovejša). Za dokončanje zaprte postavitve se uporabi koda Z
dodajanje kot zadnje točke tiste, ki ima enako vrednost koordinate X kot zadnja točka črte in kot koordinate Y najmanjšo predstavljeno vrednost.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
function dibujar_grafico()
{
var tiempo_mostrado=20000; // Se representan 20 segundos (20000 milisegundos)
var valor_maximo=10; // 10 grados sobre cero
var valor_minimo=–5; // Cinco grados bajo cero
var fecha_hora=Date.now(); // Hora actual
var matriz_de_coordenadas_de_prueba=[]; // Preparar el vector de coordenadas
for(var contador=0;contador<20;contador++)
{
fecha_hora+=500+1500*Math.random(); // Añadir medio segundo a la hora anterior y entre 0 y segundo y medio aleatoriamente
matriz_de_coordenadas_de_prueba[contador]=[]; // Preparar el siguiente punto del vector de coordenadas
matriz_de_coordenadas_de_prueba[contador][0]=fecha_hora; // En la coordenada horizontal, situar la hora
matriz_de_coordenadas_de_prueba[contador][1]=Math.random()*Math.abs(valor_maximo–valor_minimo)+valor_minimo; // En la coordenada vertical situar el valor del sensor
}
actualizar_grafico
(
document.getElementById(“relleno_temperatura”), // Trazado para el relleno definido en el código HTML
matriz_de_coordenadas_de_prueba,
tiempo_mostrado,
valor_maximo, // Diez grados de valor máximo
valor_minimo, // Cinco grados bajo cero como valor mínimo
1, // Un grado por encima y por debajo de las temperatura mínimas y máximas respectivamente
true // Cerrar el trazado para representar el área rellena
);
actualizar_grafico
(
document.getElementById(“linea_temperatura”), // Trazado para el relleno definido en el código HTML
matriz_de_coordenadas_de_prueba,
tiempo_mostrado,
valor_maximo, // Diez grados de valor máximo
valor_minimo, // Cinco grados bajo cero como valor mínimo
1, // Un grado por encima y por debajo de las temperatura mínimas y máximas respectivamente
false // No cerrar el trazado para representar la linea que une los puntos que representan las temperaturas
);
}
|
V tem primeru je funkcija dibujar_grafico()
, ki je klic ob nalaganju strani, pridobi začetne vrednosti za testiranje (ne zadnje vrednosti v realnem času) in pripravi obseg, v katerem bodo podatki upodobljeni: 20 sekund (20000 ms) vodoravno in 15 °C v navpično od -5°C do +10°C z enostopenjskim zgornjim in spodnjim robom. Opravite dva klica na actualizar_grafico()
, v prvem prehodu true
kot argument, ki nakazuje, da mora biti grafikon zaprt, da predstavlja zapolnjeno območje, pri drugem klicu pa preide false
da potegnem črto. V vsakem primeru predmet path
modificirana je tista, ki ima ustrezen videz, s polnilom in brez roba v prvem primeru in z določeno debelino črte in brez polnila v drugem primeru.
Funkcija actualizar_grafico()
delo na objektu SVG ki kot vsebnik uporablja naslednjo kodo HTML. Objekt SVG vsebuje dve poti, eno za risanje črte in drugo za risanje zapolnjenega območja. Pri nalaganju spletne strani iz elementa <body>
prejšnja funkcija se samodejno prikliče, dibujar_grafico()
zahvaljujoč dogodku JavaScript onload
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<!DOCTYPE html>
<html lang=“es”>
<head>
<meta charset=“utf-8”>
<title>Temperatura</title>
<script type=“text/javascript” src=“https://polaridad.es/javascript-grafico-svg-sensor-internet-de-las-cosas-iot/grafico.js”></script>
</head>
<body onload=“dibujar_grafico();” style=“margin:0;”> <!– Cuerpo del documento HTML. Al cargar el contenido llama a la función JavaScript dibujar_grafico() –>
<div id=“temperatura”>
<div id=“bloque_temperatura” style=“width:820px;height:150px”>
<svg
id=“grafico_temperatura”
width=“100%”
height=“100%”
viewBox=“0 0 100 100”
preserveAspectRatio=“none”>
<path
id=“relleno_temperatura”
d=“”
style=“fill:#A8C3EA;stroke:none;”
vector-effect=“non-scaling-stroke”
/>
<path
id=“linea_temperatura”
d=“”
style=“fill:none;stroke:#205587;stroke-width:4;stroke-opacity:1;”
vector-effect=“non-scaling-stroke”
/>
</svg>
</div>
</div>
</body>
</html>
|
V 10. vrstici kode HTML zgoraj je v slogu določena širina (kot primer) 820 px in višina 150 px (nekaj, kar bo v končni različici priporočljivo narediti z razredom in dokumentom CSS). Nenavadno se zdi, da vrstici 13 in 14 določata velikost predmeta SVG kot 100 % širina in višina (kar najbolj ustreza dimenzijam okna, 100×100). Kot že omenjeno, je razlog za to, da vedno delamo z znanimi dimenzijami in jim prilagodimo predstavljene vrednosti. Druge možnosti bi bile vsakič izračunati prostor grafa in pozneje znova prilagoditi vrednosti ali vsiliti fiksne dimenzije za graf, ki se jih mora dokument držati.
Odločitev za graf, katerega dimenzije se spreminjajo glede na kodo HTML, je treba vključiti nepremičnino vector-effect
z vrednostjo non-scaling-stroke
za preprečitev deformacije debeline črt, ko graf ne ohranja izbranih razmerij 1:1 na spletni strani, na kateri je prikazan, kot se dogaja v prejšnjem predlogu.
Če želite "obrezati" graf in prikazati samo območje, ki ga izberete, uporabite viewBox
. V tem primeru smo se odločili, da vidimo del grafa, ki se začne pri 0,0 (zgornji levi kot) in meri 100x100 navzdol in desno. Del risbe, ki se nahaja v koordinatah z negativnimi vrednostmi ali večjimi od 100, ne bo prikazan na spletni strani, tudi če obstajajo v objektu SVG
Dodajte nove elemente risbi SVG
V prejšnjem primeru je funkcija actualizar_grafico()
uporabite postavitev SVG na katero se spremeni lastništvo d
, kar izraža koordinatno verigo. Druga možnost bi bila, da ustvarite celoten predmet vsakič, ko ga ponovno narišete. Prednost prve možnosti je, da je grafični videz (kot je debelina ali barva) definiran v kodi HTML, omejitev je, da morajo biti objekti predhodno ustvarjeni.
Če želite ustvariti objekte SVG, uporabite createElementNS()
, ki omogoča vključitev imenski prostor. V spodnjem primeru je ustvarjen nov besedilni predmet (text
) in je povezan z elementom SVG ki že obstaja v kodi HTML spletnega mesta. Ko je nov element ustvarjen, so njegove lastnosti dodeljene z setAttribute()
in se doda SVG z appendChild()
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
function
rotular
(
objeto_grafico,
texto,
inicio=[0,0],
altura=10.0,
tipo_letra=“SircuitoRegularMedium”,
color_texto=“#000000”,
color_fondo=“#FFFFFF”
)
{
nuevo_objeto_svg=document.createElementNS(“http://www.w3.org/2000/svg”,“text”);
nuevo_objeto_svg.setAttribute(“x”,inicio[0]);
nuevo_objeto_svg.setAttribute(“y”,inicio[1]);
nuevo_objeto_svg.setAttribute(“font-family”,tipo_letra);
nuevo_objeto_svg.setAttribute(“font-size”,altura);
nuevo_objeto_svg.setAttribute(“fill”,color_texto);
nuevo_objeto_svg.textContent=texto;
objeto_grafico.appendChild(nuevo_objeto_svg);
}
//rotular(document.getElementById(“cosa_svg”),”HOLA”,[10,10]);
|
Spremenite razmerje elementov risanja
Če ste poskusili označiti s funkcijo v primeru v prejšnjem razdelku, ste videli, da je besedilo videti deformirano, ko je delež predmeta na spletni strani (width
y height
Kode HTML) ni enako predstavljenemu območju (viewBox
). Za prilagoditev razmerja je potrebno poznati mere predmeta SVG za katere si lahko ogledate slog predmeta ali vsebnika HTML, če predmet SVG prenesti to lastnino. Dodeljevanje lastništva transform
do predmetov SVG ki so odvisne od razmerja, je mogoče deformacijo popraviti z uporabo operacije skaliranja scale()
v kateri je koeficient v X drugačen od tistega v Y.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
function
rotular
(
objeto_grafico,
texto,
inicio=[0,0],
altura=10.0,
proporcion=1.0,
tipo_letra=“SircuitoRegularMedium”,
color_texto=“#000000”,
color_fondo=“#FFFFFF”
)
{
var escala_horizontal=parseFloat(getComputedStyle(objeto_grafico).height)/parseFloat(getComputedStyle(objeto_grafico).width);
nuevo_objeto_svg=document.createElementNS(“http://www.w3.org/2000/svg”,‘text’);
nuevo_objeto_svg.setAttribute(“transform”,“scale(“+escala_horizontal+“,1.0)”); // scale permite cambiar la escala en X e Y
//nuevo_objeto_svg.setAttribute(“transform”,”scaleX(“+escala_horizontal+”)”); // Como se sabe que sólo cambia la escala en X, se puede usar scaleX
nuevo_objeto_svg.setAttribute(“x”,inicio[0]);
nuevo_objeto_svg.setAttribute(“y”,inicio[1]);
nuevo_objeto_svg.setAttribute(“font-family”,tipo_letra);
nuevo_objeto_svg.setAttribute(“font-size”,altura);
nuevo_objeto_svg.setAttribute(“fill”,color_texto);
nuevo_objeto_svg.textContent=texto;
objeto_grafico.appendChild(nuevo_objeto_svg);
}
//rotular(document.getElementById(“cosa_svg”),”HOLA”,[10,10]);
|
SVG omogoča združevanje več predmetov v nov sestavljeni element, ki prav tako podpira lastnosti, kot so preprosti predmeti. Če želite isto transformacijo uporabiti za niz predmetov hkrati, namesto za vsak predmet posebej, jih lahko združite glede na ta vir in uporabite eno lastnost transform
vsem njim.
Kot je razloženo, ko govorimo o SVG format, so elementi skupine zaprti znotraj oznak <g>
y </g>
. Če želite dodati iz JavaScript elemente v skupino SVG se uporablja, kot je razvidno iz prejšnjega primera, appendChild()
ko je nov objekt definiran.
Za določitev izvora pri uporabi transformacij lahko lastnost uporabite na objektih SVG transform-origin
, katerega vrednost sta koordinati X in Y točke, od katere se transformacija začne. Če vrednost za izvor transformacije ni izrecno navedena (v spletnem brskalniku), se uporabi središče koordinat. Na žalost v času pisanja tega članka podajanje vedenja transformacij z uporabo vira, ki ni privzeti, ni homogeno v različnih brskalnikih in ga je treba uporabljati previdno.
Skupaj s transformacijo lestvice z scale
Obstajajo še drugi, kot je rotacija z rotation
in gibanje s translate
, ki ponujajo a alternativa grafični predstavitvi: namesto da pridobite nove koordinate, jih lahko predstavite v njihovem lastnem prostoru in transformirate graf, da bo ustrezal obliki, v kateri jih želite predstaviti.
Dodajte reference v grafikon
Zdaj, ko je glavni del grafa razrešen z izrisom vrednosti s profilom in zapolnjenim območjem, ga je mogoče dopolniti s sklici, ki pomagajo pri njegovem branju. Kot primer, začnimo z risanjem nekaj vodoravnih referenc (črt), ki označujejo največje in najmanjše sprejemljive vrednosti ter želeno vrednost. Kot je razloženo, lahko izberete, da dodate predmete v SVG naravnost od JavaScript ali jih ročno vključite v kodo HTML in jih pozneje spremenite z JavaScript.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
var CONTENEDOR_SVG; // Objeto SVG que contiene el gráfico que representa los valores monitorizados por los sensores en la IoT
var NS=“http://www.w3.org/2000/svg”; // Nombre del espacio de nombres (name space NS)
var ANCHO_CAJA=100.0; // Ancho del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones
var ALTO_CAJA=100.0; // Alto del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones
var VALOR_MAXIMO=10.0; // Mayor valor admisible en el gráfico SVG. Los valores mayores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
var VALOR_MINIMO=–5.0; // Menor valor admisible en el gráfico SVG. Los valores menores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
var VALOR_DESEADO=5.0; // Mejor valor del parámetro medido (temperatura). Sirve para tener una idea rápida de cómo de correcto es el estado del sistema
var MARGEN_VALOR=1.0; // Zona por encima del valor mayor y por debajo del valor menor que se representa para tener una idea aproximada de la tendencia cuando los datos monitorizados rebasen los valores máximo y/o mínimo
function inicializar_grafico()
{
CONTENEDOR_SVG=document.getElementById(“contenedor_svg”);
crear_referencia_horizontal_svg(VALOR_MAXIMO,“#FF0000”);
crear_referencia_horizontal_svg(VALOR_DESEADO,“#00FF00”);
crear_referencia_horizontal_svg(VALOR_MINIMO,“#0000FF”);
}
function crear_referencia_horizontal_svg
(
altura=0.0,
color=“#000000”,
grosor=0.5,
opacidad=1.0
)
{
var altura_corregida=ALTO_CAJA–(altura+MARGEN_VALOR–VALOR_MINIMO)*ALTO_CAJA/(Math.abs(VALOR_MAXIMO–VALOR_MINIMO)+MARGEN_VALOR*2);
var referencia_horizontal=document.createElementNS(NS,‘line’);
referencia_horizontal.setAttribute(“x1”,0.0);
referencia_horizontal.setAttribute(“x2”,ANCHO_CAJA);
referencia_horizontal.setAttribute(“y1”,altura_corregida);
referencia_horizontal.setAttribute(“y2”,altura_corregida);
referencia_horizontal.style.stroke=color;
referencia_horizontal.style.strokeWidth=grosor;
referencia_horizontal.style.strokeOpacity=opacidad;
CONTENEDOR_SVG.appendChild(referencia_horizontal);
}
//inicializar_grafico();
|
Zdi se logično, da te horizontalne reference označimo z besedilom, ki pojasnjuje vrednost, ki jo predstavljajo. Za poudarjanje besedila lahko uporabite pravokotnike, ki bodo izstopali iz ozadja in grafike. Ker bo treba besedila prilagoditi merilu, da bi nadomestili deformacijo, jih je mogoče vsa združiti v objekt, na katerega bo uporabljeno merilo; Glavna prednost tega načina je, da jih lahko spremenite v eni sami operaciji, če spremenite velikost vsebnika grafa (okno brskalnika) in spremenite razmerje, ki ga popravi lestvica.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
// Este código de ejemplo usa constantes para hacerlo más legible a desarrolladores de aplicaciones para microcontroladores de series pequeñas. La opción más recomendable, y más propia del estilo JavaScript, es crear un objeto cuyas propiedades serían las constantes y que incluiría los métodos (aquí funciones) que generan o modifican el gráfico o en este caso las referencias
var CONTENEDOR_SVG; // Objeto SVG que contiene el gráfico que representa los valores monitorizados por los sensores en la IoT
var NS=“http://www.w3.org/2000/svg”; // Nombre del espacio de nombres (name space NS)
var ANCHO_CAJA=100.0; // Ancho del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones
var ALTO_CAJA=100.0; // Alto del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones
var TIEMPO_REPRESENTADO=30000; // Milisegundos visibles en el gráfico empezando en el valor mayor (fecha y hora del último valor monitorizado)
var VALOR_MAXIMO=10.0; // Mayor valor admisible en el gráfico SVG. Los valores mayores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
var VALOR_MINIMO=–5.0; // Menor valor admisible en el gráfico SVG. Los valores menores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
var VALOR_OPTIMO=5.0; // Mejor valor del parámetro medido (temperatura). Sirve para tener una idea rápida de cómo de correcto es el estado del sistema
var MARGEN_VALOR=2.0; // Zona por encima del valor mayor y por debajo del valor menor que se representa para tener una idea aproximada de la tendencia cuando los datos monitorizados rebasen los valores máximo y/o mínimo
var desplazamiento_valor=desplazamiento(Date.now());
var escala_valor=escala();
var TIPOGRAFIA=“SircuitoRegularMedium”; // Tipografía con la que se rotula todo el gráfico (se usa una constante buscando la uniformidad, pero se puede rotular usando diferentes tipos de letra si es necesario)
var ALTURA_TEXTO=10.0; // Altura de los textos en valor absoluto (píxeles)
var COLOR_MINIMO=“#621D87”; // Color de la referencia que indica el valor mínimo
var COLOR_OPTIMO=“#1D8762”; // Color de la referencia que indica el valor máximo
var COLOR_MAXIMO=“#871E35”; // Color de la referencia que indica el valor óptimo
var COLOR_TIPOGRAFIA=“#A8C3EA”; // Color del tipo de letra con que se rotulan las referencias
var GROSOR_REFERENCIA=0.5; // Grosor de la línea que se dibuja como referencia en valor absoluto (píxeles)
var OPACIDAD_REFERENCIA=1.0; // Opacidad de la línea de referencia. Si se dibuja sobre el gráfico con cierta transparencia permite ver el dibujo bajo ella
var RELLENO_FONDO_REFERENCIA=4.0; // Margen entre el fondo de la referencia y el texto medido en valor absoluto (la línea empieza en el margen izquierdo y recorre todo el gráfico)
var MARGEN_FONDO_REFERENCIA=10.0; // Separación de la referencia y el borde izquierdo del gráfico medido en valor absoluto (la línea empieza en el margen izquierdo y recorre todo el gráfico)
var ANCHO_FONDO_REFERENCIA=34.0; // Medida horizontal del rectángulo que hace de fondo al texto de la referencia medido en valor absoluto
function proporcion_grafico()
{
return parseFloat(getComputedStyle(CONTENEDOR_SVG).height)/parseFloat(getComputedStyle(CONTENEDOR_SVG).width); // La escala debe calcularse cada vez ya que no se sabe si se ha redimensionado el objeto HTML que contiene al objeto SVG y que le da el tamaño
}
function medida_grafico()
{
var proporcion=[]; // Coeficiente que calcula la medida absoluta en píxeles en función del ancho/alto base del gráfico y de la representación en la página web // Coeficiente que calcula la medida absoluta en píxeles en función del ancho/alto base del gráfico y de la representación en la página web
proporcion[0]=ANCHO_CAJA/parseFloat(getComputedStyle(CONTENEDOR_SVG).width);
proporcion[1]=ALTO_CAJA/parseFloat(getComputedStyle(CONTENEDOR_SVG).height);
return proporcion;
}
function desplazamiento(valor_mayor)
{
var desplazamiento_valor=[];
desplazamiento_valor[0]=valor_mayor–TIEMPO_REPRESENTADO; // Valor desde el que se empieza a contar el tiempo: el valor mayor (último) menos el rango de tiempo representado
desplazamiento_valor[1]=MARGEN_VALOR–VALOR_MINIMO; // Valor menor mostrado (al menor se le añade un margen para visualizar el principio de los valores fuera del rango permitido)
return desplazamiento_valor;
}
function escala()
{
var escala_valor=[];
escala_valor[0]=ANCHO_CAJA/TIEMPO_REPRESENTADO; // Coeficiente que multiplica a los valores horizontales (tiempo) para calcular las coordenadas X
escala_valor[1]=ALTO_CAJA/(Math.abs(VALOR_MAXIMO–VALOR_MINIMO)+MARGEN_VALOR*2); // Coeficiente que multiplica a los valores (vertical) para calcular las coordenadas Y
return escala_valor;
}
function crear_referencia_horizontal_svg
(
posicion=0.0,
color_dibujo=“#000000”,
grosor_linea=GROSOR_REFERENCIA,
opacidad_linea=OPACIDAD_REFERENCIA,
color_texto=COLOR_TIPOGRAFIA,
altura_texto=ALTURA_TEXTO
)
{
var proporcion_horizontal=proporcion_grafico(); // La escala debe calcularse cada vez ya que no se sabe si se ha redimensionado el objeto HTML que contiene al objeto SVG y que le da el tamaño
var coeficiente_medida=medida_grafico();
var posicion_corregida=ALTO_CAJA–(posicion+desplazamiento_valor[1])*escala_valor[1];
var referencia_horizontal=document.createElementNS(NS,‘line’); // El orden en el que se crean los objetos determina qué tapa (lo último) y que es tapado (lo primero)
var fondo_referencia=document.createElementNS(NS,‘rect’); // El rectángulo (opaco) se creará después de la línea (que puede ser un poco transparente) para definir con claridad el fondo del texto
var texto_referencia=document.createElementNS(NS,‘text’); // El texto se creará en último lugar para que quede sobre los otros objetos
referencia_horizontal.setAttribute(“x1”,0.0);
referencia_horizontal.setAttribute(“x2”,ANCHO_CAJA);
referencia_horizontal.setAttribute(“y1”,posicion_corregida);
referencia_horizontal.setAttribute(“y2”,posicion_corregida);
referencia_horizontal.style.stroke=color_dibujo;
referencia_horizontal.style.strokeWidth=grosor_linea*coeficiente_medida[1];
referencia_horizontal.style.strokeOpacity=opacidad_linea;
CONTENEDOR_SVG.appendChild(referencia_horizontal); // Añadir la línea de referencia lo más abajo
fondo_referencia.setAttribute(“x”,MARGEN_FONDO_REFERENCIA*coeficiente_medida[0]);
fondo_referencia.setAttribute(“y”,posicion_corregida–(ALTURA_TEXTO+RELLENO_FONDO_REFERENCIA*2.0)*coeficiente_medida[1]/2.0);
fondo_referencia.setAttribute(“width”,ANCHO_FONDO_REFERENCIA*coeficiente_medida[0]);
fondo_referencia.setAttribute(“height”,(ALTURA_TEXTO+RELLENO_FONDO_REFERENCIA*2.0)*coeficiente_medida[1]);
fondo_referencia.style.fill=color_dibujo;
fondo_referencia.style.fillOpacity=1.0;
fondo_referencia.style.strokeWidth=0;
CONTENEDOR_SVG.appendChild(fondo_referencia);
texto_referencia.setAttribute(“x”,(MARGEN_FONDO_REFERENCIA+RELLENO_FONDO_REFERENCIA)*coeficiente_medida[0]/proporcion_horizontal);
texto_referencia.setAttribute(“y”,posicion_corregida+ALTURA_TEXTO/2.0*coeficiente_medida[1]);
texto_referencia.setAttribute(“font-family”,TIPOGRAFIA);
texto_referencia.setAttribute(“font-size”,ALTURA_TEXTO*coeficiente_medida[1]);
texto_referencia.setAttribute(“fill”,COLOR_TIPOGRAFIA);
texto_referencia.setAttribute(“transform”,“scale(“+proporcion_horizontal+“,1.0)”);
texto_referencia.textContent=(posicion>=0?“+”:“”)+posicion;
CONTENEDOR_SVG.appendChild(texto_referencia);
}
function inicializar_grafico()
{
CONTENEDOR_SVG=document.getElementById(“contenedor_svg”);
crear_referencia_horizontal_svg(VALOR_MAXIMO,COLOR_MAXIMO);
crear_referencia_horizontal_svg(VALOR_OPTIMO,COLOR_OPTIMO);
crear_referencia_horizontal_svg(VALOR_MINIMO,COLOR_MINIMO);
}
//inicializar_grafico();
|
V zgornjem primeru kode je več zanimivih vidikov. Najprej komentirajte, da so bile uporabljene konstante (globalne spremenljivke), da bi bil primer bolj berljiv uporabnikom, ki prihajajo iz programiranja. mikrokrmilniki en C o en C + +. Kot bo razvidno kasneje, optimalen način za programiranje JavaScript Uporabili bi objekte, ki bi vsebovali te vrednosti in metode, ki bi upravljale reference v tem primeru ali graf na splošno v proizvodnem sistemu.
Po drugi strani, da bi izboljšali, kakšna bi bila bolj splošna koda, so bile razvite ločene funkcije, ki izračunajo različne koeficiente, ki popravijo razmerje grafa za prilagoditev besedila proporcion_grafico()
, lestvica vrednosti glede na njihov razpon escala()
in korekcijski faktor za meritve, ki so znane v absolutni vrednosti, kot so meritve v referencah medida_grafico()
.
Branje te kode bi moralo pomagati razjasniti kontekst, v katerem deluje aplikacija, kot je ta, ki riše grafiko v realnem času in mora biti prilagodljiva za predstavitev v različnih grafičnih kontekstih (vsaj različnih velikostih in razmerjih). Najprej je treba ustvariti objekte SVG, bodisi "ročno" v kodi HTML, bodisi prek kode JavaScript in v vsakem primeru je treba naknadno pridobiti sklice na te objekte, da bi z njimi manipulirali JavaScript tako da je mogoče risati nove grafe in prikaz že narisanega grafa prilagoditi spremembi medija, v katerem je predstavljen.
Druga referenca, ki lahko pomaga pri preprosti interpretaciji grafa, so točke, ki predstavljajo določene vrednosti (vozlišča črte). V tem primeru, v katerem predstavljamo eno samo velikost, izbira simbola ni kritična, toda če je več različnih vrednosti prekritih zaradi iskanja korelacije, je zanimivo razlikovati poleg uporabe drugih virov, kot je barva , z risanjem različnih simbolov. Grafika, uporabljena za črtno vozlišče, mora biti spremenjena v velikosti in razmerju, kot se na primer zgodi pri besedilih, tako da so njene dimenzije absolutne in da se njena razmerja ohranijo, tudi če se razmerja polja, ki ga vsebuje, spremenijo.
V prejšnjem primeru smo že videli, kako izračunati različne koeficiente za spreminjanje velikosti in popravljanje razmerja risbe; V zvezi s tem, kako izvajati upravljanje simbolov vozlišč ali oglišč grafa, je možna rešitev lahko shranjevanje objektov SVG v vektor in spremenite njegov položaj, ko je graf posodobljen z branjem nove vrednosti ali ko je ponovno narisan s spreminjanjem velikosti vsebnika. V prvem primeru bi bilo treba spremeniti njegov položaj, v drugem pa njegovo razmerje z nepremičnino transform
in vrednost scale
. Naslednja koda je modifikacija funkcije actualizar_grafico()
da vključuje prestavljanje simbolov vozlišč grafa.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
function actualizar_grafico_puntos
(
grafico, // Objeto SVG con el que se dibuja la gráfico
coordenada, // Matriz con las coordenadas del trazado formada por pares [tiempo,valor] ordenados primero el más antiguo (tiempo menor) último el más nuevo
puntos, // Matriz con los objetos SVG que se representan en los nodos de la línea (los valores reales)
tiempo_total_representado, // Tiempo total representado por la gráfico (en milisegundos)
valor_maximo, // Valor máximo aceptable antes de emitir una alarma
valor_minimo, // Valor mínimo aceptable antes de emitir una alarma
margen_valor, // Cantidad extra que se representa sobre/bajo el valor máximo/mínimo
parametro_cerrado, // Valor booleano que indica si el trazado se cierra o no (por defecto false)
parametro_ancho_caja, // Ancho de la caja que contiene la gráfico (por defecto 100.0)
parametro_alto_caja // Alto de la caja que contiene la gráfico (por defecto 100.0)
)
{
var cerrado=parametro_cerrado||false; // Valor booleano que indica si el trazado se cierra o no (por defecto false)
var ancho_caja=parametro_ancho_caja||100.0; // Ancho de la caja que contiene la gráfico (por defecto 100.0)
var alto_caja=parametro_alto_caja||100.0; // Alto de la caja que contiene la gráfico (por defecto 100.0)
var coordenadas_trazado=“M “; // Cadena de texto que representa la propiedad “d” del trazado SVG
var desplazamiento=[]; // Desplazamientos X e Y para posicionar el tiempo y el valor representado dentro del rango del gráfico
var escala=[]; // Coeficientes X e Y para calcular el tamaño al representar el gráfico
var sin_recortar=true; // False si la gráfico se sale de la caja (si se sale, si recorta, se hace false para no seguir dibujando puntos)
var contador_valor=coordenada.length–1; // Variable para recorrer los valores (índice)
var posicion=[]; // Variable intermedia (para hacer más legible el código) con la que calcular la posición horizontal y vertical de un punto del trazado
escala[0]=ancho_caja/tiempo_total_representado; // Coeficiente que multiplica a los valores horizontales (tiempo) para calcular las coordenadas X
escala[1]=alto_caja/(Math.abs(valor_maximo–valor_minimo)+margen_valor*2); // Coeficiente que multiplica a los valores (vertical) para calcular las coordenadas Y
desplazamiento[0]=coordenada[coordenada.length–1][0]–tiempo_total_representado; // Valor desde el que se empieza a contar el tiempo: el valor mayor (último) menos el rango de tiempo representado
desplazamiento[1]=margen_valor–valor_minimo; // Valor menor mostrado (al menor se le añade un margen para visualizar el principio de los valores fuera del rango permitido)
if(cerrado) // Si se dibuja un path (trazado) cerrado…
{
coordenadas_trazado+=ancho_caja+“,”+alto_caja+” L “; // …se empieza por la parte inferior de la caja
}
while(contador_valor>=0&&sin_recortar) // Mientras queden valores por representar y no se haya llegado al borde izquierdo del gráfico…
{
posicion[0]=(coordenada[contador_valor][0]–desplazamiento[0])*escala[0]; // Calcular la X restando al tiempo el desplazamiento y convirtiéndolo a la escala del gráfico con el coeficiente horizontal
posicion[1]=alto_caja–(coordenada[contador_valor][1]+desplazamiento[1])*escala[1]; // Calcular la Y restando del alto de la caja (la Y crece hacia abajo en SVG)
punto[contador_valor].setAttribute(“cx”,posicion[0]);
punto[contador_valor].setAttribute(“cy”,posicion[1]);
coordenadas_trazado+=posicion[0]+“,”+posicion[1]; // Formar la coordenada con la X y la Y
if(posicion[0]>0) // Si no se ha rebasado el margen izquierdo…
{
coordenadas_trazado+=contador_valor>0?” L “:“”; // …y quedan valores que represntar, añadir una nueva línea (código L) para el próximo
}
else // Si se ha rebasado el margen izquierdo…
{
sin_recortar=false; // …abandonar el modo sin recorte (lo que terminará de calcular coordenadas)
}
contador_valor—; // Pasar al siguiente valor
}
if(cerrado) // Si se dibuja un trazado (path) cerrado…
{
coordenadas_trazado+=” L “+posicion[0]+“,”+alto_caja+” Z”; // …se termina por la parte inferior de la caja y se añade Z para cerrarlo en SVG
}
grafico.setAttribute(“d”,coordenadas_trazado); // Cambiar las coordenadas del trazado (propiedad “d”) por las que se han calculado
for(;contador_valor>=0;contador_valor—)
{
punto[contador_valor].setAttribute(“cx”,–10000);
punto[contador_valor].setAttribute(“cy”,0);
}
}
|
Spremembe funkcije actualizar_grafico()
da dobite novo funkcijo actualizar_grafico_puntos()
To so tisti, ki so označeni v kodi prejšnjega primera. Najprej v vrstici 5 vzamemo vektor objektov SVG kot parameter. Ta vektor bo vseboval simbole, ki jih je treba prestaviti v nova vozlišča grafa.
V 39. in 40. vrstici so pripisane nove koordinate središča, cx
y cy
, na tiste vrednosti, ki so predstavljene. Če simbol ne bi temeljil na sredini, bo verjetno treba dodati odmik cx
polovico širine in noter cy
polovice višine, da jih prestavite točno na vozlišče grafa.
V vrsticah od 57 do 61 so točke, ki ustrezajo koordinatam, ki niso narisane, ker so odrezane z levim robom, premaknjene zunaj grafa. Koordinata cy
na nič in to od cx
na poljubno negativno število (večje od same točke), tako da ni prikazano, ko ga prerežete, tako kot levi del grafa, z oknom SVG.
Upravljajte grafikon iz predmeta z JavaScriptom
Vse do sedaj razložene operacije je mogoče integrirati v objekt za upravljanje grafa s slogom, ki je bolj značilen za nove različice JavaScript. Ta implementacijska alternativa ima dodatno prednost poenostavljanja vključitve več grafov različnih vrednosti na isto spletno stran.
Preden razpravljamo o izvedbi, si oglejmo najpogostejše načine za ustvarjanje predmetov JavaScript in nekatere posebnosti funkcij, ki vplivajo na predlog za risanje IoT senzorske grafike.
Že pojasnili, da novi način ustvarjanja predmetov v JavaScript (na voljo od različice 5 naprej ECMAscript) je sestavljen iz uporabe Object.create
, ki bi se ga morali navaditi uporabljati namesto "klasičnega" new
, ki seveda še vedno deluje pravilno, čeprav je njegov namen bolj simulacija stila jezikov s predmeti, ki temeljijo na razredu (JavaScript ustvarjanje predmetov temelji na prototipih) kot delujoča alternativa.
1
2
3
4
5
6
7
8
9
10
|
<!DOCTYPE html>
<html lang=“es”>
<head>
<meta charset=“utf-8”>
<title>Crear objetos con new o con Objetct.create</title>
<script type=“text/javascript” src=“https://polaridad.es/javascript-grafico-svg-sensor-internet-de-las-cosas-iot/crear_objetos.js”></script>
</head>
<body onload=“empezar();”>
</body>
</html>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
function Objeto_clasico(primero,segundo)
{
this.primero=primero||1;
this.segundo=segundo||2;
this.hacer_algo=function()
{
console.log(“El objeto clásico le saluda (primero=”+this.primero+” y segundo=”+this.segundo+“)”);
}
}
var Objeto_ES5=
{
primero:10,
segundo:20,
hacer_algo:
function()
{
console.log(“El objeto ES5 le saluda (primero=”+this.primero+” y segundo=”+this.segundo+“)”);
}
}
var objeto_clasico=new Objeto_clasico();
var objeto_ES5=Object.create(Objeto_ES5);
function empezar()
{
console.log(“Objeto clásico (“+objeto_clasico.primero+“,”+objeto_clasico.segundo+“)”);
console.log(“Objeto ES5 (“+objeto_ES5.primero+“,”+objeto_ES5.segundo+“)”);
objeto_clasico.hacer_algo();
objeto_ES5.hacer_algo();
}
|
Prejšnja koda vam omogoča, da si zapomnite razlike med ustvarjanjem predmetov s Object.create
ali z new
. To tudi poudarja, medtem ko je funkcija, s katero je predmet ustvarjen new
je lahko kjer koli v kodi, mora objekt že obstajati, preden ga je mogoče instancirati Object.create
(Objekt ES5_Object ni funkcija).
V vrsticah 3 in 4, da nastavite privzeto vrednost za lastnosti v funkciji, s katero ustvarite predmet new
, je vsaka lastnost dodeljena vrednosti ustreznega argumenta ali (||
), če ni bil posredovan noben argument, to je, če so nedefinirani (undefined
), saj se ta okoliščina ocenjuje kot false
, je dodeljena privzeta vrednost.
Kontekst, v katerem se funkcija izvaja JavaScript odpira dve vprašanji, ki ju je pomembno upoštevati in ki sta lahko tudi zmedeni pri uporabi tega programskega jezika po sodelovanju z drugimi, kot je npr. C o C + +, v našem primeru. Kontekst vključuje spremenljivke, definirane v obsegu funkcije (in globalne), ki mimogrede odpirajo zanimiv koncept, "zapiranje", ki vzpostavi celoten programski slog v JavaScript. Se pravi, to bi lahko pričakovali this
, ki se nanaša na predmet, ko se uporablja znotraj kode, ki ga definira, se izvajalni kontekst, v katerem je bil definiran, ohrani, toda tisti, ki ga uporablja, je kontekst, iz katerega je funkcija poklicana. To vedenje je v večini primerov pregledno, vendar obstajata dve okoliščini, v katerih je lahko zmedeno: funkcija, definirana znotraj druge funkcije, in metoda, ki je poklicana iz dogodka objekta. window
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
var primero=“Primero global”;
var segundo=“Segundo global”;
var Contexto=
{
primero:“Primero en contexto”,
segundo:“Segundo en contexto”,
probar:
function()
{
console.log(“Primero en contexto: “+this.primero);
console.log(“Segundo en contexto: “+this.segundo);
function probar_dentro()
{
console.log(“Primero dentro: “+this.primero);
console.log(“Segundo dentro: “+this.segundo);
}
probar_dentro();
}
}
var probador=Object.create(Contexto);
probador.probar();
/*
Primero en contexto: Primero en contexto
Segundo en contexto: Segundo en contexto
Primero dentro: Primero global
Segundo dentro: Segundo global
*/
|
Pri izvajanju prejšnje kode se v konzoli prikaže komentirano besedilo na koncu. Dve označeni črti odražata vedenje, ki je lahko zmedeno: kontekst izvajanja funkcije probar_dentro()
ne probar()
, kot je bilo pričakovati, vendar window
, ki prikazuje globalne spremenljivke in ne lastnosti z istim imenom. Če ne želite tega obnašanja, preprosto ustvarite spremenljivko v funkciji najvišje ravni in jo dodelite this
, kot v naslednji kodi.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
var primero=“Primero global”;
var segundo=“Segundo global”;
var Contexto=
{
primero:“Primero en contexto”,
segundo:“Segundo en contexto”,
probar:
function()
{
var esto=this;
console.log(“Primero en contexto: “+esto.primero);
console.log(“Segundo en contexto: “+esto.segundo);
function probar_dentro()
{
console.log(“Primero dentro: “+esto.primero);
console.log(“Segundo dentro: “+esto.segundo);
}
probar_dentro();
}
}
var probador=Object.create(Contexto);
probador.probar();
/*
Primero en contexto: Primero en contexto
Segundo en contexto: Segundo en contexto
Primero dentro: Primero en contexto
Segundo dentro: Segundo en contexto
*/
|
Za nadzor konteksta izvajanja, ko je metoda poklicana iz dogodka window
, denimo s spreminjanjem velikosti okna brskalnika, še ena posebnost JavaScript: možnost programiranja "funkcijskih tovarn", torej funkcij, ki generirajo druge funkcije in jih z njimi vračajo return
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
var Contexto=
{
prueba:“objeto”, // La propiedad prueba es de los objetos Contexto
llamar:
function()
{
esto=this;
return function()
{
console.log(“H + “+(Date.now()–hora)+” Contexto: “+esto.prueba);
};
}
}
var prueba=“global”; // Esta variable prueba es global (window.prueba)
var hora=Date.now();
var probador=Object.create(Contexto);
var cosa=probador.llamar();
var pesadez=setInterval(cosa,3000);
setTimeout(function(){clearInterval(pesadez)},30100); // Desactivar la llamada periódica
|
V zgornjem primeru kode je metoda llamar()
predmetov Contexto
Ne opravi dela, ampak vrne anonimno funkcijo, ki poskrbi za to. Za preverjanje, ali vse deluje po pričakovanjih, obstaja globalna spremenljivka z enakim imenom kot lastnost, ki jo funkcija prikaže v konzoli; Če je kontekst pravilen, bo prikazana vrednost lastnosti in ne vrednosti globalne spremenljivke.
JavaScript Poskusite popraviti podpičja, ki jih izpuščamo na koncu povedi. To omogoča sproščen slog pisanja, vendar je dvorezen meč, s katerim je treba ravnati previdno. V večini primerov, da bi se izognili neželenim učinkom, ki jih to povzroči v izrazih, ki zasedajo več vrstic, lahko uporabite oklepaje ali pred način, kako JavaScript bo interpretiral kodo; Zato vrstica 8 primera vključuje function
zadaj return
, če bi uporabil drugo vrstico, bi bil pomen zelo drugačen. Po mojem mnenju je najbolj berljiva rešitev uporaba vmesne (pogrešljive) spremenljivke kot v naslednji različici; Očitno, ko je vedenje razumljeno, odločitev ustreza programerju.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
var Contexto=
{
prueba:“objeto”, // La propiedad prueba es de los objetos Contexto
llamar:
function()
{
esto=this;
var variable_auxiliar=
function()
{
console.log(“H + “+(Date.now()–hora)+” Contexto: “+esto.prueba);
};
return variable_auxiliar;
}
}
var prueba=“global”; // Esta variable prueba es global (window.prueba)
var hora=Date.now();
var probador=Object.create(Contexto);
var cosa=probador.llamar();
var pesadez=setInterval(cosa,3000);
setTimeout(function(){clearInterval(pesadez)},30100);
|
V enakem smislu kot vrednotenje izraza kot funkcije, to je vrnitev funkcije in ne vrednosti, ki jo funkcija vrne; v 21. vrstici zadnjega primera (bilo je v 19. vrstici prejšnjega) se ustavi z clearInterval
funkcija, imenovana z setInterval
. Da bi deloval 30 sekund, se ustavitev odloži z setTimeout
, ki nato potrebuje funkcijo kot prvi argument; da zagotovi izvedbo kot parameter clearInterval
s spremenljivko, ki vsebuje periodični klic (in ne funkcije clearInterval
) je tisto, za kar je ustvarjena anonimna funkcija v zadnji vrstici.
Izbira med pisanjem kode, ki vključuje definicijo funkcije, bolj kompaktno (kot v vrstici 21) ali uporabo pomožne spremenljivke, po mojem mnenju bolj berljivo (kot v vrstici 19 in 20), se malo razlikuje v zmogljivosti in je odvisna od več sloga in berljivosti za vzdrževanje.
Za testiranje kode, preden imate podatke na strežniku, lahko uporabite generator naključnih vrednosti v želenem obsegu ali pripravite tabele z nadzorovanimi vrednostmi, ki simulirajo delovanje pod želenimi pogoji. Naslednji primer uporablja preprost generator podatkov v celotnem obsegu, zato se zdijo nekoliko pretirani.
Če želite preizkusiti, lahko prenesite celotno kodo primera ki jo tvori spletna stran, napisana v HTML, slog CSS in kodo JavaScript. Slednje je najbolj relevantno, saj so druge komponente le minimalna podpora, zelo poenostavljene in veliko bolj razvite v člankih v ustreznih razdelkih.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<!DOCTYPE html>
<html lang=“es”>
<head>
<meta charset=“utf-8”>
<title>Temperatura</title>
<script type=“text/javascript” src=“https://polaridad.es/javascript-grafico-svg-sensor-internet-de-las-cosas-iot/grafico.js”></script>
<link rel=“stylesheet” href=“estilo.css” type=“text/css” media=“all”>
</head>
<body onload=“iniciar_grafico(‘grafico’,’valor’,’fecha’);”>
<div id=“temperatura”>
<div id=“ultimo_valor”>
<div id=“fecha”></div>
<div id=“valor”></div>
</div>
<div id=“grafico”></div>
</div>
</body>
</html>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
body
{
margin:0px 0px 0px 0px;
}
#ultimo_valor
{
box–sizing:border–box;
width:100%;
height:40px;
padding:8px 0px 8px 14px;
font–family:monospaced;
font–size:18px;
color:#205587;
background–color:#86A7D0;
}
#fecha
{
float:left;
margin–right:15px;
}
#valor
{
float:left;
}
#grafico
{
width:100%;
height:200px;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
|
var Grafico=
{
contenedor_svg:void(0), // Objeto SVG con el que se dibuja el gráfico. Se inicializa con void(0) para asegurarse de que es === undefined al principio
contenedor_html:void(0), // Objeto HTML que contiene al objeto SVG con el gráfico (seguramente un div). Se inicializa con void(0) para asegurarse de que es === undefined al principio
contenedor_valor:void(0), // Objeto HTML en el que se muestra el último valor cargado del servidor
contenedor_fecha:void(0), // Objeto HTML para mostrar la fecha del último valor
pagina_servidor:“ultimo_valor_sensor.php”, // página en la que se consultan los datos
consulta:“fr1”, // Valor del parámetro con el que se consulta el servidor. La URL sería algo como http://servidoriot.com/ultimo_valor_sensor.php?zona=fr1
NS:“http://www.w3.org/2000/svg”, // Nombre del espacio de nombres (name space NS)
MINIMO:0, // Índice del menor valor admisible en el gráfico SVG. Los valores menores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
OPTIMO:1, // Índice del mejor valor del parámetro medido. Valor deseado para el parámetro monitorizado. Sirve para tener una idea rápida de cómo de correcto es el estado del sistema
MAXIMO:2, // Índice del mayor valor admisible en el gráfico SVG. Los valores mayores se saldrán del gráfico salvo por un margen que permite tener una idea de la tendencia
maximo_puntos:0, // Número máximo de vértices representados (pueden dibujarse menos si se recortan por la parte izquierda)
valor:[], // Últimos valores cargados del servidor
trazado:[], // Trazados representados (en principio se trata de representar uno con relleno y otro con línea)
cerrado:true, // Cuando vale true se dibuja el perfil y el área (la línea del gráfico y una zona rellena debajo). Cuando vale false solo se dibuja la línea
simbolo:[], // Objetos SVG utilizados para marcar los vértices de la línea (círculos)
linea_referencia:[], // Líneas horizontales en los valores de referencia
texto_referencia:[], // Objetos texto que rotulan los valores de referencia
fondo_referencia:[], // Rectángulos bajo los textos de los valores de referencia
medida_caja_svg:[100.0,100.0], // Ancho,Ancho del objeto SVG (aunque al dibujarlo con el código HTML tomará otras dimensiones ya que se dimensiona al 100% de su contenedor
correccion_caja_svg:[1.0,1.0], // Coeficientes para calcular la medida en el gráfico de un objeto del que se sabe el valor absoluto (Se usa el píxel como unidad)
tiempo_representado:0, // Milisegundos visibles en el gráfico empezando en el valor mayor (fecha y hora del último valor monitorizado)
valor_referencia:[0,0,0], // Valores de referencia [mínimo,óptimo,máximo]
margen_valor:0, // Zona por encima del valor mayor y por debajo del valor menor que se representa para tener una idea aproximada de la tendencia cuando los datos monitorizados rebasen los valores máximo y/o mínimo
escala_valor:[1.0,1.0], // Coeficientes que multiplican el valor monitorizado (y almacenado en el servidor) para calcular el representado según las dimensiones del gráfico
desplazamiento_valor:[0.0,0.0], // Desplazamiento que se suma al tiempo (X) y al valor (Y) para representarlo en el rango especificado para el gráfico
area_bajo_linea:true, // True para dibujar una zona rellena además del perfil (línea) del gráfico
medida_simbolo:[5,5], // Valor absoluto (en píxeles) del ancho y el alto del dibujo que se hace en los vértices de la línea del gráfico
tipografia:“sans-serif”, // Tipo de letra usado para rotular el gráfico (se usa solamente una tipografía por uniformidad)
altura_texto:10.0, // Altura de los textos en valor absoluto (píxeles). No todos los navegadores soportan todos los valores intermedios, será necesario coordinarlo con los valores que estén relacionados
escala_horizontal_texto:1, // Transformación que se aplica al texto para corregir la que implica la proporción del gráfico
color_fondo:“”, // Color de fondo del contenedor HTML del objeto SVG (Si es una cadena vacía no se cambia)
color_simbolos:“#000000”, // Color de los símbolos que se dibujan en los vértices de la línea del gráfico
color_referencia:[“#000000”,“#000000”,“#000000”], // Color de la referencia que indica el valor [mínimo,óptimo,máximo]
color_tipografia:“#FFFFFF”, // Color del tipo de letra con que se rotulan las referencias
grosor_trazado:4, // Grosor de la línea del gráfico
color_trazado:“#000000”, // Color de la línea del gráfico
color_relleno:“#000000”, // Color del relleno del gráfico
opacidad_relleno:1.0, // Opacidad del relleno del gráfico
grosor_referencia:0.5, // Grosor de la línea que se dibuja como referencia en valor absoluto (píxeles)
opacidad_referencia:1.0, // Opacidad de la línea de referencia. Si se dibuja sobre el gráfico con cierta transparencia permite ver el dibujo bajo ella
relleno_fondo_referencia:7.0, // Margen entre el fondo de la referencia y el texto medido en valor absoluto (la línea empieza en el margen izquierdo y recorre todo el gráfico)
margen_fondo_referencia:10.0, // Separación de la referencia y el borde izquierdo del gráfico medido en valor absoluto (la línea empieza en el margen izquierdo y recorre todo el gráfico)
ancho_fondo_referencia:50.0, // Medida horizontal del rectángulo que hace de fondo al texto de la referencia medido en valor absoluto
texto_valor:[“temperatura: “,” °C”], // Prefijo y sufico con los que se rotula el valor monitorizado
texto_hora:[“hora “,“”], // Prefijo y sufijo con los que se rotula la hora (cuando solamente se rotula la hora)
texto_fecha:[“”,“”], // Prefijo y sufijo con los que se rotula la fecha (cuando solamente se rotula la fecha)
texto_fecha_hora:[“el “,” a las “,” | “], // Prefijo con el que se rotula la hora, separador de fecha y hora y sufjo de la hora cuando se rotula la fecha y la hora
HORA:0, // Constante que representa la hora para el modo de la fecha/hora
FECHA:1, // Constante que representa la fehca para el modo de la fecha/hora
FECHA_Y_HORA:2, // Constante que representa rotular la fecha y la hora (para el modo de fecha/hora)
modo_fecha:2, // 0->hora, 1-> fecha 2-> fecha y hora
repetir:null, // Función llamada por setInterval
nueva_proporcion: // Calcular la nueva proporción (al iniciar y al redimensionar el contenedor del gráfico) para transformar el texto
function()
{
if(this.contenedor_svg!==undefined) // Se entiende que si no es undefined se ha asignado un objeto
{
if(this.contenedor_svg.nodeName===“svg”) // Si el objeto asignado es un SVG
{
this.escala_horizontal_texto=parseFloat(getComputedStyle(this.contenedor_svg).height)/parseFloat(getComputedStyle(this.contenedor_svg).width); // La escala debe calcularse cada vez ya que no se sabe si se ha redimensionado el objeto HTML que contiene al objeto SVG y que le da el tamaño
}
}
},
nueva_correccion_caja_svg:
function()
{
if(this.contenedor_svg!==undefined) // Se entiende que si no es undefined se ha asignado un objeto
{
if(this.contenedor_svg.nodeName.toLowerCase()===“svg”) // Si el objeto asignado es un SVG
{
this.correccion_caja_svg[0]=this.medida_caja_svg[0]/parseFloat(getComputedStyle(this.contenedor_svg).width);
this.correccion_caja_svg[1]=this.medida_caja_svg[1]/parseFloat(getComputedStyle(this.contenedor_svg).height);
}
}
},
nueva_escala:
function()
{
if(this.tiempo_representado>0) // Antes de inicializar el objeto el tiempo representado es cero
{
this.escala_valor[0]=this.medida_caja_svg[0]/this.tiempo_representado; // Coeficiente que multiplica a los valores horizontales (tiempo) para calcular las coordenadas X
this.escala_valor[1]=this.medida_caja_svg[1]/(Math.abs(this.valor_referencia[this.MAXIMO]–this.valor_referencia[this.MINIMO])+this.margen_valor*2); // Coeficiente que multiplica a los valores (vertical) para calcular las coordenadas Y
}
},
nuevo_desplazamiento:
function()
{
if(this.tiempo_representado>0) // Antes de inicializar el objeto el tiempo representado es cero
{
this.desplazamiento_valor[0]=this.valor[this.valor.length–1][0]–this.tiempo_representado; // Valor desde el que se empieza a contar el tiempo: el valor mayor (último) menos el rango de tiempo representado
this.desplazamiento_valor[1]=this.margen_valor–this.valor_referencia[this.MINIMO]; // Valor menor mostrado (al menor se le añade un margen para visualizar el principio de los valores fuera del rango permitido)
}
},
crear_svg: // Crear el objeto SVG dentro del objeto HTML
function()
{
if(this.contenedor_html!==null&&this.contenedor_html!==undefined) // Ya se ha asignado el objeto HTML
{
if(this.contenedor_html.nodeType===1) // Es un objeto HTML válido
{
// Color de fondo del objeto HTML
if(this.color_fondo!==“”)
{
this.contenedor_html.style.backgroundColor=this.color_fondo;
}
// Contenedor SVG
this.contenedor_svg=document.createElementNS(this.NS,“svg”); // Crear un objeto SVG
this.contenedor_svg.setAttribute(“width”,“100%”); // Ancho del objeto SVG
this.contenedor_svg.setAttribute(“height”,“100%”); // Alto del objeto SVG
this.contenedor_svg.setAttribute(“viewBox”,“0 0 “+this.medida_caja_svg[0]+” “+this.medida_caja_svg[1]); // Zona del SVG que se muestra
this.contenedor_svg.setAttribute(“preserveAspectRatio”,“none”); // No preservar la proporción para ocupar todo el objeto HTML que hace de contenedor
this.contenedor_html.appendChild(this.contenedor_svg); // Añadir al contenedor HTML el objeto SVG (que será el contenedor del gráfico)
// Trazado
this.trazado[0]=document.createElementNS(this.NS,“path”); // Crear el trazado que soporta el relleno
this.trazado[0].style.fill=this.color_relleno;
this.trazado[0].style.fillOpacity=this.opacidad_relleno;
this.trazado[0].style.stroke=“none”;
this.contenedor_svg.appendChild(this.trazado[0]); // Añadir el relleno al SVG
this.trazado[1]=document.createElementNS(this.NS,“path”); // Crear el trazado que soporta el perfil
this.trazado[1].setAttribute(“vector-effect”,“non-scaling-stroke”); // No mantener la proporción en el trazado (no deformarlo)
this.trazado[1].style.fill=“none”;
this.trazado[1].style.stroke=this.color_trazado;
this.trazado[1].style.strokeWidth=this.grosor_trazado;
//this.trazado[1].style.strokeOpacity=1.0; // La opacidad por defecto es 1.0
this.contenedor_svg.appendChild(this.trazado[1]); // Añadir el perfil al SVG
// Símbolos para los vértices
var ahora=Date.now()–30000; // Fecha y hora actual menos 30 segundos
for(var contador_vertices=0;contador_vertices<this.maximo_puntos;contador_vertices++)
{
this.valor[contador_vertices]=[];
this.valor[contador_vertices][0]=ahora; // Inicializar los valores a la fecha y hora actual menos 30 segundos
this.valor[contador_vertices][1]=this.valor_referencia[this.OPTIMO]; // Inicializar los valores al óptimo
this.simbolo[contador_vertices]=document.createElementNS(this.NS,“ellipse”); // Crear una elipse (círculo) para cada vértice
this.simbolo[contador_vertices].style.fill=this.color_simbolos;
this.simbolo[contador_vertices].style.fillOpacity=1.0;
this.simbolo[contador_vertices].style.stroke=“none”;
this.contenedor_svg.appendChild(this.simbolo[contador_vertices]); // Añadir el símbolo al SVG
}
//this.nuevo_desplazamiento(); // Necesario si se asignaran las alturas de las referencias
for(var contador_referencia=0;contador_referencia<this.valor_referencia.length;contador_referencia++)
{
// Línea de referencia
//var posicion_corregida=this.medida_caja_svg[1]-(this.valor_referencia[contador_referencia]+this.desplazamiento_valor[1])*this.escala_valor[1]; // Necesario si se asignaran las alturas de las referencias
this.linea_referencia[contador_referencia]=document.createElementNS(this.NS,“line”); // Crear la línea que representa el valor mínimo
this.linea_referencia[contador_referencia].style.stroke=this.color_referencia[contador_referencia];
this.linea_referencia[contador_referencia].style.strokeWidth=this.grosor_referencia;
this.linea_referencia[contador_referencia].style.strokeOpacity=this.opacidad_referencia;
this.linea_referencia[contador_referencia].setAttribute(“x1”,0.0); // Las líneas de referencia empiezan en el borde izquierdo…
this.linea_referencia[contador_referencia].setAttribute(“x2”,this.medida_caja_svg[0]); // …y terminan en el derecho
//this.linea_referencia[contador_referencia].setAttribute(“y1”,posicion_corregida); // Ambos extremos a la altura correspondiente a la referencia [mínimo,óptimo,máximo]
//this.linea_referencia[contador_referencia].setAttribute(“y2”,posicion_corregida); // Ambos extremos a la altura correspondiente a la referencia [mínimo,óptimo,máximo]
this.contenedor_svg.appendChild(this.linea_referencia[contador_referencia]);
// Rectángulo de fondo del texto que indica el valor de referencia
this.fondo_referencia[contador_referencia]=document.createElementNS(this.NS,‘rect’);
this.fondo_referencia[contador_referencia].style.fill=this.color_referencia[contador_referencia];
this.fondo_referencia[contador_referencia].style.fillOpacity=1.0;
this.fondo_referencia[contador_referencia].style.stroke=“none”;
this.contenedor_svg.appendChild(this.fondo_referencia[contador_referencia]);
// Texto de referencia
this.texto_referencia[contador_referencia]=document.createElementNS(this.NS,“text”); // Crear el texto para rotular la referencia
this.texto_referencia[contador_referencia].setAttribute(“font-family”,this.tipografia); // Asignar el tipo de letra
this.texto_referencia[contador_referencia].setAttribute(“fill”,this.color_tipografia); // Asignar el color
//this.texto_referencia[contador_referencia].textContent=””+(this.valor_referencia[contador_referencia]>=0?”+”:””)+this.valor_referencia[contador_referencia]; // Texto que se rotula (los valores máximo, óptimo y mínimo ya deben estar asignados)
this.contenedor_svg.appendChild(this.texto_referencia[contador_referencia]);
}
}
}
},
ajustar_prporcion:
function()
{
this.nueva_proporcion();
this.nueva_correccion_caja_svg();
var posicion_corregida;
for(var contador_vertices=0;contador_vertices<this.simbolo.length;contador_vertices++)
{
this.simbolo[contador_vertices].setAttribute(“rx”,this.medida_simbolo[0]*this.correccion_caja_svg[0]);
this.simbolo[contador_vertices].setAttribute(“ry”,this.medida_simbolo[1]*this.correccion_caja_svg[1]);
}
for(var contador_referencia=0;contador_referencia<this.valor_referencia.length;contador_referencia++)
{
posicion_corregida=this.medida_caja_svg[1]–(this.valor_referencia[contador_referencia]+this.desplazamiento_valor[1])*this.escala_valor[1];
this.fondo_referencia[contador_referencia].setAttribute(“x”,this.margen_fondo_referencia*this.correccion_caja_svg[0]);
this.fondo_referencia[contador_referencia].setAttribute(“y”,posicion_corregida–(this.altura_texto+this.relleno_fondo_referencia*2.0)*this.correccion_caja_svg[1]/2.0);
this.fondo_referencia[contador_referencia].setAttribute(“width”,this.ancho_fondo_referencia*this.correccion_caja_svg[0]);
this.fondo_referencia[contador_referencia].setAttribute(“height”,(this.altura_texto+this.relleno_fondo_referencia*2.0)*this.correccion_caja_svg[1]);
this.linea_referencia[contador_referencia].setAttribute(“y1”,posicion_corregida);
this.linea_referencia[contador_referencia].setAttribute(“y2”,posicion_corregida);
this.texto_referencia[contador_referencia].setAttribute(“transform”,“scale(“+this.escala_horizontal_texto+“,1.0)”);
this.texto_referencia[contador_referencia].setAttribute(“font-size”,this.altura_texto*this.correccion_caja_svg[1]);
this.texto_referencia[contador_referencia].setAttribute(“x”,(this.margen_fondo_referencia+this.relleno_fondo_referencia)*this.correccion_caja_svg[0]/this.escala_horizontal_texto);
this.texto_referencia[contador_referencia].setAttribute(“y”,posicion_corregida+this.altura_texto/2.0*this.correccion_caja_svg[1]);
this.texto_referencia[contador_referencia].textContent=(this.valor_referencia[contador_referencia]>=0?“+”:“”)+this.valor_referencia[contador_referencia]; // Texto que se rotula
}
},
rotar_valores:
function()
{
for(var contador_valor=0;contador_valor<this.valor.length–1;contador_valor++)
{
this.valor[contador_valor][0]=this.valor[contador_valor+1][0];
this.valor[contador_valor][1]=this.valor[contador_valor+1][1];
}
},
nuevo_valor_aleatorio:
function()
{
this.rotar_valores();
this.valor[this.valor.length–1][0]=this.valor[this.valor.length–2][0]+1000+Math.random()*1000; // El nuevo tiempo es el anterior más un segundo más un valor entre 0 y un segundo
this.valor[this.valor.length–1][1]=Math.random()*Math.abs(this.valor_referencia[this.MAXIMO]–this.valor_referencia[this.MINIMO])+this.valor_referencia[this.MINIMO]; // Un valor aleatorio entre el máximo y el mínimo
this.nuevo_desplazamiento(); // Cada nuevo valor cambia el desplazamiento en horizontal
this.dibujar_nuevo_valor(true);
this.dibujar_nuevo_valor(false);
this.rotular_nuevo_valor();
this.ritular_nueva_fecha();
},
cargar_nuevo_valor:
function()
{
var consulta=‘zona=”+this.consulta;
var resultado;
var ajax;
if(window.XMLHttpRequest)
{
ajax=new XMLHttpRequest(); // ajax=Object.create(XMLHttpRequest);
}
else // Versiones antiguas de MS Internet Explorer
{
ajax=new ActiveXObject(“Microsoft.XMLHTTP”);
}
ajax.onreadystatechange=
function()
{
if(ajax.readyState==4&&ajax.status==200&&ajax.responseType==“json”)
{
resultado=JSON.parse(ajax.responseText);
if(resultado.fecha>objeto_grafico.fecha[objeto_grafico.fecha.length–1])
{
this.rotar_valores();
this.valor[this.valor.length–1][0]=resultado.fecha;
this.valor[this.valor.length–1][1]=resultado.temperatura;
this.nuevo_desplazamiento(); // Cada nuevo valor cambia el desplazamiento en horizontal
this.dibujar_nuevo_valor(true);
this.dibujar_nuevo_valor(false);
this.rotular_nuevo_valor();
this.ritular_nueva_fecha();
}
}
}
ajax.open(“POST”,this.pagina_servidor);
ajax.setRequestHeader(“Method”,“POST “+this.pagina_servidor+” HTTP/1.1″);
ajax.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);
ajax.setRequestHeader(“Content-length”,consulta.length);
ajax.setRequestHeader(“Connection”,“close”);
ajax.send(consulta);
},
rotular_nuevo_valor:
function()
{
var valor_redondeado=Math.round(this.valor[this.valor.length–1][1]*100.0)/100.0;
this.contenedor_valor.innerHTML=this.texto_valor[0]+valor_redondeado+this.texto_valor[1];
},
ritular_nueva_fecha:
function()
{
var fecha_lectura=new Date(this.valor[this.valor.length–1][0]);
var texto_fecha=this.texto_hora[0];
texto_fecha+=(fecha_lectura.getHours()<10?“0”:“”)+fecha_lectura.getHours();
texto_fecha+=“:”;
texto_fecha+=(fecha_lectura.getMinutes()<10?“0”:“”)+fecha_lectura.getMinutes();
texto_fecha+=“:”;
texto_fecha+=(fecha_lectura.getSeconds()<10?“0”:“”)+fecha_lectura.getSeconds();
texto_fecha+=this.texto_hora[1];
this.contenedor_fecha.innerHTML=texto_fecha;
},
dibujar_nuevo_valor: // Dibujar el gráfico cuando llega un nuevo valor (que estará almacenado en el vector valor
function(cerrado)
{
// Si cerrado es undefined se evalúa a false, que se toma como valor por defecto
var contador_valor=this.valor.length–1; // Variable para recorrer los valores (índice)
var sin_recortar=true; // False si la gráfico se sale de la caja (si se sale, si recorta, se hace false para no seguir dibujando puntos)
var posicion=[]; // Variable intermedia (para hacer más legible el código) con la que calcular la posición horizontal y vertical de un punto del trazado
var coordenadas_trazado=“M “; // Cadena de texto que representa la propiedad “d” del trazado SVG
if(cerrado) // Si el trazado que se está dibujando está cerrado (no confundir con this.cerrado que determina si se dibujan los dos trazados, la línea y el relleno)
{
coordenadas_trazado+=this.medida_caja_svg[0]+“,”+this.medida_caja_svg[1]+” L “; // …se empieza por la parte inferior de la caja
}
while(contador_valor>=0&&sin_recortar) // Mientras queden valores por representar y no se haya llegado al borde izquierdo del gráfico…
{
posicion[0]=(this.valor[contador_valor][0]–this.desplazamiento_valor[0])*this.escala_valor[0]; // Calcular la X restando al tiempo el desplazamiento y convirtiéndolo a la escala del gráfico con el coeficiente horizontal
posicion[1]=this.medida_caja_svg[1]–(this.valor[contador_valor][1]+this.desplazamiento_valor[1])*this.escala_valor[1]; // Calcular la Y restando del alto de la caja (la Y crece hacia abajo en SVG)
this.simbolo[contador_valor].setAttribute(“cx”,posicion[0]);
this.simbolo[contador_valor].setAttribute(“cy”,posicion[1]);
coordenadas_trazado+=posicion[0]+“,”+posicion[1]; // Formar la coordenada con la X y la Y
if(posicion[0]>0) // Si no se ha rebasado el margen izquierdo…
{
coordenadas_trazado+=contador_valor>0?” L “:“”; // …y quedan valores que representar, añadir una nueva línea (código L) para el próximo
contador_valor—; // Pasar al siguiente valor
}
else // Si se ha rebasado el margen izquierdo…
{
sin_recortar=false; // …abandonar el modo sin recorte (lo que terminará de calcular coordenadas)
}
}
if(cerrado) // Si se dibuja un trazado (path) cerrado…
{
coordenadas_trazado+=” L “+posicion[0]+“,”+this.medida_caja_svg[1]+” Z”; // …se termina por la parte inferior de la caja y se añade Z para cerrarlo en SVG
}
this.trazado[cerrado?0:1].setAttribute(“d”,coordenadas_trazado); // Cambiar las coordenadas del trazado (propiedad “d”) por las que se han calculado
for(;contador_valor>=0;contador_valor—)
{
this.simbolo[contador_valor].setAttribute(“cx”,–10000);
this.simbolo[contador_valor].setAttribute(“cy”,0);
}
}
}
var temperatura_frigorifico;
function iniciar_grafico(nombre_objeto_grafico,nombre_objeto_valor,nombre_objeto_fecha)
{
temperatura_frigorifico=Object.create(Grafico);
temperatura_frigorifico.contenedor_html=document.getElementById(nombre_objeto_grafico);
temperatura_frigorifico.contenedor_valor=document.getElementById(nombre_objeto_valor);
temperatura_frigorifico.contenedor_fecha=document.getElementById(nombre_objeto_fecha);
temperatura_frigorifico.color_fondo=“#A8C3EA”;
temperatura_frigorifico.color_trazado=“#205587”;
temperatura_frigorifico.grosor_trazado=3;
temperatura_frigorifico.color_relleno=“#205587”;
temperatura_frigorifico.opacidad_relleno=0.5;
temperatura_frigorifico.color_simbolos=“#205587”;
temperatura_frigorifico.color_referencia[Grafico.MINIMO]=“#621D87”;
temperatura_frigorifico.color_referencia[Grafico.OPTIMO]=“#1D8762”;
temperatura_frigorifico.color_referencia[Grafico.MAXIMO]=“#871E35”;
temperatura_frigorifico.grosor_referencia=1.5;
temperatura_frigorifico.opacidad_referencia=0.5;
temperatura_frigorifico.tipografia=“monospaced”;
temperatura_frigorifico.color_tipografia=“#A8C3EA”;
temperatura_frigorifico.cerrado=true; // Dibujar una línea y una zona rellena debajo (true por defecto)
temperatura_frigorifico.maximo_puntos=32; // Un espacio de 30 segundos representados con un intervalo mínimo de 1 segundo necesitan como máximo 31 puntos, se añade uno por seguridad (por si algún valor monitorizado estuviera por debajo del segundo)
temperatura_frigorifico.crear_svg();
temperatura_frigorifico.nueva_correccion_caja_svg();
temperatura_frigorifico.tiempo_representado=30000;
temperatura_frigorifico.valor_referencia[Grafico.MINIMO]=–5;
temperatura_frigorifico.valor_referencia[Grafico.OPTIMO]=5;
temperatura_frigorifico.valor_referencia[Grafico.MAXIMO]=10;
temperatura_frigorifico.margen_valor=3;
temperatura_frigorifico.nueva_escala();
temperatura_frigorifico.nuevo_desplazamiento(); // El desplazamiento se (re)calcula cada vez que se añade un valor
temperatura_frigorifico.ajustar_prporcion();
window.addEventListener(“resize”,function(){temperatura_frigorifico.ajustar_prporcion()}); // Versión moderna
temperatura_frigorifico.repetir=setInterval(function(){temperatura_frigorifico.nuevo_valor_aleatorio()},1000);
}
|
po Komentar