Generuj i modyfikuj grafikę SVG danych z czujników podłączonych do IoT za pomocą JavaScript
W tej ostatniej części cyklu artykułów o rysunku grafika z danymi z czujników podłączonych do Internetu Rzeczy, czas porozmawiać o tym, jak generować lub modyfikować za pomocą JAVASCRIPT rysunki w formacie SVG i niektóre elementy HTML które służą jako pojemnik lub prezentują informacje uzupełniające grafikę.
Docelowi użytkownicy tego samouczka powinni stworzyć profil elektroniki i programowania komputerowego. mikrokontrolery, mogą nie być zaznajomieni HTML, CSS o SVG; Z tego powodu w poprzednich odsłonach dokonano krótkiego wprowadzenia do języka lub odpowiadającej mu technologii. W tej ostatniej części podejście jest nieco inne, ponieważ czytelnicy z pewnością wiedzą, jak programować, możliwe jest, że użyją tego języka C + + co, jak JAVASCRIPT, ma taką samą podstawową składnię jak C i można go wykorzystać jako odniesienie, aby pominąć większość podstawowych koncepcji programowania i w ten sposób skupić się na różnicach i konkretnym zastosowaniu, które nas interesuje przy tworzeniu grafiki czujników w IoT.
Nazwa daje wskazówkę co do pierwszej różnicy: JAVASCRIPT Jest to język programowania scenariusz (łącznik) i jako taki, tak jest interpretowane, nie ma potrzeby go kompilować; kontekst, w którym scenariusz (np. przeglądarka internetowa) odczyta, przetłumaczy i zrealizuje zamówienia. Mówiąc ściślej, w większości przypadków istnieje kompilacja środowiska uruchomieniowego (JIT), ale dla procesu pisania kodu JAVASCRIPT Nas to nie dotyczy, po prostu piszemy kod i może działać.
W nazwie kryje się także pierwsze zamieszanie: JAVASCRIPT nie ma najmniejszego związku z Java. Początkowo, kiedy został opracowany Netscape w swojej przeglądarce nazywał się najpierw Mocha, a następnie mniej zagmatwany LiveScript. Po pomyślnym wdrożeniu w przeglądarkach i przekroczeniu ich, został ustandaryzowany jako ECMAScript (Na ECMA-262, wersja 6 w momencie pisania tego tekstu), aby stać się neutralnym w stosunku do przeglądarek, które je implementują. Obecnie istnieje również standard ISO od wersji 5, 2011 (ISO / IEC 16262: 2011 w momencie pisania artykułu)
Zmienne, podstawowe typy danych i obiekty w JavaScript
W odróżnieniu od tego, co dzieje się np C + +, en JAVASCRIPT typ danych nie jest uwzględniany podczas deklarowania zmiennej a także typ powiązany ze zmienną nie jest ustalony, możliwe jest przypisanie wartości innego typu w trakcie wykonywania programu.
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
|
W poprzednim przykładzie zadeklarowana została zmienna „thing” (bez wskazania typu danych), następnie przypisane są dane innego typu i są one konsultowane z typeof
typ, który JAVASCRIPT który zinterpretował. Aby zdebugować kod, możesz napisać go w konsoli inspektora przeglądarki internetowej (co nie będzie miało wpływu na prezentację sieci) za pomocą console.log()
.
Aby wymusić konwersję danych na określony typ, szczególnie tekstowy na numeryczny, można skorzystać z funkcji takich jak parseInt()
o parseFloat()
które konwertują odpowiednio na liczby całkowite lub zmiennoprzecinkowe. Można dokonać odwrotnej konwersji String()
, chociaż jest mało prawdopodobne, aby było to konieczne, ponieważ zwykle wystarcza automatyczna konwersja. Z parseFloat()
Na przykład można uzyskać wartość właściwości strony internetowej, taką jak szerokość lub wysokość obiektu, zawierającą jednostki; W ten sposób wyrażenie parseFloat("50px");
w rezultacie zwróci 50, czyli wartość liczbową.
En JAVASCRIPT nie ma rozróżnienia między cudzysłowami podwójnymi i pojedynczymi; Typ danych w obu przypadkach to string
, a każdy z nich może zawierać drugi bez potrzeby stosowania kodów ucieczki.
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
|
W poprzednim przykładzie widać, że zmienna, gdy została zadeklarowana (istnieje), ale nie ma przypisanej żadnej wartości, zawiera niezdefiniowany typ danych (undefined
). Nieprzypisany obiekt ma wartość null
; Oznacza to, że przedmiot istnieje, ale bez wartości; zmienna, która się do niej odwołuje, nie miałaby a typeof
undefined
ale object
. Obiekt może być również pusty, to znaczy nie mieć wartości null, ale nie może mieć żadnych właściwości.
do zdefiniować obiekt w JAVASCRIPT są ujęte w nawiasy klamrowe ({
y }
) właściwości lub metody oddzielone dwukropkiem (:
) nazwa właściwości wartość właściwości i przecinek (,
) różne właściwości. Więcej informacji na temat tego sposobu wyrażania przedmiotu znajdziesz w artykule na temat Format JSON.
Chociaż możesz użyć składni, która może skłonić Cię do innego myślenia, en JAVASCRIPT Nie ma klas, są tylko prototypyOznacza to, że aby obiekt mógł dziedziczyć właściwości i metody, tworzony jest inny obiekt (prototyp), którego inne obiekty (dzieci) używają jako odniesienia. Składnia najbliższa stylowi JAVASCRIPT użycie prototypu jest Object.create
chociaż jest to również możliwe (i czasami przydatne) w użyciu new
jak w innych językach obiektowych.
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));
|
do zapytanie, czy jeden obiekt jest instancją innego, jeśli użyjesz go jako prototypu, jeśli odziedziczysz jego właściwości, krótko mówiąc, możesz użyć instanceof
(utworzony z new
) Lub isPrototypeOf
(utworzony z Object.create
), która będzie miała wartość true, gdy obiekt użyje prototypu, i false, jeśli tego nie zrobi.
Po utworzeniu obiektu przy użyciu innego obiektu jako prototypu, to znaczy po utworzeniu instancji obiektu, można go dodać nowe właściwości lub zastąpić właściwości prototypu używając składni kropki jak w gato.peso=2.5
.
La tablice w JAVASCRIPT Różnią się od tych, które zapewne znasz C. Na początek deklaruje się je bez konieczności podawania ich długości, jedynie ze znakami otwierania i zamykania nawiasów kwadratowych ([
y ]
), komponenty mogą być heterogeniczne (różne typy danych w tej samej tablicy), a nowe elementy można dodawać bez ograniczeń. Macierze JAVASCRIPT są w rzeczywistości listami (zbiórami) elementów, do których odwołuje się do indeksu liczbowego lub nazwy. Tablica może jednocześnie zawierać indeksy numeryczne i nazwy elementów, ale często używa się obiektów (właściwości) do wykorzystania drugiego typu.
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
|
Jak widać w poprzednim przykładzie, aby dowiedzieć się, czy zmienna odpowiada instancji tablicy (jest to obiekt tablicowy), można użyć instanceof
, jak to było już używane w przypadku obiektów ogólnych lub, w nowszych wersjach JAVASCRIPT możesz się powołać Array.isArray()
Aby uzyskać dostęp do elementów tablicy, możesz użyć jej indeksu (matriz[7]
) lub po nazwie nieruchomości z nazwą w nawiasie kwadratowym (matriz["nombre"]
) lub ze zwykłą składnią kropkową dla obiektów (matriz.nombre
). Ponieważ nazwa jest ciągiem tekstowym, do jej utworzenia można użyć wyrażenia zawierającego zmienne. Aby przejść przez tablicę z właściwościami, można użyć pętli z formatem 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
*/
|
Leczenie jest interesujące z punktu widzenia naszego celu obiekt Date
, za pomocą którego można reprezentować datę i godzinę oraz zarządzać nią w JAVASCRIPT. Obiekt można utworzyć bez danych, więc będzie przyjmować bieżącą datę i godzinę, lub można go utworzyć poprzez wskazanie daty jako wartości w milisekundach od 1 stycznia 1970 r. (np. Czas uniksowy lub czas POSIX ale wyrażone w milisekundach zamiast w sekundach) lub podając osobne wartości roku, miesiąca, dnia, godziny...
Obiekt obejmuje kompletną serię metody wysyłania zapytań lub ustawiania daty i godziny:
-
now()
Zwraca bieżącą datę i godzinę wyrażoną w milisekundach od 1 stycznia 1970 r -
getTime()
|setTime()
Pobiera lub zmienia odpowiednio wartość czasu w milisekundach od 1 stycznia 1970 r. UżywanievalueOf()
, czyli metoda występująca w większości obiektów, uzyskiwana jest także wartość odpowiedniego obiektu Date, npgetTime()
z Czas uniksowy lub czas POSIX wyrażone w ms. -
getMilliseconds()
|setMilliseconds()
Służy do wysyłania zapytań lub ustawiania ułamkowej milisekundowej części obiektuDate
na którym jest wykonywany. Po konsultacji uzyskana wartość mieści się w przedziale od 0 do 999, ale można przypisać większe wartości, które będą kumulować się w całkowitej dacie i godzinie, więc podobnie jak pozostałe metody get służy to zwiększeniu wartości obiektuDate
(lub zmniejsz ją, jeśli używane są wartości ujemne). -
getSeconds()
|setSeconds()
Odpowiednio zwraca lub zmienia wartość sekund obiektuDate
. -
getMinutes()
|setMinutes()
Służy do sprawdzania lub ustawiania minut obiektuDate
. -
getHours()
|setHours()
Umożliwia sprawdzenie lub modyfikację godzin (od 0 do 23) obiektuDate
. -
getDay()
Zwraca dzień tygodnia dla daty wyrażonej jako wartość od 0 do 6 (od niedzieli do soboty). -
getDate()
|setDate()
Zwraca lub zmienia dzień miesiąca obiektuDate
na którym jest stosowany. -
getMonth()
|setMonth()
Służy do sprawdzania lub modyfikowania numeru miesiąca obiektuDate
. -
getFullYear()
|setFullYear()
Wysyła zapytanie o wartość roku lub ustawia ją w obiekcie zawierającym datę i godzinę.
Poprzednie metody Date
zawierać wersję UTC aby móc bezpośrednio pracować z czasem uniwersalnym, bez konieczności wykonywania obliczeń pośrednich. W tym sensie np. getHours()
ma wersję getUTCHours()
o getMilliseconds()
alternatywa getUTCMilliseconds()
pracować na zmianę z czasem urzędowym (prawnym) lub powszechnym. Z getTimezoneOffset()
Możesz poznać różnicę między czasem uniwersalnym a lokalnym czasem urzędowym.
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;
|
Funkcje JavaScriptu
Jeśli to czytasz, na pewno wiesz, jak programować. mikrokontrolery en C lub C + + i znać pojęcie funkcji. Chociaż podstawowa idea jest taka sama, w JAVASCRIPT Sposób ich definiowania i używania jest nieco inny. Na początek powiedziano już, że JAVASCRIPT Nie używa jawnie typów danych, więc nie trzeba tego wskazywać przy definiowaniu funkcji. Podążać, Funkcja nie musi mieć nazwy, może być anonimowa. Można je powiązać ze zmienną w celu ich wywołania, ale może też nie być konieczne, gdyż czasem warto wywołać je od razu, dla czego nawiasy i parametry dodawane są po definicji funkcji.
Aby zdefiniować funkcję, przedrostek function
, jeśli ma to zastosowanie, wpisz nazwę, argumenty (parametry przekazywane do funkcji) w nawiasach, a w nawiasach klamrowych kod, który zostanie wykonany po wywołaniu funkcji.
1
2
3
4
5
|
function doble(numero)
{
var resultado=numero*2;
return resultado;
}
|
Oczywiście w poprzednim przykładzie zmienna „result” nie była w ogóle potrzebna, ale jest to dobry pretekst, aby o tym pamiętać zakres zmienny, który działa zgodnie z oczekiwaniami: zmienna „result” istnieje tylko w funkcji „double”. W JAVASCRIPT można również użyć let
, zamiast var
, aby określić zakres zmiennej w kontekście bloku kodu (ujętego w nawiasy klamrowe, {
y }
)
Mówiąc o obiektach w poprzedniej sekcji, zabrakło czegoś podstawowego: zdefiniowano właściwości, ale nie zdefiniowano metod. Zgodnie z oczekiwaniami, metody obiektowe są funkcjami, nie mają nazwy i są używane (wywoływane) na podstawie nazwy (właściwości) przypisanej przez definicję obiektu.
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”);
}
}
|
W poprzednim przykładzie istnieje już metoda „view_temperature”, która wyświetla w konsoli wartość właściwości „current_temperature”. Nie jest to zbyt przydatne, ale daje pełniejszy obraz tego, jak wygląda definicja obiektu JAVASCRIPT.
Aby uzyskać dostęp do metod obiektu (funkcji) i jego właściwości, użyj this
, jak w poprzednim przykładzie w linii 11, gdy używana jest właściwość „current_temperature”.
Uzyskaj dostęp do modelu obiektowego dokumentu (DOM) za pomocą JavaScript
z JAVASCRIPT Masz dostęp do zawartości strony internetowej, na której ona działa, a także do niektórych aspektów przeglądarki, która wyświetla tę stronę, ale nie do zasobów systemowych. Struktura danych obsługująca właściwości i metody, z których można uzyskać dostęp JAVASCRIPT część obiektu okna, w szczególności zawartość obiektu (dokument HTML) odpowiada obiektowi document
. Chociaż czasami używa się go dla przejrzystości, nie jest konieczne poprzedzanie okna do metod lub właściwości, aby się do nich odwołać, wystarczy np. użyć document
, nie ma potrzeby wpisywania nazwy obiektu głównego jak w window.document
, o ile odwołuje się do bieżącego okna.
Najczęściej używana forma znaleźć obiekt w dokumencie HTML To poprzez metodę getElementById()
, do którego jako argument przekazywany jest identyfikator wskazany podczas tworzenia kodu HTML. Z tego, co wyjaśniono w poprzednich sekcjach, łatwo założyć, że dostęp do komponentów wewnątrz obiektu jest również możliwy document
używając składni kropki (document.componente
) lub nawiasy, używając zarówno nazwy (document["componente"]
), najbardziej przydatne, jak indeks liczbowy, trudne w użyciu i niepraktyczne przy dostępie do treści ręcznie utworzonej strony internetowej.
z JAVASCRIPT możesz pobierz element zawierający inny element (element lub węzeł nadrzędny) konsultacja z Twoją nieruchomością parentNode
lub Twoją własność parentElement
różnica polega na tym, że element nadrzędny (parentElement
) ostatniego elementu ciągu DOM Jest zerowy (null
) i węzeł nadrzędny (parentNode
) to sam dokument (document
).
do modyfikować zawartość elementu HTML, na przykład etykieta <div>
, To może być użyte innerHTML
i aby zmienić jego właściwości, możesz przypisać mu inną klasę className
lub zmieniać jego właściwości indywidualnie za pomocą style
. Sprawdzanie stylu wyświetlanego przez element na stronie internetowej niekoniecznie jest przydatne style
ponieważ może to zależeć od kilku czynników lub po prostu nie zostało wyraźnie określone. Aby sprawdzić styl elementu ostatecznie wyświetlonego na stronie internetowej, wykorzystywana jest metoda getComputedStyle.
Do elementu dokumentu HTML Można mu przypisać kilka klas, aby określić jego wygląd i zachowanie zarządzaj listą klas obiektu z JAVASCRIPT możesz się powołać classList
który oferuje metody add
aby dodać nową klasę do listy, remove
aby go usunąć, toggle
aby go zastąpić lub sprawdzić zawartość listy klas elementu item
i contains
, która zwraca klasę zajmującą określoną pozycję na liście oraz wartość true
o false
czy dana klasa znajduje się na liście.
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”)
}
|
W poprzednim przykładzie znajduje się on w getElementById
obiekt, którym chcesz manipulować (element <div>
dla jego id
), przed zmianą wyglądu treść zostaje usunięta poprzez przypisanie za pomocą innerHTML
pusty ciąg tekstowy, z którym zostaje przypisana nowa klasa className
i jego styl jest modyfikowany za pomocą style
w zależności od wartości zawartości (temperatury), ewentualnie zmieniając kolor poprzez właściwość color
. Po ustaleniu aspektu wartość jest zapisywana ponownie za pomocą innerHTML
.
W drugiej części powyższego przykładu (linie od 9 do 19) uzyskiwany jest dostęp do elementu kodu HTML używając składni document[]
i własności id
elementu, aby zmienić jego listę klas za pomocą metody classList.remove()
i z metodąclassList.add()
, na podstawie wyników kilku zapytań wykonywanych w wykonaniach warunkowych, za pomocą których porównują classList.contains()
.
Kiedy to się stanie odnosić się do elementu HTML varias razy w całym kodzie JAVASCRIPT, To trochę bardziej efektywne jest przypisanie go do zmiennej lub użyj jego indeksu zamiast nazwy, ponieważ w przeciwnym razie użyłbyś metody JAVASCRIPT uzyskanie go za każdym razem wymagałoby wyszukiwania jego nazwy, co zajęłoby nieco więcej czasu niż w przypadku dostępu do zmiennej.
do dodać nowe obiekty do dokumentu HTML, można je najpierw utworzyć za pomocą metody createElement
de document
a później dołącz je do pozostałych elementów w odpowiednim miejscu drzewa appendChild
. Aby utworzyć obiekt XML, jak przedmioty SVG którego używamy do rysowania wykresu czujników IoT, możesz użyć createElementNS
(NS dla przestrzeń nazw). Jak wyjaśniono, mówiąc o formacie SVG, odpowiadająca mu przestrzeń nazw (dla bieżącej wersji) to http://www.w3.org/2000/svg
, do którego należy przekazać createElementNS
jako argument wraz z typem elementu, svg
, w tym przypadku.
A alternatywa dla innerHTML
aby dodać tekst jako treść do elementu dokumentu HTML jest metoda createTextNode()
Obiekt document
. Dzięki tej alternatywie możesz utwórz nowy tekst (który jest później dostępny, jeśli jest przypisany do zmiennej), który jest włączany do drzewa obiektów za pomocą metody appendChild()
. Jak alternatywa dla appendChild()
, który dodaje nową treść na końcu tego, co już istnieje w węźle, do którego jest dodawana, możesz użyć metoda insertBefore()
, który dodaje nowy obiekt przed istniejącym. Nosić insertBefore()
zamiast appendChild()
udostępnia metodę, która służy np sortuj nowe obiekty przed istniejącymi gdy element musi znajdować się przed innym (jak na liście) lub zakrywać lub być przykryty strukturą graficzną, w której znajdują się elementy bliżej pierwszego planu lub tła.
Reaguj na wydarzenia za pomocą JavaScript
Kiedy sposób użyj strony internetowej jako pojemnika na wykresy czujników podłączonych do IoT było użyte onload
Na etykiecie <body>
aby rozpocząć rysowanie wykresu. Ta właściwość powiązana z obiektami kodu HTML, odnosi się do wydarzenia JAVASCRIPT. Jak już wyjaśniono, wykonuje funkcję po załadowaniu strony. Chociaż zostało to powiązane z kodem HTML aby lepiej o tym pamiętać, można było to zapisać w kodzie JAVASCRIPT jako body.onload=dibujar;
bycie dibujar
nazwa funkcji, która powinna zostać uruchomiona podczas ładowania strony internetowej.
W najnowszych wersjach JAVASCRIPT zdarzenia można powiązać z funkcjami za pomocą addEventListener
z formatem objeto.addEventListener(evento,función);
lub używając składni objeto.evento=función;
co działa również w starszych wdrożeniach. Aby odłączyć funkcję powiązaną ze zdarzeniem, musisz removeEventListener
który ma taki sam format jak addEventListener
.
JAVASCRIPT Potrafi reagować na wiele zdarzeń, które mogą wystąpić na stronie internetowej. Może na przykład wykryć kliknięcie elementu HTML z onmousedown
lub po kliknięciu onclick
, po naciśnięciu klawisza onkeydown
, korzystając z paska przewijania za pomocą onscroll
. Dla naszych celów to wystarczy wykryć ładowanie strony za pomocą onload
i jego zmiana rozmiaru za pomocą onresize
. Skojarzymy te zdarzenia z przedmiotami body
y window
del DOM odpowiednio. Pierwszy można przypisać w kodzie HTML, jak widać, i drugi w kodzie JAVASCRIPT wewnątrz funkcji wywoływanej przez pierwszą i z formatem window.onresize=redimensionar;
bycie redimensionar
funkcja, która będzie wywoływana za każdym razem, gdy okno zmieni rozmiar.
Uruchom po pewnym czasie
JAVASCRIPT ma dwa zasoby dla odroczona realizacja: setTimeout
, który wykonuje funkcję po upływie określonego czasu i setInterval
który będzie wykonywał funkcję w określonym przedziale czasu. Obie metody wymagają jako parametrów (1) wywoływanej funkcji i (2) przedziału czasu wyrażonego w milisekundach. Aby zatrzymać ich działanie, możesz przypisać wynik zwracany przez te funkcje do zmiennych i przekazać je jako argument do clearTimeout
lub clearInterval
kiedy nie chcesz ich ponownie wywoływać (lub kiedy nie chcesz, aby były wykonywane po raz pierwszy) setTimeout
o setInterval
odpowiednio.
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
}
|
W poprzednim przykładzie wprowadzono metodę alert
który służy do wyświetlania znaku ostrzegawczego. Chociaż był szeroko stosowany w przeszłości, obecnie jest prawie zakazany w kodzie JAVASCRIPT ze względu na to, jak agresywne (natrętne) jest zakrywanie strony internetowej oknem dialogowym.
W programie napisanym dla a mikrokontroler małej serii (takiej jak ta na talerzu Arduino Uno) często stosuje się zmienne globalne, jak w poprzednim przykładzie JAVASCRIPT, ponieważ kod jest krótki i niezbyt zagmatwany, ponieważ wielokrotnie funkcje są implementowane ad hoc, a użycie zmiennych globalnych pozwala w bardzo prosty i intuicyjny sposób przewidzieć wykorzystanie pamięci, co jest krytyczne w systemach o małych zasobach . Zamiast, en JAVASCRIPT Powszechnym zjawiskiem jest ograniczanie użycia zmiennych globalnych do możliwego minimum. ponieważ nie musi przyspieszać użycia pamięci, ponieważ działa normalnie na komputerze CPU z zasobami znacznie przewyższającymi zasoby A MCU, ponieważ prawdopodobnie współistnieje z dużą ilością kodu stron trzecich, z którym musi współpracować bez ingerencji, a ponieważ jest to system otwarty, nie można przewidzieć przyszłego kontekstu wykonania (program mikrokontroler small całkowicie określa jego działanie bez dodawania więcej kodu po jego uruchomieniu) oraz ponieważ wymiary aplikacji mogą utrudniać czytanie, jeśli kod nie zawiera jego działania, czyniąc metody tak samodzielnymi, jak to tylko możliwe.
Operacje matematyczne na obiekcie JavaScript Math
W obiekcie zgrupowane są operacje matematyczne bardziej skomplikowanych obliczeń matematycznych Math
. Ten obiekt jest używany bezpośrednio, nie jest konieczne tworzenie jego instancji, aby móc korzystać z metod lub właściwości (stałych), które zawiera.
Math.abs(n)
Wartość bezwzględna parametru nMath.acos(n)
Arccosinus parametru n (wynik w radianach)Math.asin(n)
Arcsine parametru n (wynik w radianach)Math.atan(n)
Arcus tangens parametru n (wynik w radianach)Math.atan2(n,m)
Arcus tangens n/m (wynik w radianach)Math.ceil(n)
Zaokrąglij parametr do najbliższej liczby całkowitej w góręMath.cos(α)
Cosinus parametru α (α w radianach)Math.E
liczba (≃2.718281828459045)Math.exp(n)
e podniesione do parametru n: enMath.floor(n)
Zaokrąglij parametr n do najbliższej liczby całkowitej w dółMath.log(n)
Logarytm naturalny (o podstawie e) parametru nMath.LN2
Logarytm naturalny (podstawa e) liczby 2 (≃0.6931471805599453)Math.LN10
Logarytm naturalny (podstawa e) liczby 10 (≃2.302585092994046)Math.LOG2E
Logarytm o podstawie 2 z e (≃1.4426950408889634)Math.LOG10E
Logarytm o podstawie 10 z e (≃0.4342944819032518)Math.max(a,b,c,…)
Największa wartość z listy przekazanych parametrówMath.min(a,b,c,…)
Najmniejsza wartość z listy przekazanych parametrówMath.PI
Liczba π (≃3.141592653589793)Math.pow(n,m)
Pierwszy parametr n podniesiony do drugiego parametru m: nmMath.random()
(Prawie) losowa liczba z zakresu od 0.0 do 1.0Math.round(n)
Zaokrąglij parametr n do najbliższej liczby całkowitejMath.sin(α)
Sinus parametru α (α w radianach)Math.sqrt(n)
Pierwiastek kwadratowy z parametru nMath.SQRT1_2
Pierwiastek kwadratowy z 1/2 (≃0.7071067811865476)Math.SQRT2
Pierwiastek kwadratowy z 2 (≃1.4142135623730951)Math.tan(α)
Tangens parametru α (α w radianach)
Załaduj dane z serwera za pomocą AJAX
Metoda rysowania informacji przechowywanych w IoT polega na co pewien czas ładowaniu danych z serwera i ponownym rysowaniu wykresu, za pomocą którego są one reprezentowane. Do odczytu danych z serwera wykorzystywana jest technologia AJAX (asynchroniczny JavaScript i XML) przez obiekt XMLHttpRequest
de JAVASCRIPT. Wykreślanie wykresu danych odbywa się poprzez ponowne wykorzystanie obiektu SVG co jest już w kodzie HTML i który zawiera wykres, którego współrzędne są modyfikowane, aby odpowiadały nowym załadowanym danym.
W przykładzie tej propozycji, oprócz aktualizacji rysunku, zaktualizowano także tekst na stronie internetowej, który pokazuje datę i wartość ostatnich danych pomiarowych dla każdego wykresu.
Po stronie serwera znajduje się baza danych zawierająca informacje że czujniki podłączone do Internetu Rzeczy monitorują. Ta baza danych jest odczytywana przez żądanie obiektu XMLHttpRequest
odpowiadając informacjami zakodowanymi w pliku Format JSON, choć nazwa zastosowanej metody sugeruje związek z formatem XML.
W pierwszym tutorialu polaridad.es na temat Przechowywanie danych IoT Można zobaczyć przykładową infrastrukturę do zarządzania od strony serwera informacjami dostarczanymi przez urządzenia podłączone do Internetu Rzeczy. W tej serii artykułów serwer jest używany jako zasób Apache z którego można korzystać z języka programowania PHP aby uzyskać dostęp do bazy danych MySQL o MariaDB. Na serwerach obsługujących IoT bardzo często spotyka się bazy danych MongoDB (NoSQL) i język programowania JAVASCRIPT na node.js jako infrastruktura oprogramowania.
Kolejna funkcja odpowiada za żądanie od serwera najświeższych danych z jednego z czujników. W wywołaniu funkcji obiekt jest używany jako argument JAVASCRIPT obsługujący rysowane dane. Jeśli ten sam wykres przedstawia kilka wartości, na przykład w celu wizualnego wyszukiwania korelacji, do serwera można wysłać żądanie zwrócenia kilku wartości jednocześnie, co jest metodą bardziej optymalną ze względu na sposób działania serwera. Protokół 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);
}
|
W trzeciej linii poprzedniego przykładu przygotowywane jest zapytanie, które zostanie skierowane do serwera, w którym zostanie przekazany argument „strefa”, którego wartością będzie nazwa lub kod monitorowanego miejsca, gdyż informacja o obszar może współistnieć w tej samej bazie danych, różne czujniki (np. termometry mierzące temperaturę w różnych pomieszczeniach). Oczekuje się, że parametr przekazany do poprzedniej funkcji, czyli obiekt z danymi wykresu, będzie zawierał właściwość z nazwą pomieszczenia („przyrostek_nazwy”).
Pomiędzy wierszami 7 i 14 poprzedniego kodu, obiekt XMLHttpRequest
który jest przechowywany w zmiennej „ajax”. Zanim wybierzesz sposób utworzenia obiektu, przeprowadzasz wyszukiwanie window
Jeśli XMLHttpRequest
nie był dostępny (coś, co miało miejsce w starych wersjach eksploratora Microsoftu i chociaż jest daleko w tyle, służy jako przykład alternatywy do utworzenia obiektu przy użyciu (bardziej natywnej) składni. Object.create
o new
, podobnie jak w przypadku innych języków obiektowych.
Aby móc natychmiast zarządzać odpowiedzią, kod obsługujący ją jest przygotowywany w liniach od 15 do 26 przed wysłaniem żądania do serwera.
Sposób wykonać zapytanie HTTP na serwer składa się z otwórz połączenie z open
wskazanie typu i strony (opcjonalnie nazwa użytkownika i hasło), przygotuj nagłówki protokołu z setRequestHeader
y wyślij prośbę z send
. Nagłówek HTTP Content-length
będziesz musiał znać długość zapytania (liczbę znaków), która jest obliczana za pomocą length
.
Kiedy prośba AJAX jest gotowy, wykonywana jest funkcja powiązana ze zdarzeniem onreadystatechange
. Zamiast przypisywać funkcję, w poprzednim przykładzie na bieżąco definiowana jest anonimowa funkcja, która będzie zarządzać odbiorem danych przychodzących z serwera. Przede wszystkim w linii 18 sprawdzane jest, czy status żądania to „zakończone”, co odpowiada wartości 4
nieruchomości readyState
, że status pliku to „OK”. Protokół HTTP (kod 200
), które można uzyskać od nieruchomości status
i że dane, które nadeszły, są Format JSON, konsultując nieruchomość responseType
.
Po sprawdzeniu, czy status odpowiedzi jest zgodny z oczekiwaniami, w linii 20 poprzedniego przykładu tworzy obiekt z wynikiem, konwertując tekst JSON. W odpowiedzi oczekuje się zwrócenia daty, dzięki temu możemy sprawdzić, czy wynik, który wysyła serwer, był już wcześniej przedstawiony na wykresie, co jest weryfikowane w linii 21. Jeżeli dane są nowe, w linii 23 nazywa się funkcję odpowiedzialną za przerysowanie wykresu o nowe informacje.
Założeniem proponowania tej metody odczytu jest to, że dane będą bardzo często odświeżane. Jeśli prezentowane informacje dotyczą okresu długoterminowego (np. temperatury w ciągu dnia lub tygodnia), można wdrożyć żądanie wstępne, które zbierze wszystkie dostępne dane, a następnie podobne do tego w przykładzie, które je zaktualizuje w ciągu korespondent epoki.
Generuj losowe dane do testów
Kiedy cała infrastruktura serwerowa i kliencka będzie gotowa, funkcja taka jak w poprzedniej sekcji będzie odpowiedzialna za odczytanie danych i narysowanie z nich wykresu, ale W fazie testowania bardziej praktyczne może być użycie liczb losowych w kontrolowanym zakresie aby sprawdzić, czy pisany kod jest poprawny. Poniższa funkcja może posłużyć jako przykład pozyskiwania danych podczas budowania finalnej aplikacji.
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);
}
|
Zamiast czytać informacje z bazy danych, powyższy przykład generuje je losowo i przekazuje do funkcji odpowiedzialnej za rysowanie wykresu. Wymyślone dane to wektor utworzony przez datę wyrażoną w milisekundach, moment zarejestrowania informacji z czujnika oraz monitorowane dane, które mieszczą się pomiędzy wartością maksymalną a wartością minimalną.
W tym przykładzie podczas generowania daty można ją opóźnić o maksymalnie jedną sekundę (1000 milisekund) w stosunku do daty w momencie wynalezienia. Jak Math.random()
generuje liczbę od 0.0 do 1.0, pomnożenie jej przez 1000 daje liczbę od 0 do 1000, która następnie jest konwertowana na liczbę całkowitą. W ten sam sposób wartość uzyskuje się, mnożąc liczbę losową przez zakres (maksimum minus minimum) i dodając minimum.
Narysuj wykres czujników IoT z wykresem SVG
Ponieważ widzieliśmy, jak możemy uzyskać wartości, które chcemy przedstawić (w przykładzie temperaturę) i ich położenie w czasie, które można wyrazić łącznie w postaci współrzędnych, poniższy przykład pokazuje funkcję rysowania ścieżki łączący te punkty i opcjonalnie kolorowy obszar ograniczony tą linią u góry. Rezultat będzie taki jak na poniższym obrazku.
Oś pozioma (X) wykresu przedstawia czas, a oś pionowa (Y) wartości monitorowane przez czujniki podłączone do IoT. Odstęp poziomy wynosi kilka sekund, ponieważ w tej propozycji wykres jest aktualizowany bardzo często (na przykład co sekundę), aby zapewnić informacje o stanie czujników w czasie niemal rzeczywistym.
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
}
|
W poprzednim kodzie są dwa interesujące aspekty, po pierwsze, obliczenia, które na to pozwalają dostosować zakres reprezentowanych wartości a po drugie budowa nieruchomości d
który wskazuje współrzędne punktów na układzie (path
).
Aby dostosować zakres reprezentowanych wartości, przesuwa się je od minimum i skaluje tak, aby widoczna wielkość odpowiadała rozmiarowi wykresu. W przypadku czasu przesunięcie uzyskuje się poprzez odjęcie zakresu, który chcesz wyświetlić od najdłuższego czasu (data i godzina najbliższa bieżącej) (w przykładzie 20 sekund). Przesunięcie wartości temperatur to dolny zakres (jeden stopień) minus najniższa wartość, tak aby dane pokazane poniżej były jak najbardziej zbliżone do najniższej dopuszczalnej wartości, ale z pozostawieniem marginesu, który pozwala nam docenić to, co mija
Współczynnik mnożący wartości czasu w celu uzyskania współrzędnych poziomych wykresu uzyskuje się poprzez podzielenie całkowitej szerokości wykresu (w przykładzie 100 jednostek) przez reprezentowany zakres czasu (w przykładzie 20 sekund). Aby uzyskać współczynnik ze skalarnymi wartościami temperatury, należy pamiętać, że przedstawiony zakres rozciąga się od marginesu poniżej wartości minimalnej do marginesu powyżej maksimum, o jeden stopień w obu przypadkach. W ten sposób współczynnik skali pionowej wynika z podzielenia wysokości wykresu (w przykładzie 100 jednostek) przez wartość maksymalną minus minimum plus górny i dolny margines. Ponieważ wartości te mogą całkowicie rozwinąć się w temperaturach ujemnych, używamy Math.abs()
użyć wartości bezwzględnej różnicy.
Własność d
Obiekt path
Konstruuje się go poprzez połączenie współrzędnych punktów w tekście. Każda para współrzędnych jest poprzedzona kodem SVG L
, który rysuje linię od aktualnej pozycji do wartości bezwzględnej wskazanej przez współrzędne. Wartości X i Y oddzielamy przecinkami i każdą operację SVG jest oddzielona spacją od następnego.
Aby rozpocząć układ, użyj kodu M
(przejdź do współrzędnej absolutnej). W przypadku wykresu zamkniętego i wypełnionego zaczynasz od prawego dolnego rogu, w przypadku wykresu otwartego rysującego profil danych zaczynasz od ostatniej reprezentowanej wartości (najnowszej). Aby zakończyć zamknięty układ, używany jest kod Z
dodając jako ostatni punkt ten, który ma tę samą wartość współrzędnej X co ostatni punkt linii, a jako współrzędną Y najmniejszą reprezentowaną wartość.
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
);
}
|
W tym przykładzie funkcja dibujar_grafico()
, czyli wywołanie ładowania strony, pobiera początkowe wartości do przetestowania (nie ostatnią wartość w czasie rzeczywistym) i przygotowuje zakres, w jakim dane będą renderowane: 20 sekund (20000 ms) w poziomie i 15°C w pionowo od -5°C do +10°C z jednostopniowym marginesem górnym i dolnym. Wykonaj dwa połączenia do actualizar_grafico()
, w pierwszym przejściu true
jako argument wskazujący, że wykres powinien zostać zamknięty, aby reprezentował wypełniony obszar, a przy drugim wywołaniu zostaje uznany false
narysować linię. W każdym przypadku przedmiot path
zmodyfikowany to taki, który ma odpowiedni wygląd, z wypełnieniem i bez obramowania w pierwszym przypadku oraz z określoną grubością linii i bez wypełnienia w drugim przypadku.
Funkcja actualizar_grafico()
pracować nad przedmiotem SVG który używa następującego kodu jako kontenera HTML. Obiekt SVG zawiera dwie ścieżki, jedną do rysowania linii i drugą do rysowania wypełnionego obszaru. Podczas ładowania strony internetowej z elementu <body>
poprzednia funkcja wywoływana jest automatycznie, dibujar_grafico()
dzięki wydarzeniu 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>
|
W linii 10 kodu HTML powyżej, w stylu ustalona jest szerokość (dla przykładu) 820 px i wysokość 150 px (coś, co w ostatecznej wersji będzie wskazane z klasą i dokumentem CSS). Wydaje się dziwne, że linie 13 i 14 określają rozmiar obiektu SVG np. 100% szerokości i wysokości (która najlepiej odpowiada wymiarom okna, 100×100). Jak już wspomniano, powodem tego jest zawsze praca ze znanymi wymiarami i dostosowywanie do nich reprezentowanych wartości. Inną alternatywą byłoby każdorazowe obliczenie przestrzeni wykresu i późniejsze dostosowanie wartości lub wymuszenie stałych wymiarów wykresu, których dokument będzie musiał przestrzegać.
Wybierając wykres, którego wymiary zmieniają się zgodnie z kodem HTML, konieczne jest uwzględnienie nieruchomości vector-effect
z odwagą non-scaling-stroke
aby zapobiec deformacji grubości linii, gdy wykres nie zachowuje wybranych proporcji 1:1 na stronie internetowej, na której jest wyświetlany, jak to miało miejsce w poprzedniej propozycji.
Aby „przyciąć” wykres i wyświetlić tylko wybrany obszar, użyj opcji viewBox
. W tym przypadku wybraliśmy część wykresu zaczynającą się od 0,0 (lewy górny róg) i mającą wymiary 100x100 w dół i w prawo. Część rysunku znajdująca się we współrzędnych o wartościach ujemnych lub większych niż 100 nie będzie wyświetlana na stronie internetowej nawet jeśli istnieją w obiekcie SVG
Dodaj nowe elementy do rysunku SVG
W poprzednim przykładzie funkcja actualizar_grafico()
użyj układu SVG na który następuje zmiana właściciela d
, co wyraża łańcuch współrzędnych. Alternatywą byłoby utworzenie całego obiektu za każdym razem, gdy jest on przerysowywany. Zaletą pierwszej opcji jest to, że wygląd graficzny (np. grubość czy kolor) jest zdefiniowany w kodzie HTMLograniczeniem jest to, że obiekty muszą zostać wcześniej utworzone.
Aby utworzyć obiekty SVG, użyj createElementNS()
, co pozwala na włączenie przestrzeń nazw. W poniższym przykładzie tworzony jest nowy obiekt tekstowy (text
) i jest powiązany z elementem SVG który już istnieje w kodzie HTML strony internetowej. Po utworzeniu nowego elementu przypisywane są jego właściwości setAttribute()
i jest dodawany do 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]);
|
Zmień proporcje elementów rysunku
Jeśli próbowałeś etykietować za pomocą funkcji z przykładu z poprzedniej sekcji, zauważyłeś, że tekst wydaje się zdeformowany, gdy proporcje obiektu na stronie internetowej (width
y height
kodu HTML) nie jest równy reprezentowanemu obszarowi (viewBox
). Aby dostosować proporcje, konieczna jest znajomość wymiarów obiektu SVG dla którego możesz sprawdzić styl obiektu lub pojemnika HTML, jeśli obiekt SVG przenieść tę nieruchomość. Przypisywanie własności transform
do przedmiotów SVG które zależą od proporcji, deformację można skorygować, stosując operację skalowania scale()
w którym współczynnik w X jest inny niż w 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 umożliwia zgrupowanie kilku obiektów w nowy element złożony, który obsługuje również właściwościjak proste przedmioty. Aby zastosować tę samą transformację do szeregu obiektów na raz, a nie do każdego obiektu osobno, możesz pogrupować je według tego zasobu i zastosować pojedynczą właściwość transform
do nich wszystkich.
Jak wyjaśniono podczas rozmowy Format SVG, elementy grupy są otoczone etykietami <g>
y </g>
. Aby dodać z JAVASCRIPT elementy do grupy SVG jest używany, jak widać w poprzednim przykładzie, appendChild()
po zdefiniowaniu nowego obiektu.
Aby ustalić początek podczas stosowania przekształceń, właściwość można zastosować na obiektach SVG transform-origin
, którego wartością są współrzędne X i Y punktu, od którego rozpoczyna się transformacja. Jeżeli wartość początku transformacji nie jest wyraźnie wskazana (w przeglądarce internetowej), stosowany jest środek współrzędnych. Niestety, w momencie pisania tego tekstu, określenie zachowania transformacji przy użyciu źródła innego niż domyślne nie jest jednolite w różnych przeglądarkach i należy stosować je ostrożnie.
Wraz z transformacją skali za pomocą scale
Istnieją inne, takie jak obrót z rotation
i ruch z translate
, które oferują alternatywa dla reprezentacji graficznej: zamiast uzyskiwać nowe współrzędne, możesz przedstawić je w ich własnej przestrzeni i przekształcić wykres tak, aby pasował do formatu, w jakim chcesz je przedstawić.
Dodaj odniesienia do wykresu
Teraz, gdy główna część wykresu została rozwiązana poprzez wykreślenie wartości z profilem i wypełnionym obszarem, można go uzupełnić odniesieniami, które pomogą w jego odczytaniu. Jako przykład zacznijmy od narysowania poziomych odniesień (linii), które zaznaczają maksymalne i minimalne akceptowalne wartości, a także pożądaną wartość. Jak wyjaśniono, możesz dodać obiekty do pliku SVG prosto z JAVASCRIPT lub umieść je ręcznie w kodzie HTML i zmodyfikuj je później za pomocą 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();
|
Logiczne wydaje się oznaczenie tych odniesień poziomych tekstem wyjaśniającym wartość, jaką reprezentują. Do wyróżnienia tekstu można zastosować prostokąty, które wyróżnią się na tle tła i grafiki. Ponieważ teksty będą musiały zostać przeskalowane, aby skompensować deformację, można je wszystkie pogrupować w obiekt, do którego zostanie zastosowana skala; Główną zaletą takiego działania jest możliwość ich modyfikacji w jednej operacji, jeśli rozmiar kontenera wykresu (okna przeglądarki) zostanie zmieniony i zmieni się proporcja korygowana przez skalę.
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();
|
W powyższym przykładowym kodzie jest kilka interesujących aspektów. Na początek zauważ, że zastosowano stałe (zmienne globalne), aby przykład był bardziej czytelny dla użytkowników zajmujących się programowaniem. mikrokontrolery en C lub C + +. Jak się później okaże, optymalny sposób na zaprogramowanie tego JAVASCRIPT Byłoby to użycie obiektów zawierających te wartości i metod, które zarządzałyby referencjami w tym przykładzie lub ogólnie na wykresie w systemie produkcyjnym.
Z drugiej strony, udoskonalając wygląd bardziej ogólnego kodu, opracowano osobne funkcje, które obliczają różne współczynniki korygujące proporcje wykresu w celu dostosowania tekstu proporcion_grafico()
, skala wartości w zależności od ich zakresu escala()
oraz współczynnik korekcyjny dla pomiarów znanych w wartościach bezwzględnych, takich jak pomiary w odniesieniach medida_grafico()
.
Lektura tego kodu powinna pomóc w wyjaśnieniu kontekstu, w którym działa taka aplikacja, która rysuje grafikę w czasie rzeczywistym i musi być elastyczna, aby można ją było prezentować w różnych kontekstach graficznych (przynajmniej w różnych rozmiarach i proporcjach). Przede wszystkim należy wygenerować obiekty SVG, „ręcznie” w kodzie HTML, albo poprzez kod JAVASCRIPT w każdym razie należy następnie uzyskać odniesienia do tych obiektów, aby nimi manipulować JAVASCRIPT dzięki czemu można rysować nowe wykresy i dostosowywać reprezentację już narysowanego wykresu do zmiany medium, w którym jest on prezentowany.
Kolejnym odniesieniem, które może pomóc w łatwej interpretacji wykresu, są punkty reprezentujące określone wartości (węzły prostej). W tym przykładzie, w którym reprezentujemy pojedynczą wielkość, wybór symbolu nie jest krytyczny, ale jeśli nałoży się na siebie kilka różnych wartości w celu poszukiwania korelacji, warto rozróżnić, oprócz wykorzystania innych zasobów, takich jak kolor , rysując różne symbole. Grafika używana dla węzła linii musi zostać zmodyfikowana pod względem wielkości i proporcji, jak to ma miejsce na przykład w przypadku tekstów, tak aby jej wymiary były absolutne i aby jej proporcje zostały zachowane nawet w przypadku zmiany zawartych w grafice ramek.
W poprzednim przykładzie widzieliśmy już, jak obliczyć różne współczynniki w celu przeskalowania i skorygowania proporcji rysunku; Jeśli chodzi o sposób wdrożenia zarządzania symbolami węzłów lub wierzchołków grafu, możliwym rozwiązaniem może być przechowywanie obiektów SVG do wektora i modyfikować jego położenie podczas aktualizacji wykresu poprzez odczytanie nowej wartości lub podczas ponownego rysowania poprzez zmianę rozmiaru kontenera. W pierwszym przypadku należałoby zmienić jego położenie, a w drugim jego proporcje w stosunku do nieruchomości transform
i wartość scale
. Poniższy kod jest modyfikacją funkcji actualizar_grafico()
aby uwzględnić zmianę położenia symboli wierzchołków wykresu.
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);
}
}
|
Modyfikacje wprowadzone w funkcji actualizar_grafico()
aby uzyskać nową funkcję actualizar_grafico_puntos()
Są to te wyróżnione w kodzie poprzedniego przykładu. Najpierw w linii 5 bierzemy wektor obiektów SVG jako parametr. Ten wektor będzie zawierał symbole, które należy zmienić w nowych węzłach wykresu.
W liniach 39 i 40 przypisane są nowe współrzędne środka, cx
y cy
, do wartości, które są reprezentowane. Jeżeli symbol nie opierał się na środku, prawdopodobnie konieczne będzie dodanie przesunięcia cx
połowę szerokości i w cy
połowy wysokości, aby przenieść je dokładnie w węźle wykresu.
W liniach od 57 do 61 punkty odpowiadające współrzędnym, które nie zostały narysowane, ponieważ zostały obcięte lewą krawędzią, są przenoszone poza wykres. Współrzędna cy
do zera i tyle cx
do dowolnej liczby ujemnej (większej niż sam punkt), tak aby nie była ona pokazywana po przecięciu, podobnie jak lewa część wykresu, przez okno SVG.
Zarządzaj wykresem z obiektu za pomocą JavaScript
Wszystkie wyjaśnione do tej pory operacje można zintegrować w obiekcie, aby zarządzać wykresem w stylu bardziej typowym dla nowych wersji JAVASCRIPT. Ta alternatywa implementacyjna ma dodatkową zaletę polegającą na uproszczeniu włączenia kilku wykresów o różnych wartościach na tej samej stronie internetowej.
Zanim omówimy implementację, przejrzyjmy najczęstsze sposoby tworzenia obiektów JAVASCRIPT oraz niektóre cechy funkcji, które wpływają na propozycję rysowania grafiki czujnika IoT.
Wyjaśniono już, że nowy sposób tworzenia obiektów w JAVASCRIPT (dostępne od wersji 5 ECMAScript) polega na używaniu Object.create
, do którego należy się przyzwyczaić zamiast „klasycznego” new
, który oczywiście nadal działa poprawnie, chociaż jego celem jest bardziej symulowanie stylu języków za pomocą obiektów klasowych (JAVASCRIPT opiera tworzenie obiektów na prototypach) niż działająca alternatywa.
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();
}
|
Poprzedni kod pozwala zapamiętać różnice pomiędzy tworzeniem obiektów za pomocą Object.create
lub new
. Służy to również podkreśleniu tego, choć funkcja, z jaką obiekt jest tworzony new
może znajdować się w dowolnym miejscu kodu, obiekt musi już istnieć, zanim będzie można utworzyć jego instancję Object.create
(Obiekt ES5_Object nie jest funkcją).
W liniach 3 i 4, aby ustawić wartość domyślną właściwości w funkcji, która tworzy obiekt new
, każda właściwość jest przypisana do wartości odpowiedniego argumentu lub (||
), jeśli nie przekazano żadnych argumentów, to znaczy, jeśli są one niezdefiniowane (undefined
), ponieważ okoliczność ta jest oceniana jako false
, przypisana jest wartość domyślna.
Kontekst, w którym wykonywana jest funkcja JAVASCRIPT podnosi dwie kwestie, o których należy pamiętać i które mogą być mylące podczas używania tego języka programowania po pracy z innymi, np. C o C + +, w naszym przypadku. Kontekst obejmuje zmienne zdefiniowane w zakresie funkcji (i te globalne), co swoją drogą nasuwa ciekawą koncepcję, „domknięcia”, które ustanawiają cały styl programowania w JAVASCRIPT. To powiedziawszy, można było się tego spodziewać this
, który odnosi się do obiektu, gdy jest używany w kodzie go definiującym, kontekst wykonania, w którym został zdefiniowany, jest zachowywany, ale ten, którego używa, jest kontekstem, z którego wywoływana jest funkcja. To zachowanie jest w większości przypadków przezroczyste, ale istnieją dwie okoliczności, w których może być mylące: funkcja zdefiniowana wewnątrz innej funkcji i metoda wywoływana ze zdarzenia obiektu. 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
*/
|
Podczas wykonywania poprzedniego kodu w konsoli wyświetlany jest tekst z komentarzem na końcu. Dwie zaznaczone linie odzwierciedlają zachowanie, które może być mylące: kontekst wykonania funkcji probar_dentro()
nie probar()
jak można się było spodziewać, ale window
, który pokazuje zmienne globalne, a nie właściwości o tej samej nazwie. Jeśli nie chcesz takiego zachowania, po prostu utwórz zmienną w funkcji najwyższego poziomu i przypisz ją do this
, jak w poniższym kodzie.
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
*/
|
Aby kontrolować kontekst wykonania, gdy metoda jest wywoływana ze zdarzenia window
, na przykład poprzez zmianę rozmiaru okna przeglądarki, co jest kolejną osobliwością JAVASCRIPT: możliwość programowania „fabryk funkcji”, czyli funkcji generujących inne funkcje, zwracając je 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
|
W powyższym przykładowym kodzie metoda llamar()
obiektów Contexto
Nie wykonuje całej pracy, ale zwraca anonimową funkcję, która się tym zajmuje. Aby sprawdzić, czy wszystko działa zgodnie z oczekiwaniami, istnieje zmienna globalna o tej samej nazwie, co właściwość wyświetlana przez funkcję w konsoli; Jeśli kontekst jest poprawny, zostanie wyświetlona wartość właściwości, a nie zmiennej globalnej.
JAVASCRIPT Spróbuj poprawić znaki średnika, które pomijamy na końcu zdań. Pozwala to na swobodny styl pisania, ale jest mieczem obosiecznym, z którym należy obchodzić się ostrożnie. W większości przypadków, aby uniknąć niepożądanych efektów, jakie powoduje to w wyrażeniach zajmujących kilka wierszy, można użyć nawiasów lub poprzedzić sposób, w jaki JAVASCRIPT zinterpretuje kod; Dlatego linia 8 przykładu zawiera function
z tyłu return
, gdybym użył innego wersu, znaczenie byłoby zupełnie inne. Moim zdaniem najbardziej czytelnym rozwiązaniem jest użycie zmiennej pośredniej (zbędnej) jak w poniższej wersji; Oczywiście po zrozumieniu zachowania decyzja należy do programisty.
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);
|
W tym samym sensie oceniania wyrażenia jako funkcji, to znaczy zwracania funkcji, a nie wartości, którą funkcja zwraca; w linii 21 ostatniego przykładu (było w linii 19 poprzedniego) kończy się clearInterval
funkcja wywołana with setInterval
. Aby mógł działać przez 30 sekund, zatrzymanie zostaje odroczone za pomocą setTimeout
, co z kolei wymaga funkcji jako pierwszego argumentu; aby dostarczyć wykonanie jako parametr clearInterval
ze zmienną zawierającą wywołanie okresowe (a nie funkcję clearInterval
) jest tym, do czego utworzono funkcję anonimową w ostatniej linii.
Wybór pomiędzy napisaniem kodu integrującego definicję funkcji, bardziej zwartego (jak w linii 21) lub użyciem zmiennej pomocniczej, moim zdaniem, bardziej czytelnej (jak w liniach 19 i 20) różni się nieznacznie pod względem wydajności i zależy od większego stylu i czytelności konserwacja.
Aby przetestować kod, zanim dane znajdą się na serwerze, można skorzystać z generatora wartości losowych z żądanego zakresu lub przygotować tabele z kontrolowanymi wartościami, które symulują działanie w zadanych warunkach. Poniższy przykład wykorzystuje prosty generator danych w całym zakresie, dlatego wydają się one nieco przesadzone.
Aby przetestować, możesz pobierz pełny kod przykładu utworzony przez stronę internetową napisaną w HTML, styl CSS i kod JAVASCRIPT. To ostatnie jest najbardziej istotne, ponieważ pozostałe komponenty mają jedynie minimalne wsparcie, są bardzo uproszczone i są znacznie bardziej rozwinięte w artykułach w odpowiednich sekcjach.
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);
}
|
Zamieść komentarz