Δημιουργήστε και τροποποιήστε γραφικά SVG δεδομένων από αισθητήρες που είναι συνδεδεμένοι στο IoT με JavaScript
Σε αυτό το τελευταίο μέρος της σειράς άρθρων για το σχέδιο γραφικά με δεδομένα από αισθητήρες συνδεδεμένους στο Internet of Things, ήρθε η ώρα να μιλήσουμε για το πώς να δημιουργήσετε ή να τροποποιήσετε με το JavaScript σχέδια σε μορφή SVG και μερικά από τα στοιχεία HTML που χρησιμεύουν ως κοντέινερ ή που παρουσιάζουν συμπληρωματικές πληροφορίες στα γραφικά.
Οι χρήστες-στόχοι αυτού του σεμιναρίου υποτίθεται ότι σχηματίζουν ένα προφίλ ηλεκτρονικών και προγραμματισμού υπολογιστών. μικροελεγκτές, μπορεί να μην είναι εξοικειωμένοι HTML, CSS o SVG; Για το λόγο αυτό, στις προηγούμενες δόσεις έγινε μια σύντομη εισαγωγή στη γλώσσα ή την αντίστοιχη τεχνολογία. Σε αυτό το τελευταίο μέρος η προσέγγιση είναι λίγο διαφορετική, αφού οι αναγνώστες σίγουρα γνωρίζουν πώς να προγραμματίζουν, είναι πιθανό ότι χρησιμοποιώντας τη γλώσσα C + + τι πως το JavaScript, μοιράζεται τη βασική σύνταξη με C και μπορεί να χρησιμοποιηθεί ως αναφορά για να παρακάμψουμε τις περισσότερες βασικές έννοιες προγραμματισμού και έτσι να εστιάσουμε στις διαφορές και τη συγκεκριμένη χρήση που μας ενδιαφέρει για τη δημιουργία γραφικών αισθητήρων στο IoT.
Το όνομα δίνει μια ένδειξη για την πρώτη διαφορά: το JavaScript Είναι μια γλώσσα προγραμματισμού γραφή (παύλα) και ως εκ τούτου, είναι ερμηνεύονται, δεν χρειάζεται να το μεταγλωττίσετε. το πλαίσιο στο οποίο οι γραφή (ένα πρόγραμμα περιήγησης ιστού, για παράδειγμα) θα διαβάσει, θα μεταφράσει και θα εκτελέσει τις εντολές. Για την ακρίβεια, στις περισσότερες περιπτώσεις υπάρχει α συλλογή χρόνου εκτέλεσης (JIT), αλλά για τη διαδικασία γραφής κώδικα το JavaScript Δεν μας επηρεάζει, απλά γράφουμε τον κώδικα και μπορεί να λειτουργήσει.
Το όνομα περιέχει επίσης την πρώτη σύγχυση: το JavaScript δεν έχει την παραμικρή σχέση με Java. Αρχικά, όταν αναπτύχθηκε Netscape για το πρόγραμμα περιήγησής του, ονομαζόταν πρώτα Mocha και μετά το λιγότερο συγκεχυμένο LiveScript. Μετά την επιτυχή εφαρμογή του σε προγράμματα περιήγησης, και την υπέρβασή τους, τυποποιήθηκε ως ECMAScript (Στο ECMA-262, έκδοση 6 τη στιγμή της σύνταξης) να γίνει ουδέτερο σε σχέση με τα προγράμματα περιήγησης που το εφαρμόζουν. Επί του παρόντος υπάρχει επίσης ένα πρότυπο ISO από την έκδοση 5, 2011 (ISO / IEC 16262: 2011 τη στιγμή της συγγραφής του άρθρου)
Μεταβλητές, βασικοί τύποι δεδομένων και αντικείμενα σε JavaScript
Σε αντίθεση με αυτό που συμβαίνει, για παράδειγμα, στο C + +, en το JavaScript ο τύπος δεδομένων δεν περιλαμβάνεται κατά τη δήλωση μιας μεταβλητής και επίσης ο τύπος που συσχετίζεται με μια μεταβλητή δεν είναι σταθερός, είναι δυνατό να εκχωρηθεί μια τιμή διαφορετικού τύπου σε όλη την εκτέλεση του προγράμματος.
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
|
Στο προηγούμενο παράδειγμα, η μεταβλητή "thing" έχει δηλωθεί (χωρίς να υποδεικνύεται ο τύπος δεδομένων) και στη συνέχεια εκχωρούνται δεδομένα διαφορετικού τύπου και γίνεται διαβούλευση με typeof
ο τύπος που το JavaScript που έχει ερμηνεύσει. Για τον εντοπισμό σφαλμάτων του κώδικα, μπορείτε να τον γράψετε στην κονσόλα επιθεώρησης του προγράμματος περιήγησης ιστού (η οποία δεν θα επηρεάσει την παρουσίαση του Ιστού) με console.log()
.
Για να εξαναγκάσετε τη μετατροπή δεδομένων σε συγκεκριμένο τύπο, ιδίως κείμενο σε αριθμητικό, μπορείτε να χρησιμοποιήσετε συναρτήσεις όπως π.χ parseInt()
o parseFloat()
που μετατρέπονται σε ακέραιους ή αριθμούς κινητής υποδιαστολής αντίστοιχα. Η αντίθετη μετατροπή μπορεί να γίνει με String()
, αν και είναι απίθανο να είναι απαραίτητο καθώς συνήθως αρκεί η αυτόματη μετατροπή. Με parseFloat()
Για παράδειγμα, μπορείτε να λάβετε την τιμή μιας ιδιότητας ιστοσελίδας, όπως το πλάτος ή το ύψος ενός αντικειμένου, που περιλαμβάνει μονάδες. Με αυτόν τον τρόπο η έκφραση parseFloat("50px");
θα επιστρέψει 50, μια αριθμητική τιμή, ως αποτέλεσμα.
En το JavaScript δεν υπάρχει διάκριση μεταξύ διπλών και μονών εισαγωγικών; Ο τύπος δεδομένων και στις δύο περιπτώσεις είναι string
, και το καθένα από αυτά μπορεί να περιλαμβάνει το άλλο χωρίς την ανάγκη κωδικών διαφυγής.
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
|
Στο προηγούμενο παράδειγμα μπορεί να φανεί ότι μια μεταβλητή, όταν έχει δηλωθεί (υπάρχει) αλλά δεν της έχει εκχωρηθεί καμία τιμή, περιέχει έναν απροσδιόριστο τύπο δεδομένων (undefined
). Ένα μη εκχωρημένο αντικείμενο έχει την τιμή null
; Δηλαδή το αντικείμενο υπάρχει, αλλά χωρίς αξία. μια μεταβλητή που την ανέφερε δεν θα είχε α typeof
undefined
αλλά object
. Ένα αντικείμενο μπορεί επίσης να είναι κενό, δηλαδή να μην είναι null αλλά να μην έχει ιδιότητες.
να ορίστε ένα αντικείμενο σε το JavaScript είναι κλεισμένα σε σιδεράκια ({
y }
) τις ιδιότητες ή τις μεθόδους, διαχωρισμένες με το σύμβολο άνω και κάτω τελείας (:
) όνομα ιδιότητας αξία ιδιότητας και με κόμμα (,
) τις διαφορετικές ιδιότητες. Μπορείτε να βρείτε περισσότερες πληροφορίες σχετικά με αυτόν τον τρόπο έκφρασης ενός αντικειμένου στο άρθρο για το Μορφή JSON.
Αν και μπορείτε να χρησιμοποιήσετε σύνταξη που μπορεί να σας κάνει να σκεφτείτε διαφορετικά, en το JavaScript Δεν υπάρχουν τάξεις αλλά πρωτότυπαΔηλαδή, για να κληρονομήσει ένα αντικείμενο ιδιότητες και μεθόδους, δημιουργείται ένα άλλο αντικείμενο (το πρωτότυπο) που τα άλλα (τα παιδιά) χρησιμοποιούν ως αναφορά. Η σύνταξη που πλησιάζει περισσότερο στο στυλ του το JavaScript να χρησιμοποιήσετε ένα πρωτότυπο είναι Object.create
αν και είναι επίσης δυνατό (και μερικές φορές χρήσιμο) στη χρήση new
όπως και σε άλλες αντικειμενοστρεφείς γλώσσες.
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));
|
να ερώτημα εάν ένα αντικείμενο είναι μια παρουσία ενός άλλου, αν το χρησιμοποιήσετε ως πρωτότυπο, αν κληρονομήσετε τις ιδιότητές του, με λίγα λόγια, μπορείτε να το χρησιμοποιήσετε instanceof
(δημιουργήθηκε με new
) Ή isPrototypeOf
(δημιουργήθηκε με Object.create
) που θα αξιολογηθεί ως true όταν το αντικείμενο χρησιμοποιεί το πρωτότυπο και false όταν δεν το κάνει.
Μόλις ένα αντικείμενο έχει δημιουργηθεί χρησιμοποιώντας ένα άλλο ως πρωτότυπο, δηλαδή, μόλις ένα αντικείμενο έχει δημιουργηθεί, μπορεί να προσθέστε νέες ιδιότητες ή παρακάμψτε τις πρωτότυπες ιδιότητες χρησιμοποιώντας τη σύνταξη κουκκίδων όπως στο gato.peso=2.5
.
La συστοιχίες σε το JavaScript Είναι διαφορετικά από αυτά που πιθανότατα γνωρίζετε C. Αρχικά, δηλώνονται χωρίς να χρειάζεται να αναγράφεται το μήκος τους, μόνο με τα σημάδια ανοίγματος και κλεισίματος αγκύλων ([
y ]
), τα στοιχεία μπορεί να είναι ετερογενή (διαφορετικοί τύποι δεδομένων στον ίδιο πίνακα) και μπορούν να προστεθούν νέα στοιχεία χωρίς περιορισμό σε κάποιο όριο. Οι μήτρες του το 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
|
// 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
|
Όπως φαίνεται στο προηγούμενο παράδειγμα, για να μάθετε εάν μια μεταβλητή αντιστοιχεί σε μια παρουσία ενός πίνακα (είναι αντικείμενο πίνακα) μπορείτε να χρησιμοποιήσετε instanceof
, όπως έχει ήδη χρησιμοποιηθεί με γενικά αντικείμενα ή, σε πιο πρόσφατες εκδόσεις του το JavaScript μπορείτε να καταφύγετε Array.isArray()
Για πρόσβαση στα στοιχεία του πίνακα μπορείτε να χρησιμοποιήσετε το ευρετήριό του (matriz[7]
) ή με το όνομα του ακινήτου με το όνομα σε αγκύλες (matriz["nombre"]
) ή με τη συνήθη σύνταξη κουκκίδων για αντικείμενα (matriz.nombre
). Δεδομένου ότι το όνομα είναι μια συμβολοσειρά κειμένου, μια έκφραση, συμπεριλαμβανομένων των μεταβλητών, μπορεί να χρησιμοποιηθεί για τη σύνθεσή της. Για να κάνετε βρόχο μέσω ενός πίνακα με ιδιότητες, μπορεί να χρησιμοποιηθεί ένας βρόχος με τη μορφή 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
*/
|
Είναι ενδιαφέρον για τον στόχο μας να θεραπεύσουμε το αντικείμενο Date
, με το οποίο μπορείτε να αναπαραστήσετε και να διαχειριστείτε την ημερομηνία και την ώρα το JavaScript. Το αντικείμενο μπορεί να δημιουργηθεί χωρίς δεδομένα, επομένως θα πάρει την τρέχουσα ημερομηνία και ώρα, ή μπορεί να δημιουργηθεί υποδεικνύοντας μια ημερομηνία ως τιμή, είτε σε χιλιοστά του δευτερολέπτου από την 1η Ιανουαρίου 1970 (π.χ. Χρόνος Unix ή ώρα POSIX αλλά εκφράζεται σε χιλιοστά του δευτερολέπτου αντί για δευτερόλεπτα) ή καθορίζοντας ξεχωριστές τιμές έτους, μήνα, ημέρας, ώρας...
Το αντικείμενο περιλαμβάνει μια πλήρη σειρά από μεθόδους αναζήτησης ή ρύθμισης ημερομηνίας και ώρας:
-
now()
Επιστρέφει την τρέχουσα ημερομηνία και ώρα που εκφράζονται σε χιλιοστά του δευτερολέπτου από την 1η Ιανουαρίου 1970 -
getTime()
|setTime()
Λαμβάνει ή αλλάζει, αντίστοιχα, την τιμή χρόνου σε χιλιοστά του δευτερολέπτου από την 1η Ιανουαρίου 1970. ΧρησιμοποιώνταςvalueOf()
, που είναι μια μέθοδος που υπάρχει στα περισσότερα αντικείμενα, λαμβάνεται και η τιμή του αντίστοιχου αντικειμένου Date, όπως π.χ.getTime()
με Χρόνος Unix ή ώρα POSIX εκφράζεται σε ms. -
getMilliseconds()
|setMilliseconds()
Χρησιμοποιείται για την αναζήτηση ή τον ορισμό του τμήματος κλασματικού χιλιοστού του δευτερολέπτου του αντικειμένουDate
στο οποίο εκτελείται. Εάν συμβουλευτείτε, η τιμή που λαμβάνεται είναι μεταξύ 0 και 999, αλλά μπορούν να εκχωρηθούν μεγαλύτερες τιμές που θα συγκεντρωθούν στη συνολική ημερομηνία και ώρα, έτσι, όπως και οι υπόλοιπες μέθοδοι λήψης, χρησιμεύει για την αύξηση της τιμής του αντικειμένουDate
(ή μειώστε το, εάν χρησιμοποιούνται αρνητικές τιμές). -
getSeconds()
|setSeconds()
Επιστρέφει ή αλλάζει, αντίστοιχα, την τιμή των δευτερολέπτων του αντικειμένουDate
. -
getMinutes()
|setMinutes()
Χρησιμοποιείται για να συμβουλευτείτε ή να ορίσετε τα πρακτικά του αντικειμένουDate
. -
getHours()
|setHours()
Σας επιτρέπει να συμβουλευτείτε ή να τροποποιήσετε τις ώρες (από 0 έως 23) του αντικειμένουDate
. -
getDay()
Επιστρέφει την ημέρα της εβδομάδας για την ημερομηνία, εκφρασμένη ως τιμή από 0 έως 6 (Κυριακή έως Σάββατο). -
getDate()
|setDate()
Επιστρέφει ή αλλάζει την ημέρα του μήνα του αντικειμένουDate
στην οποία εφαρμόζεται. -
getMonth()
|setMonth()
Χρησιμοποιείται για να συμβουλευτεί ή να τροποποιήσει τον αριθμό μήνα του αντικειμένουDate
. -
getFullYear()
|setFullYear()
Υποβάλλει ερωτήματα ή ορίζει την τιμή έτους στο αντικείμενο που περιέχει την ημερομηνία και την ώρα.
Οι προηγούμενες μέθοδοι του Date
περιλαμβάνει μια έκδοση UTC να μπορείς να δουλεύεις απευθείας με τον καθολικό χρόνο χωρίς να χρειάζεται να κάνεις ενδιάμεσους υπολογισμούς. Υπό αυτή την έννοια, για παράδειγμα, getHours()
έχει μια έκδοση getUTCHours()
o getMilliseconds()
Μία εναλλακτική getUTCMilliseconds()
να συνεργαστεί εναλλακτικά με την επίσημη (νόμιμη) ή καθολική ώρα. Με getTimezoneOffset()
Μπορείτε να γνωρίζετε τη διαφορά που υπάρχει μεταξύ της παγκόσμιας ώρας και της τοπικής επίσημης ώρας.
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;
|
Λειτουργίες JavaScript
Αν διαβάζετε αυτό, σίγουρα γνωρίζετε πώς να προγραμματίζετε. μικροελεγκτές en C ή C + + και γνωρίζουν την έννοια της συνάρτησης. Αν και η βασική ιδέα είναι η ίδια, στο το JavaScript Ο τρόπος που ορίζονται και χρησιμοποιούνται είναι λίγο διαφορετικός. Αρχικά, έχει ήδη ειπωθεί, το JavaScript Δεν χρησιμοποιεί ρητά τύπους δεδομένων, επομένως δεν χρειάζεται να το υποδείξετε κατά τον ορισμό της συνάρτησης. Ακολουθώ, Δεν είναι υποχρεωτικό για μια συνάρτηση να έχει όνομα, μπορεί να είναι ανώνυμα. Μπορούν να συσχετιστούν με μια μεταβλητή για την επίκλησή τους, αλλά μπορεί επίσης να μην είναι απαραίτητο αφού, μερικές φορές, είναι χρήσιμο να τα καλέσετε αμέσως, για την οποία προστίθενται οι παρενθέσεις και οι παράμετροι μετά τον ορισμό της συνάρτησης.
Για να ορίσετε μια συνάρτηση, προσθέστε πρόθεμα function
, εάν ισχύει, γράψτε το όνομα, τα ορίσματα (τις παραμέτρους που μεταβιβάστηκαν στη συνάρτηση) σε παρένθεση και τον κώδικα που θα εκτελεστεί όταν η συνάρτηση καλείται σε αγκύλες.
1
2
3
4
5
|
function doble(numero)
{
var resultado=numero*2;
return resultado;
}
|
Σίγουρα, στο προηγούμενο παράδειγμα η μεταβλητή "αποτέλεσμα" δεν χρειαζόταν καθόλου, αλλά είναι μια καλή δικαιολογία για να θυμόμαστε μεταβλητό εύρος, το οποίο λειτουργεί όπως περιμένετε: η μεταβλητή "αποτέλεσμα" υπάρχει μόνο στη συνάρτηση "διπλό". Σε το JavaScript μπορεί επίσης να χρησιμοποιηθεί let
, αντί για var
, για την εμβέλεια μιας μεταβλητής σε ένα πλαίσιο μπλοκ κώδικα (περικλείεται σε σγουρά άγκιστρα, {
y }
)
Όταν μιλάμε για αντικείμενα στην προηγούμενη ενότητα, κάτι θεμελιώδες έλειπε: οι ιδιότητες έχουν οριστεί αλλά οι μέθοδοι δεν έχουν καθοριστεί. Οπως αναμενόταν, Οι μέθοδοι αντικειμένων είναι συναρτήσεις, δεν έχουν όνομα και χρησιμοποιούνται (επικαλούνται) από το όνομα (ιδιότητα) που έχει εκχωρηθεί από τον ορισμό του αντικειμένου.
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”);
}
}
|
Στο προηγούμενο παράδειγμα, υπάρχει ήδη μια μέθοδος, "view_temperature", που εμφανίζει την τιμή της ιδιότητας "current_temperature" μέσω της κονσόλας. Δεν είναι πολύ χρήσιμο, αλλά δίνει μια πιο ολοκληρωμένη ιδέα για το πώς είναι ο ορισμός ενός αντικειμένου στο το JavaScript.
Για να αποκτήσετε πρόσβαση στις μεθόδους ενός αντικειμένου (συναρτήσεων) στις ιδιότητές του, χρησιμοποιήστε this
, όπως στο προηγούμενο παράδειγμα στη γραμμή 11, όταν χρησιμοποιείτε την ιδιότητα "current_temperature".
Πρόσβαση στο μοντέλο αντικειμένου εγγράφου (DOM) με JavaScript
από το JavaScript Έχετε πρόσβαση στο περιεχόμενο της ιστοσελίδας στην οποία εκτελείται, καθώς και σε ορισμένες πτυχές του προγράμματος περιήγησης που εμφανίζει αυτήν τη σελίδα, αν και όχι στους πόρους του συστήματος. Η δομή δεδομένων που υποστηρίζει τις ιδιότητες και τις μεθόδους από τις οποίες έχει πρόσβαση το JavaScript μέρος του αντικειμένου παραθύρου, συγκεκριμένα, το περιεχόμενο του αντικειμένου (το έγγραφο HTML) αντιστοιχεί στο αντικείμενο document
. Αν και μερικές φορές χρησιμοποιείται για λόγους σαφήνειας, δεν είναι απαραίτητο να προηγηθεί το παράθυρο των μεθόδων ή των ιδιοτήτων για να αναφερθείτε σε αυτές, αρκεί, για παράδειγμα, να χρησιμοποιήσετε document
, δεν χρειάζεται να γράψετε το όνομα του ριζικού αντικειμένου όπως στο window.document
, αρκεί να αναφέρεται το τρέχον παράθυρο.
Η πιο χρησιμοποιούμενη μορφή βρείτε ένα αντικείμενο μέσα στο έγγραφο HTML Είναι μέσω της μεθόδου getElementById()
, στο οποίο μεταβιβάζεται ως όρισμα το αναγνωριστικό που υποδείχθηκε κατά τη δημιουργία του κώδικα HTML. Από όσα εξηγήθηκαν σε προηγούμενες ενότητες, είναι εύκολο να υποθέσουμε ότι μπορείτε επίσης να έχετε πρόσβαση στα στοιχεία μέσα στο αντικείμενο document
χρησιμοποιώντας σύνταξη κουκκίδων (document.componente
) ή αγκύλες χρησιμοποιώντας και το όνομα (document["componente"]
), το πιο χρήσιμο, όπως το αριθμητικό ευρετήριο, δύσκολο στη χρήση και μη πρακτικό κατά την πρόσβαση στο περιεχόμενο μιας μη αυτόματης σύνθεσης ιστοσελίδας.
με το JavaScript μπορείτε λάβετε το στοιχείο που περιέχει ένα άλλο στοιχείο (στοιχείο ή γονικό κόμβο) συμβουλευτείτε την ιδιοκτησία σας parentNode
ή την περιουσία σας parentElement
, η διαφορά είναι ότι το γονικό στοιχείο (parentElement
) του τελικού στοιχείου της χορδής DOM Είναι μηδενικό (null
) και τον γονικό κόμβο (parentNode
) είναι το ίδιο το έγγραφο (document
).
να τροποποιήσετε το περιεχόμενο ενός στοιχείου HTML, για παράδειγμα αυτό μιας ετικέτας <div>
, Μπορεί να χρησιμοποιηθεί innerHTML
και για να αλλάξετε τις ιδιότητές του, μπορείτε να επιλέξετε να του αντιστοιχίσετε μια διαφορετική κλάση className
ή να αλλάξουν τις ιδιότητές του μεμονωμένα με style
. Το να συμβουλευτείτε το στυλ που εμφανίζεται από ένα στοιχείο στην ιστοσελίδα δεν είναι απαραίτητα χρήσιμο style
δεδομένου ότι μπορεί να εξαρτάται από πολλούς παράγοντες ή απλώς να μην έχει καθοριστεί ρητά. Για να ελέγξετε το στυλ ενός στοιχείου που τελικά εμφανίζεται στην ιστοσελίδα, χρησιμοποιείται η μέθοδος getComputedStyle.
Σε ένα στοιχείο εγγράφου HTML Μπορούν να του ανατεθούν διάφορες κατηγορίες για να προσδιοριστεί η εμφάνιση και η συμπεριφορά του, σε διαχείριση της λίστας των κλάσεων ενός αντικειμένου από το JavaScript μπορείτε να καταφύγετε classList
που προσφέρει τις μεθόδους add
για να προσθέσετε μια νέα τάξη στη λίστα, remove
να το αφαιρέσετε, toggle
για να το αντικαταστήσετε ή να συμβουλευτείτε το περιεχόμενο της λίστας κλάσης ενός στοιχείου με item
και contains
, το οποίο επιστρέφει την κλάση που καταλαμβάνει μια συγκεκριμένη θέση στη λίστα και μια τιμή true
o false
ανεξάρτητα από το αν μια συγκεκριμένη τάξη περιλαμβάνεται στη λίστα ή όχι.
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”)
}
|
Στο προηγούμενο παράδειγμα βρίσκεται με getElementById
το αντικείμενο που θέλετε να χειριστείτε (ένα στοιχείο <div>
για τον id
), πριν από την αλλαγή της εμφάνισης, το περιεχόμενο διαγράφεται με αντιστοίχιση με innerHTML
μια κενή συμβολοσειρά κειμένου, της εκχωρείται μια νέα κλάση className
και το στυλ του τροποποιείται με style
ανάλογα με την αξία του περιεχομένου (θερμοκρασία), αλλάζοντας το χρώμα, εάν ισχύει, μέσω της ιδιοκτησίας color
. Μόλις καθοριστεί η πτυχή, η τιμή γράφεται ξανά χρησιμοποιώντας innerHTML
.
Στο δεύτερο μέρος του παραπάνω παραδείγματος (γραμμές 9 έως 19) γίνεται πρόσβαση σε ένα στοιχείο κώδικα HTML χρησιμοποιώντας τη σύνταξη document[]
και ιδιοκτησίας id
του στοιχείου για να αλλάξει τη λίστα κλάσεων του με τη μέθοδο classList.remove()
και με τη μέθοδοclassList.add()
, με βάση το αποτέλεσμα πολλών ερωτημάτων που εκτελούνται σε εκτελέσεις υπό όρους, τις οποίες συγκρίνουν χρησιμοποιώντας classList.contains()
.
Πότε πρόκειται να αναφέρονται σε ένα στοιχείο HTML διάφοροι φορές σε όλο τον κώδικα το JavaScript, είναι λίγο πιο αποτελεσματικό να το αντιστοιχίσετε σε μια μεταβλητή ή χρησιμοποιήστε το ευρετήριό του αντί για το όνομα αφού, διαφορετικά, η μέθοδος που θα χρησιμοποιούσατε το JavaScript για να την αποκτήσετε κάθε φορά θα απαιτούσε την αναζήτηση του ονόματός της, καταναλώνοντας λίγο περισσότερο χρόνο από ό,τι αν υπήρχε πρόσβαση σε μια μεταβλητή.
να προσθέστε νέα αντικείμενα στο έγγραφο HTML, μπορούν να δημιουργηθούν πρώτα με τη μέθοδο createElement
de document
και αργότερα ενσωματώστε τα στα υπόλοιπα στοιχεία στο σημείο του δέντρου που είναι απαραίτητο με appendChild
. Για να δημιουργήσετε ένα αντικείμενο XML, σαν αντικείμενα SVG που χρησιμοποιούμε για να σχεδιάσουμε το γράφημα των αισθητήρων IoT, μπορείτε να χρησιμοποιήσετε createElementNS
(NS για χώρο ονόματος). Όπως εξηγείται όταν μιλάμε για τη μορφή SVG, ο χώρος ονομάτων που αντιστοιχεί σε αυτό (για την τρέχουσα έκδοση) είναι http://www.w3.org/2000/svg
, το οποίο πρέπει να περάσει στο createElementNS
ως όρισμα μαζί με τον τύπο του στοιχείου, svg
, σε αυτήν την περίπτωση.
ένα εναλλακτική λύση για innerHTML
για να προσθέσετε κείμενο ως περιεχόμενο σε ένα στοιχείο εγγράφου HTML είναι η μέθοδος createTextNode()
του αντικειμένου document
. Με αυτή την εναλλακτική μπορείτε δημιουργία νέου κειμένου (η οποία αποκτάται αργότερα πρόσβαση εάν εκχωρηθεί σε μια μεταβλητή) που ενσωματώνεται στο δέντρο αντικειμένων με τη μέθοδο appendChild()
. Όπως εναλλακτική λύση για appendChild()
, το οποίο προσθέτει το νέο περιεχόμενο στο τέλος αυτού που υπάρχει ήδη στον κόμβο στον οποίο προστίθεται, μπορείτε να χρησιμοποιήσετε η μέθοδος insertBefore()
, το οποίο προσθέτει ένα νέο αντικείμενο μπροστά από ένα υπάρχον. Φορούν insertBefore()
αντί για appendChild()
παρέχει μια μέθοδο που εξυπηρετεί, για παράδειγμα, σε ταξινομήστε νέα αντικείμενα μπροστά από υπάρχοντα όταν ένα στοιχείο πρέπει να βρίσκεται μπροστά από ένα άλλο (όπως σε μια λίστα) ή να καλύπτει ή να καλύπτεται σε μια γραφική δομή στην οποία υπάρχουν στοιχεία πιο κοντά στο προσκήνιο ή το φόντο.
Αντιδράστε σε συμβάντα με JavaScript
Όταν ο τρόπος του χρησιμοποιήστε μια ιστοσελίδα ως κοντέινερ για γραφήματα αισθητήρων που συνδέονται με το IoT χρησιμοποιήθηκε onload
Στην ετικέτα <body>
για να αρχίσετε να σχεδιάζετε το γράφημα. Αυτή η ιδιότητα, που σχετίζεται με τα αντικείμενα κώδικα HTML, αναφέρεται στο εκδηλώσεις το JavaScript. Όπως έχει ήδη εξηγηθεί, εκτελεί μια συνάρτηση όταν η σελίδα έχει φορτωθεί. Αν και έχει συσχετιστεί με τον κώδικα HTML για να το έχουμε κατά νου περισσότερο, θα μπορούσε να ήταν γραμμένο στον κώδικα το JavaScript ως body.onload=dibujar;
ύπαρξη dibujar
το όνομα της συνάρτησης που πρέπει να ξεκινήσει κατά τη φόρτωση της ιστοσελίδας.
Στις πιο πρόσφατες εκδόσεις του το JavaScript συμβάντα μπορούν να συσχετιστούν με συναρτήσεις χρησιμοποιώντας addEventListener
με τη μορφή objeto.addEventListener(evento,función);
ή χρησιμοποιώντας τη σύνταξη objeto.evento=función;
που λειτουργεί και σε παλαιότερες υλοποιήσεις. Για να αποσυνδέσετε τη συνάρτηση που σχετίζεται με το συμβάν, έχετε removeEventListener
που έχει την ίδια μορφή με addEventListener
.
το JavaScript Είναι ικανό να αντιδρά σε ένα πλήθος γεγονότων που μπορεί να συμβούν σε μια ιστοσελίδα. Για παράδειγμα, μπορεί να ανιχνεύσει πότε γίνεται κλικ σε ένα στοιχείο HTML με onmousedown
, ή όταν κάνετε κλικ με onclick
, όταν πατηθεί ένα πλήκτρο με onkeydown
, λειτουργώντας τη γραμμή κύλισης με onscroll
. Για τον σκοπό μας αρκεί να το κάνουμε ανίχνευση φόρτωσης σελίδας με onload
και η αλλαγή του μεγέθους του με onresize
. Θα συσχετίσουμε αυτά τα γεγονότα με τα αντικείμενα body
y window
del DOM αντίστοιχα. Το πρώτο μπορεί να αντιστοιχιστεί στον κωδικό HTML, όπως φαίνεται και το δεύτερο εντός του κώδικα το JavaScript μέσα στη συνάρτηση που καλείται από τον πρώτο και με τη μορφή window.onresize=redimensionar;
ύπαρξη redimensionar
η συνάρτηση που θα καλείται κάθε φορά που το παράθυρο αλλάζει μέγεθος.
Τρέξτε μετά από ένα χρονικό διάστημα
το JavaScript έχει δύο πόρους για αναβαλλόμενη εκτέλεση: setTimeout
, που εκτελεί μια συνάρτηση μετά από ένα χρονικό διάστημα και setInterval
που θα εκτελεί μια συνάρτηση κάθε συγκεκριμένο χρονικό διάστημα. Και οι δύο μέθοδοι απαιτούν ως παραμέτρους (1) την προκληθείσα συνάρτηση και (2) το χρονικό διάστημα εκφρασμένο σε χιλιοστά του δευτερολέπτου. Για να σταματήσετε τη λειτουργία τους, μπορείτε να αντιστοιχίσετε το αποτέλεσμα που επιστρέφεται από αυτές τις συναρτήσεις σε μεταβλητές και να τις μεταβιβάσετε ως όρισμα σε clearTimeout
ή clearInterval
όταν δεν θέλετε να τα επικαλέσετε ξανά (ή όταν δεν θέλετε να εκτελεστούν για πρώτη φορά) setTimeout
o setInterval
αντιστοίχως.
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
}
|
Στο προηγούμενο παράδειγμα παρουσιάζεται η μέθοδος alert
που χρησιμεύει για την εμφάνιση ενός προειδοποιητικού σήματος. Αν και χρησιμοποιήθηκε ευρέως στο παρελθόν, επί του παρόντος είναι σχεδόν απαγορευμένο από τον κώδικα το JavaScript λόγω του πόσο επιθετικό (παρεμβατικό) είναι να καλύψετε την ιστοσελίδα με ένα πλαίσιο διαλόγου.
Σε ένα πρόγραμμα που γράφτηκε για α μικροελεγκτής μιας μικρής σειράς (όπως αυτή στο πιάτο Arduino Uno) είναι σύνηθες να χρησιμοποιούνται καθολικές μεταβλητές, όπως στο προηγούμενο παράδειγμα in το JavaScript, καθώς ο κώδικας είναι σύντομος και δεν προκαλεί ιδιαίτερη σύγχυση, επειδή πολλές φορές οι συναρτήσεις υλοποιούνται ad hoc και επειδή η χρήση καθολικών μεταβλητών επιτρέπει την πρόβλεψη της χρήσης της μνήμης με πολύ απλό και διαισθητικό τρόπο, κάτι που είναι κρίσιμο σε συστήματα με λίγους πόρους. Αντι αυτου, en το JavaScript Είναι σύνηθες να μειώνεται η χρήση καθολικών μεταβλητών στο ελάχιστο δυνατό. γιατί δεν χρειάζεται βιαστική χρήση μνήμης, αφού τρέχει κανονικά σε α CPU με πόρους πολύ ανώτερους από αυτούς του α MCU, επειδή είναι πιθανό να συνυπάρχει με πολλούς κώδικα τρίτων με τους οποίους πρέπει να λειτουργεί χωρίς παρεμβολές και επειδή είναι ανοιχτό σύστημα, δεν μπορεί να προβλεφθεί το μελλοντικό πλαίσιο εκτέλεσης (το πρόγραμμα ενός μικροελεγκτής Το small καθορίζει πλήρως τη λειτουργία του χωρίς να προσθέτει περισσότερο κώδικα μόλις είναι σε λειτουργία) και επειδή οι διαστάσεις των εφαρμογών θα μπορούσαν να δυσκολέψουν την ανάγνωση εάν ο κώδικας δεν περικλείει τη λειτουργία του, καθιστώντας τις μεθόδους όσο το δυνατόν πιο αυτοτελείς.
Μαθηματικές πράξεις με το αντικείμενο JavaScript Math
Οι μαθηματικές πράξεις των πιο περίπλοκων μαθηματικών υπολογισμών ομαδοποιούνται στο αντικείμενο Math
. Αυτό το αντικείμενο χρησιμοποιείται απευθείας, δεν είναι απαραίτητο να δημιουργηθεί για να χρησιμοποιηθούν οι μέθοδοι ή οι ιδιότητες (σταθερές) που ενσωματώνει.
Math.abs(n)
Απόλυτη τιμή της παραμέτρου nMath.acos(n)
Αρκοζίνη της παραμέτρου n (αποτέλεσμα σε ακτίνια)Math.asin(n)
Τόξο της παραμέτρου n (αποτέλεσμα σε ακτίνια)Math.atan(n)
Τοξική εφαπτομένη της παραμέτρου n (αποτέλεσμα σε ακτίνια)Math.atan2(n,m)
Arctangent n/m (αποτέλεσμα σε ακτίνια)Math.ceil(n)
Στρογγυλοποιήστε την παράμετρο στον πλησιέστερο ακέραιο προς τα πάνωMath.cos(α)
Συνημίτονο της παραμέτρου α (α σε ακτίνια)Math.E
αριθμός e (≃2.718281828459045)Math.exp(n)
e ανυψώθηκε στην παράμετρο n: enMath.floor(n)
Στρογγυλοποιήστε την παράμετρο n στον πλησιέστερο ακέραιο προς τα κάτωMath.log(n)
Φυσικός λογάριθμος (βάση ε) της παραμέτρου nMath.LN2
Φυσικός λογάριθμος (βάση ε) του 2 (≃0.6931471805599453)Math.LN10
Φυσικός λογάριθμος (βάση ε) του 10 (≃2.302585092994046)Math.LOG2E
Βάση 2 λογάριθμος του e (≃1.4426950408889634)Math.LOG10E
Βάση 10 λογάριθμος του e (≃0.4342944819032518)Math.max(a,b,c,…)
Μεταβιβάστηκε η μεγαλύτερη τιμή της λίστας παραμέτρωνMath.min(a,b,c,…)
Η μικρότερη τιμή της λίστας παραμέτρων που έχει περάσειMath.PI
Αριθμός π (≃3.141592653589793)Math.pow(n,m)
Πρώτη παράμετρος n αυξήθηκε στη δεύτερη παράμετρο m: nmMath.random()
(Σχεδόν) τυχαίος αριθμός μεταξύ 0.0 και 1.0Math.round(n)
Στρογγυλοποιήστε την παράμετρο n στον πλησιέστερο ακέραιοMath.sin(α)
Ημίτονο της παραμέτρου α (α σε ακτίνια)Math.sqrt(n)
Τετραγωνική ρίζα της παραμέτρου nMath.SQRT1_2
Τετραγωνική ρίζα 1/2 (≃0.7071067811865476)Math.SQRT2
Τετραγωνική ρίζα 2 (≃1.4142135623730951)Math.tan(α)
Εφαπτομένη της παραμέτρου α (α σε ακτίνια)
Φόρτωση δεδομένων από διακομιστή με AJAX
Η μέθοδος που ακολουθείται για την κατάρτιση των πληροφοριών που είναι αποθηκευμένες στο IoT συνίσταται στη φόρτωση των δεδομένων από τον διακομιστή κατά διαστήματα και στην εκ νέου σχεδίαση του γραφήματος με το οποίο αντιπροσωπεύονται. Για την ανάγνωση δεδομένων από τον διακομιστή, χρησιμοποιείται τεχνολογία AJAX (Ασύγχρονη JavaScript και XML) μέσα από ένα αντικείμενο XMLHttpRequest
de το JavaScript. Η γραφική παράσταση του γραφήματος δεδομένων γίνεται με την επαναχρησιμοποίηση ενός αντικειμένου SVG που υπάρχει ήδη στον κωδικό HTML και περιέχει ένα γράφημα του οποίου οι συντεταγμένες έχουν τροποποιηθεί ώστε να αντιστοιχούν στα νέα δεδομένα που έχουν φορτωθεί.
Στο παράδειγμα αυτής της πρότασης, εκτός από την ενημέρωση του σχεδίου, ενημερώνεται επίσης ένα κείμενο στην ιστοσελίδα που δείχνει την ημερομηνία και την τιμή των τελευταίων δεδομένων μέτρησης για κάθε γράφημα.
Στην πλευρά του διακομιστή υπάρχει μια βάση δεδομένων που περιέχει τις πληροφορίες ότι οι αισθητήρες που είναι συνδεδεμένοι στο IoT παρακολουθούν. Αυτή η βάση δεδομένων διαβάζεται από το αίτημα αντικειμένου XMLHttpRequest
απαντώντας με πληροφορίες κωδικοποιημένες στο Μορφή JSON, αν και το όνομα της μεθόδου που χρησιμοποιείται υποδηλώνει μια σχέση με τη μορφή XML.
Στο πρώτο σεμινάριο polaridad.es για το Αποθήκευση δεδομένων IoT Μπορείτε να δείτε ένα παράδειγμα υποδομής για τη διαχείριση, από την πλευρά του διακομιστή, των πληροφοριών που παρέχονται από συσκευές συνδεδεμένες στο Internet of Things. Σε αυτήν τη σειρά άρθρων ένας διακομιστής χρησιμοποιείται ως πόρος Apache από το οποίο μπορείτε να χρησιμοποιήσετε τη γλώσσα προγραμματισμού PHP για πρόσβαση σε μια βάση δεδομένων MySQL o MariaDB. Σε διακομιστές που χρησιμοποιούνται για την υποστήριξη IoT είναι πολύ συνηθισμένο να βρίσκουμε βάσεις δεδομένων MongoDB (NoSQL) και τη γλώσσα προγραμματισμού το JavaScript επί Node.js ως υποδομή λογισμικού.
Η επόμενη λειτουργία είναι υπεύθυνη για την αίτηση των πιο πρόσφατων δεδομένων από έναν από τους αισθητήρες από τον διακομιστή. Στην κλήση συνάρτησης, το αντικείμενο χρησιμοποιείται ως όρισμα το JavaScript που υποστηρίζει τα δεδομένα που σχεδιάζονται. Εάν το ίδιο γράφημα αντιπροσωπεύει πολλές τιμές, για παράδειγμα για οπτική αναζήτηση για μια συσχέτιση, μπορεί να ζητηθεί από τον διακομιστή να επιστρέψει πολλές ταυτόχρονα, μια πιο βέλτιστη μέθοδος λόγω του τρόπου λειτουργίας του διακομιστή. Πρωτόκολλο 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);
}
|
Στην τρίτη γραμμή του προηγούμενου παραδείγματος, προετοιμάζεται το ερώτημα που θα γίνει στον διακομιστή, στο οποίο θα μεταβιβαστεί το όρισμα "zone", η τιμή του οποίου θα είναι το όνομα ή ο κωδικός του τόπου παρακολούθησης, καθώς πληροφορίες σχετικά με το περιοχή μπορεί να συνυπάρχει στην ίδια βάση δεδομένων διαφορετικοί αισθητήρες (για παράδειγμα, θερμόμετρα που μετρούν τη θερμοκρασία σε διαφορετικούς χώρους). Η παράμετρος που μεταβιβάστηκε στην προηγούμενη συνάρτηση, το αντικείμενο με τα δεδομένα γραφήματος, αναμένεται να περιλαμβάνει μια ιδιότητα με το όνομα του δωματίου ("όνομα_κατάληξη").
Μεταξύ των γραμμών 7 και 14 του προηγούμενου κώδικα, το αντικείμενο XMLHttpRequest
η οποία αποθηκεύεται στη μεταβλητή "ajax". Πριν επιλέξετε πώς να δημιουργήσετε το αντικείμενο, κάνετε αναζήτηση window
αν XMLHttpRequest
δεν ήταν διαθέσιμο (κάτι που συνέβη σε παλιές εκδόσεις του εξερευνητή της Microsoft και παρόλο που είναι πολύ πίσω, χρησιμεύει ως παράδειγμα εναλλακτικών λύσεων για τη δημιουργία του αντικειμένου χρησιμοποιώντας την (πιο εγγενή) σύνταξη. Object.create
o new
, παρόμοια με αυτή άλλων αντικειμενοστρεφών γλωσσών.
Για να μπορέσετε να διαχειριστείτε την απόκριση αμέσως, ο κώδικας που τη χειρίζεται προετοιμάζεται στις γραμμές 15 έως 26 πριν υποβάλετε το αίτημα στον διακομιστή.
Ο τρόπος εκτελέστε το ερώτημα HTTP στον διακομιστή αποτελείται από ανοίξτε μια σύνδεση με open
με ένδειξη τύπου και σελίδας (προαιρετικά όνομα χρήστη και κωδικός πρόσβασης), προετοιμάστε τις κεφαλίδες του πρωτοκόλλου με setRequestHeader
y στείλετε το αίτημα με send
. Η κεφαλίδα HTTP Content-length
θα πρέπει να γνωρίζετε το μήκος του ερωτήματος (αριθμός χαρακτήρων) που υπολογίζεται χρησιμοποιώντας length
.
Όταν το αίτημα AJAX είναι έτοιμο, εκτελείται η συνάρτηση που σχετίζεται με το συμβάν onreadystatechange
. Αντί να εκχωρηθεί μια συνάρτηση, στο προηγούμενο παράδειγμα ορίζεται μια ανώνυμη συνάρτηση on the fly που θα διαχειρίζεται τη λήψη δεδομένων που φτάνουν από τον διακομιστή. Πρώτα απ 'όλα, στη γραμμή 18, επαληθεύεται ότι η κατάσταση του αιτήματος είναι "ολοκληρώθηκε", η οποία αντιστοιχεί στην τιμή 4
του ακινήτου readyState
, ότι η κατάσταση είναι "OK" του Πρωτόκολλο HTTP (κώδικας 200
) που μπορείτε να προμηθευτείτε από το ακίνητο status
και ότι τα δεδομένα που έχουν φτάσει είναι Μορφή JSON, συμβουλευτείτε το ακίνητο responseType
.
Μόλις επαληθευτεί ότι η κατάσταση της απάντησης είναι η αναμενόμενη, στη γραμμή 20 του προηγούμενου παραδείγματος δημιουργεί ένα αντικείμενο με το αποτέλεσμα, μετατρέποντας το κείμενο JSON. Στην απάντηση, αναμένεται να επιστραφεί μια ημερομηνία, η οποία μας επιτρέπει να δούμε αν το αποτέλεσμα που στέλνει ο διακομιστής είχε ήδη αναπαρασταθεί στο γράφημα, το οποίο επαληθεύεται στη γραμμή 21. Εάν τα δεδομένα είναι νέα, στη γραμμή 23 καλείται η συνάρτηση που είναι υπεύθυνη για την επανασχεδίαση του γραφήματος με τις νέες πληροφορίες.
Η ιδέα όταν προτείνεται αυτή η μέθοδος ανάγνωσης είναι ότι τα δεδομένα θα ανανεώνονται πολύ συχνά. Εάν οι πληροφορίες που παρουσιάζονται αντιστοιχούν σε μακροπρόθεσμη βάση (όπως οι θερμοκρασίες μιας ημέρας ή μιας εβδομάδας), μπορεί να εφαρμοστεί ένα αρχικό αίτημα που συλλέγει όλα τα διαθέσιμα δεδομένα και στη συνέχεια ένα, παρόμοιο με αυτό στο παράδειγμα, που το ενημερώνει σε ο ανταποκριτής της περιόδου.
Δημιουργήστε τυχαία δεδομένα για δοκιμή
Όταν όλη η υποδομή διακομιστή και πελάτη είναι έτοιμη, μια συνάρτηση όπως αυτή στην προηγούμενη ενότητα θα είναι υπεύθυνη για την ανάγνωση των δεδομένων και τη σχεδίαση του γραφήματος με αυτά, αλλά Στη φάση της δοκιμής μπορεί να είναι πιο πρακτικό να χρησιμοποιείτε τυχαίους αριθμούς μέσα σε ένα ελεγχόμενο εύρος για να δούμε αν ο κώδικας που γράφεται είναι σωστός. Η παρακάτω συνάρτηση μπορεί να χρησιμεύσει ως παράδειγμα για τη λήψη δεδομένων κατά την κατασκευή της τελικής εφαρμογής.
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);
}
|
Αντί να διαβάζει τις πληροφορίες από μια βάση δεδομένων, το παραπάνω παράδειγμα τις δημιουργεί τυχαία και τις μεταβιβάζει στη συνάρτηση που είναι υπεύθυνη για τη σχεδίαση του γραφήματος. Τα δεδομένα που επινοήθηκαν είναι ένα διάνυσμα που σχηματίζεται από μια ημερομηνία που εκφράζεται ως τιμή σε χιλιοστά του δευτερολέπτου, τη στιγμή της καταγραφής των πληροφοριών του αισθητήρα και τα δεδομένα παρακολούθησης, τα οποία είναι μεταξύ μιας μέγιστης τιμής και μιας ελάχιστης τιμής.
Σε αυτό το παράδειγμα, κατά τη δημιουργία μιας ημερομηνίας μπορεί να καθυστερήσει έως και ένα δευτερόλεπτο (1000 χιλιοστά του δευτερολέπτου) σε σχέση με την ημερομηνία τη στιγμή της εφεύρεσης. Οπως και Math.random()
δημιουργεί έναν αριθμό μεταξύ 0.0 και 1.0, πολλαπλασιάζοντάς τον με το 1000 δημιουργείται ένας αριθμός μεταξύ 0 και 1000 ο οποίος στη συνέχεια μετατρέπεται σε ακέραιο. Με τον ίδιο τρόπο, η τιμή προκύπτει πολλαπλασιάζοντας τον τυχαίο αριθμό με το εύρος (μέγιστο μείον ελάχιστο) και προσθέτοντας το ελάχιστο.
Σχεδιάστε το γράφημα των αισθητήρων IoT με μια γραφική παράσταση SVG
Εφόσον είδαμε πώς μπορούμε να λάβουμε τις τιμές που θέλουμε να αναπαραστήσουμε (θερμοκρασία, στο παράδειγμα) και τη χρονική τους θέση, οι οποίες μπορούν να εκφραστούν μαζί με τη μορφή συντεταγμένων, το παρακάτω παράδειγμα δείχνει μια συνάρτηση για να σχεδιάσετε μια διαδρομή που ενώνει αυτά τα σημεία και προαιρετικά μια έγχρωμη περιοχή που οριοθετείται από αυτή τη γραμμή στην κορυφή. Το αποτέλεσμα θα ήταν όπως η παρακάτω εικόνα.
Ο οριζόντιος άξονας (X) του γραφήματος αντιπροσωπεύει το χρόνο και ο κατακόρυφος άξονας (Y) τις τιμές που παρακολουθούσαν οι αισθητήρες που είναι συνδεδεμένοι στο IoT. Το οριζόντιο διάστημα είναι μερικά δευτερόλεπτα αφού σε αυτήν την πρόταση το γράφημα ενημερώνεται πολύ συχνά (κάθε δευτερόλεπτο, για παράδειγμα) για να παρέχει πληροφορίες σχεδόν σε πραγματικό χρόνο για την κατάσταση των αισθητήρων.
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
}
|
Στον προηγούμενο κώδικα υπάρχουν δύο ενδιαφέρουσες πτυχές, πρώτον ο υπολογισμός που επιτρέπει προσαρμόστε το εύρος των τιμών που αντιπροσωπεύονται και δεύτερον το κατασκευή ακινήτου d
που δείχνει τις συντεταγμένες των σημείων στη διάταξη (path
).
Για να προσαρμόσουν το εύρος των τιμών που αντιπροσωπεύονται, μετακινούνται από το ελάχιστο και κλιμακώνονται έτσι ώστε το ορατό μέγεθος να αντιστοιχεί στο μέγεθος του γραφήματος. Στην περίπτωση του χρόνου, η μετατόπιση λαμβάνεται αφαιρώντας το εύρος που θέλετε να εμφανίσετε από τον μεγαλύτερο χρόνο (η ημερομηνία και ώρα που είναι πλησιέστερα στην τρέχουσα) (20 δευτερόλεπτα στο παράδειγμα). Η μετατόπιση των τιμών θερμοκρασίας είναι αυτή του χαμηλότερου εύρους (ένας βαθμός) μείον τη χαμηλότερη τιμή, έτσι ώστε τα δεδομένα που φαίνονται παρακάτω να είναι τα πιο παρόμοια με τη χαμηλότερη επιτρεπόμενη τιμή, αλλά αφήνοντας ένα περιθώριο που μας επιτρέπει να εκτιμήσουμε τι περνάει
Ο συντελεστής που πολλαπλασιάζει τις τιμές χρόνου για να ληφθούν οι οριζόντιες συντεταγμένες του γραφήματος προκύπτει διαιρώντας το συνολικό πλάτος του γραφήματος (100 μονάδες στο παράδειγμα) με το χρονικό εύρος που αντιπροσωπεύεται (20 δευτερόλεπτα στο παράδειγμα). Για να ληφθεί ο συντελεστής με τις βαθμωτές τιμές θερμοκρασίας, πρέπει να θυμόμαστε ότι το εύρος που αντιπροσωπεύεται πηγαίνει από ένα περιθώριο κάτω από την ελάχιστη τιμή σε ένα περιθώριο πάνω από το μέγιστο, ένα βαθμό και στις δύο περιπτώσεις. Με αυτόν τον τρόπο, ο συντελεστής κατακόρυφης κλίμακας προκύπτει από τη διαίρεση του ύψους του γραφήματος (100 μονάδες στο παράδειγμα) με τη μέγιστη τιμή, μείον το ελάχιστο συν το άνω και κάτω περιθώριο. Δεδομένου ότι αυτές οι τιμές θα μπορούσαν να αναπτυχθούν εντελώς σε αρνητικές θερμοκρασίες, χρησιμοποιούμε Math.abs()
να χρησιμοποιήσουμε την απόλυτη τιμή της διαφοράς.
Η ιδιοκτησία d
του αντικειμένου path
Κατασκευάζεται με τη συνένωση των συντεταγμένων των σημείων σε ένα κείμενο. Κάθε ζεύγος συντεταγμένων προηγείται από έναν κωδικό SVG L
, που τραβάει μια γραμμή από την τρέχουσα θέση σε μια απόλυτη τιμή που υποδεικνύεται από τις συντεταγμένες. Οι τιμές X και Y διαχωρίζονται με κόμμα και κάθε λειτουργία SVG χωρίζεται από ένα κενό από το επόμενο.
Για να ξεκινήσετε τη διάταξη, χρησιμοποιήστε τον κωδικό M
(μετακίνηση σε απόλυτη συντεταγμένη). Στην περίπτωση του κλειστού και γεμάτου γραφήματος, ξεκινάτε από κάτω δεξιά, στην περίπτωση του ανοιχτού γραφήματος που σχεδιάζει το προφίλ δεδομένων, ξεκινάτε με την τελευταία τιμή που αναπαρίσταται (την πιο πρόσφατη). Για να ολοκληρωθεί η κλειστή διάταξη, χρησιμοποιείται ο κωδικός Z
προσθέτοντας ως τελευταίο σημείο εκείνο που έχει την ίδια τιμή συντεταγμένων Χ με το τελευταίο σημείο της ευθείας και ως συντεταγμένη Υ τη μικρότερη τιμή που αναπαρίσταται.
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
);
}
|
Σε αυτό το παράδειγμα, η συνάρτηση dibujar_grafico()
, που είναι η κλήση κατά τη φόρτωση σελίδας, λαμβάνει τις αρχικές τιμές για δοκιμή (όχι την τελευταία τιμή σε πραγματικό χρόνο) και προετοιμάζει το εύρος στο οποίο θα αποδοθούν τα δεδομένα: 20 δευτερόλεπτα (20000 ms) οριζόντια και 15 °C σε κατακόρυφα από -5°C έως +10°C με περιθώριο πάνω και κάτω μία μοίρα. Πραγματοποιήστε δύο κλήσεις σε actualizar_grafico()
, στο πρώτο πέρασμα true
ως όρισμα, το οποίο υποδεικνύει ότι το γράφημα πρέπει να είναι κλειστό για να αντιπροσωπεύει μια γεμάτη περιοχή και στη δεύτερη κλήση περνά false
για να τραβήξετε τη γραμμή. Σε κάθε περίπτωση, το αντικείμενο path
τροποποιημένο είναι αυτό που έχει την αντίστοιχη εμφάνιση, με γέμισμα και χωρίς περίγραμμα στην πρώτη περίπτωση και με συγκεκριμένο πάχος γραμμής και χωρίς γέμισμα στη δεύτερη.
Η λειτουργία actualizar_grafico()
εργασία σε ένα αντικείμενο SVG που χρησιμοποιεί τον παρακάτω κώδικα ως κοντέινερ HTML. Το αντικείμενο SVG περιέχει δύο μονοπάτια, ένα για να σχεδιάσει τη γραμμή και ένα άλλο για να σχεδιάσει την γεμάτη περιοχή. Κατά τη φόρτωση της ιστοσελίδας, από το στοιχείο <body>
η προηγούμενη συνάρτηση καλείται αυτόματα, dibujar_grafico()
χάρη στην εκδήλωση το 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>
|
Στη γραμμή 10 του κώδικα HTML Πάνω, ένα πλάτος (για παράδειγμα) 820 px και ένα ύψος 150 px καθορίζεται στο στυλ (κάτι που, στην τελική έκδοση, θα ήταν σκόπιμο να γίνει με μια τάξη και ένα έγγραφο CSS). Φαίνεται περίεργο ότι οι γραμμές 13 και 14 ορίζουν το μέγεθος του αντικειμένου SVG όπως 100% πλάτος και ύψος (που ταιριάζει καλύτερα με τις διαστάσεις του παραθύρου, 100×100). Όπως ήδη αναφέρθηκε, ο λόγος για να το κάνετε αυτό είναι να εργάζεστε πάντα με γνωστές διαστάσεις και να προσαρμόζετε τις αντιπροσωπευόμενες τιμές σε αυτό. Οι άλλες εναλλακτικές λύσεις θα ήταν να υπολογίζεται ο χώρος του γραφήματος κάθε φορά και στη συνέχεια να αναπροσαρμόζονται οι τιμές ή οι σταθερές διαστάσεις για το γράφημα, στις οποίες θα πρέπει να τηρεί το έγγραφο.
Έχοντας επιλέξει ένα γράφημα του οποίου οι διαστάσεις αλλάζουν ανάλογα με τον κώδικα HTML, είναι απαραίτητο να συμπεριληφθεί το ακίνητο vector-effect
με το θάρρος non-scaling-stroke
για να αποτρέψετε την παραμόρφωση του πάχους των γραμμών όταν το γράφημα δεν διατηρεί τις επιλεγμένες αναλογίες 1:1 στην ιστοσελίδα στην οποία εμφανίζεται, όπως συμβαίνει στην προηγούμενη πρόταση.
Για να "περικόψετε" το γράφημα και να εμφανίσετε μόνο την περιοχή που επιλέγετε, χρησιμοποιήστε viewBox
. Σε αυτήν την περίπτωση επιλέξαμε να δούμε το τμήμα του γραφήματος που ξεκινά από το 0,0 (πάνω αριστερή γωνία) και έχει διαστάσεις 100x100 προς τα κάτω και προς τα δεξιά. Το τμήμα του σχεδίου που βρίσκεται σε συντεταγμένες με αρνητικές τιμές ή μεγαλύτερες από 100 δεν θα εμφανίζεται στην ιστοσελίδα ακόμα κι αν υπάρχουν στο αντικείμενο SVG
Προσθέστε νέα στοιχεία στο σχέδιο SVG
Στο προηγούμενο παράδειγμα, η συνάρτηση actualizar_grafico()
χρησιμοποιήστε μια διάταξη SVG στην οποία μεταβάλλεται η ιδιοκτησία d
, που είναι αυτό που εκφράζει την αλυσίδα συντεταγμένων. Η εναλλακτική θα ήταν να δημιουργείτε ολόκληρο το αντικείμενο κάθε φορά που επανασχεδιάζεται. Το πλεονέκτημα της πρώτης επιλογής είναι ότι η γραφική εμφάνιση (όπως πάχος ή χρώμα) ορίζεται στον κώδικα HTML, ο περιορισμός είναι ότι τα αντικείμενα πρέπει να έχουν δημιουργηθεί προηγουμένως.
Για να δημιουργήσετε αντικείμενα SVG, χρησιμοποιήστε createElementNS()
, το οποίο επιτρέπει τη συμπερίληψη του χώρο ονομάτων. Στο παρακάτω παράδειγμα δημιουργείται ένα νέο αντικείμενο κειμένου (text
) και σχετίζεται με ένα στοιχείο SVG που υπάρχει ήδη στον κώδικα HTML της ιστοσελίδας. Μόλις δημιουργηθεί το νέο στοιχείο, οι ιδιότητές του εκχωρούνται με setAttribute()
και προστίθεται σε SVG με 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]);
|
Τροποποίηση της αναλογίας των στοιχείων σχεδίασης
Εάν δοκιμάσατε να βάλετε ετικέτες με τη συνάρτηση στο παράδειγμα στην προηγούμενη ενότητα, θα έχετε δει ότι το κείμενο εμφανίζεται παραμορφωμένο όταν η αναλογία του αντικειμένου στην ιστοσελίδα (width
y height
Του κώδικα HTML) δεν είναι ίσο με αυτό της περιοχής που αντιπροσωπεύεται (viewBox
). Για την προσαρμογή της αναλογίας είναι απαραίτητο να γνωρίζουμε τις μετρήσεις του αντικειμένου SVG για το οποίο μπορείτε να συμβουλευτείτε το στυλ του αντικειμένου ή το δοχείο HTML, εάν το αντικείμενο SVG μεταβίβαση αυτής της ιδιοκτησίας. Εκχώρηση ιδιοκτησίας transform
σε αντικείμενα SVG που εξαρτώνται από την αναλογία, η παραμόρφωση μπορεί να διορθωθεί εφαρμόζοντας μια λειτουργία κλιμάκωσης scale()
στην οποία ο συντελεστής στο Χ είναι διαφορετικός από αυτόν στο Υ.
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 επιτρέπει την ομαδοποίηση πολλών αντικειμένων σχηματίζοντας ένα νέο σύνθετο στοιχείο που υποστηρίζει επίσης ιδιότητες, όπως απλά αντικείμενα. Για να εφαρμόσετε τον ίδιο μετασχηματισμό σε μια σειρά αντικειμένων ταυτόχρονα αντί για κάθε αντικείμενο ξεχωριστά, μπορείτε να τα ομαδοποιήσετε σύμφωνα με αυτόν τον πόρο και να εφαρμόσετε μια μεμονωμένη ιδιότητα transform
σε όλους αυτούς.
Όπως εξηγείται όταν μιλάμε για Μορφή SVG, τα στοιχεία μιας ομάδας περικλείονται μέσα στις ετικέτες <g>
y </g>
. Για προσθήκη από το JavaScript στοιχεία σε μια ομάδα SVG χρησιμοποιείται, όπως φαίνεται στο προηγούμενο παράδειγμα, appendChild()
μόλις οριστεί το νέο αντικείμενο.
Για να καθορίσετε μια προέλευση κατά την εφαρμογή μετασχηματισμών, η ιδιότητα μπορεί να χρησιμοποιηθεί σε αντικείμενα SVG transform-origin
, του οποίου η τιμή είναι οι συντεταγμένες X και Y του σημείου από το οποίο ξεκινά ο μετασχηματισμός. Εάν μια τιμή για την αρχή του μετασχηματισμού δεν αναφέρεται ρητά (στο πρόγραμμα περιήγησης ιστού), χρησιμοποιείται το κέντρο των συντεταγμένων. Δυστυχώς, τη στιγμή της γραφής, ο καθορισμός της συμπεριφοράς των μετασχηματισμών χρησιμοποιώντας μια πηγή διαφορετική από την προεπιλεγμένη δεν είναι ομοιογενής μεταξύ των προγραμμάτων περιήγησης και θα πρέπει να χρησιμοποιείται με προσοχή.
Μαζί με τον μετασχηματισμό κλίμακας με scale
Υπάρχουν και άλλα, όπως η περιστροφή με rotation
και η κίνηση με translate
, που προσφέρουν α εναλλακτική στην αναπαράσταση γραφήματος: αντί να λάβετε νέες συντεταγμένες, μπορείτε να τις αναπαραστήσετε στον δικό τους χώρο και να μετατρέψετε το γράφημα ώστε να ταιριάζει στη μορφή στην οποία θέλετε να τις αναπαραστήσετε.
Προσθέστε αναφορές στο γράφημα
Τώρα που το κύριο μέρος του γραφήματος επιλύεται σχεδιάζοντας τις τιμές με ένα προφίλ και μια γεμάτη περιοχή, μπορεί να συμπληρωθεί με αναφορές που βοηθούν στην ανάγνωσή του. Για παράδειγμα, ας ξεκινήσουμε σχεδιάζοντας μερικές οριζόντιες αναφορές (γραμμές) που επισημαίνουν τις μέγιστες και ελάχιστες αποδεκτές τιμές καθώς και μια επιθυμητή τιμή. Όπως εξηγήθηκε, μπορείτε να επιλέξετε να προσθέσετε τα αντικείμενα στο SVG κατευθείαν από το JavaScript ή να τα συμπεριλάβετε χειροκίνητα στον κώδικα HTML και να τα τροποποιήσετε αργότερα με το 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();
|
Φαίνεται λογικό να επισημαίνονται αυτές οι οριζόντιες αναφορές με κείμενο που διευκρινίζει την τιμή που αντιπροσωπεύουν. Για να επισημάνετε το κείμενο, μπορείτε να χρησιμοποιήσετε ορθογώνια που θα ξεχωρίζουν από το φόντο και το γραφικό. Καθώς τα κείμενα θα πρέπει να κλιμακωθούν για να αντισταθμίσουν την παραμόρφωση, μπορούν όλα να ομαδοποιηθούν σε ένα αντικείμενο στο οποίο θα εφαρμοστεί η κλίμακα. Το κύριο πλεονέκτημα του να γίνει αυτό είναι να μπορείς να τα τροποποιήσεις με μία μόνο λειτουργία, εάν το κοντέινερ γραφήματος (το παράθυρο του προγράμματος περιήγησης) αλλάξει μέγεθος και αλλάξει την αναλογία που διορθώνει η κλίμακα.
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();
|
Υπάρχουν πολλές ενδιαφέρουσες πτυχές στο παραπάνω παράδειγμα κώδικα. Πρώτα απ 'όλα, σχολιάστε ότι έχουν χρησιμοποιηθεί σταθερές (καθολικές μεταβλητές) για να κάνουν το παράδειγμα πιο ευανάγνωστο στους χρήστες που προέρχονται από τον προγραμματισμό. μικροελεγκτές en C ή C + +. Όπως θα φανεί αργότερα, ο βέλτιστος τρόπος προγραμματισμού του το JavaScript Θα ήταν η χρήση αντικειμένων που θα περιέχουν αυτές τις τιμές και τις μεθόδους που θα διαχειρίζονταν τις αναφορές σε αυτό το παράδειγμα ή το γράφημα, γενικά, σε ένα σύστημα παραγωγής.
Από την άλλη πλευρά, προωθώντας ποιο θα ήταν ο πιο γενικός κώδικας, έχουν αναπτυχθεί ξεχωριστές συναρτήσεις που υπολογίζουν τους διαφορετικούς συντελεστές που διορθώνουν την αναλογία του γραφήματος για να προσαρμόσουν το κείμενο proporcion_grafico()
, την κλίμακα των τιμών ανάλογα με το εύρος τους escala()
και συντελεστή διόρθωσης για μετρήσεις που είναι γνωστές σε απόλυτη τιμή, όπως μετρήσεις σε αναφορές medida_grafico()
.
Η ανάγνωση αυτού του κώδικα θα βοηθήσει να διευκρινιστεί το πλαίσιο στο οποίο λειτουργεί μια εφαρμογή όπως αυτή, η οποία σχεδιάζει γραφικά σε πραγματικό χρόνο και πρέπει να είναι ευέλικτη ώστε να παρουσιάζεται σε διάφορα γραφικά περιβάλλοντα (διάφορα μεγέθη και αναλογίες, τουλάχιστον). Πρώτα απ 'όλα, τα αντικείμενα πρέπει να δημιουργηθούν SVG, είτε "χειροκίνητα" στον κώδικα HTML, είτε μέσω κώδικα το JavaScript και σε κάθε περίπτωση, οι αναφορές σε αυτά τα αντικείμενα πρέπει στη συνέχεια να λαμβάνονται για να τα χειριστείτε από το JavaScript ώστε να μπορούν να σχεδιαστούν νέα γραφήματα και η αναπαράσταση ενός ήδη σχεδιασμένου γραφήματος να μπορεί να προσαρμοστεί σε μια αλλαγή στο μέσο στο οποίο παρουσιάζεται.
Μια άλλη αναφορά που μπορεί να βοηθήσει στην εύκολη ερμηνεία ενός γραφήματος είναι τα σημεία που αντιπροσωπεύουν συγκεκριμένες τιμές (οι κόμβοι της γραμμής). Σε αυτό το παράδειγμα, στο οποίο αντιπροσωπεύουμε ένα μεμονωμένο μέγεθος, η επιλογή ενός συμβόλου δεν είναι κρίσιμη, αλλά εάν πολλές διαφορετικές τιμές υπερτίθενται για την αναζήτηση συσχέτισης, είναι ενδιαφέρον να γίνει διάκριση, εκτός από τη χρήση άλλων πόρων, όπως το χρώμα , σχεδιάζοντας διαφορετικά σύμβολα. Τα γραφικά που χρησιμοποιούνται για τον κόμβο γραμμής πρέπει να τροποποιηθούν σε μέγεθος και αναλογία, όπως συμβαίνει, για παράδειγμα, με τα κείμενα, έτσι ώστε οι διαστάσεις του να είναι απόλυτες και ώστε οι αναλογίες του να διατηρούνται ακόμη και αν αλλάξουν αυτές του πλαισίου που περιέχει.
Στο προηγούμενο παράδειγμα είδαμε ήδη πώς να υπολογίσουμε τους διαφορετικούς συντελεστές για να επανακλιμακωθεί και να διορθωθεί η αναλογία του σχεδίου. Όσον αφορά τον τρόπο υλοποίησης της διαχείρισης των συμβόλων των κόμβων ή των κορυφών του γραφήματος, μια πιθανή λύση μπορεί να είναι η αποθήκευση των αντικειμένων SVG σε ένα διάνυσμα και τροποποιήστε τη θέση του όταν το γράφημα ενημερώνεται διαβάζοντας μια νέα τιμή ή όταν επανασχεδιάζεται με αλλαγή του μεγέθους του κοντέινερ. Στην πρώτη περίπτωση θα έπρεπε να τροποποιηθεί η θέση του και στη δεύτερη η αναλογία του με το ακίνητο transform
και η αξία του scale
. Ο παρακάτω κώδικας είναι μια τροποποίηση της συνάρτησης actualizar_grafico()
να περιλαμβάνει επανατοποθέτηση των συμβόλων κορυφής του γραφήματος.
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);
}
}
|
Τροποποιήσεις που έγιναν στη λειτουργία actualizar_grafico()
για να λάβετε τη νέα λειτουργία actualizar_grafico_puntos()
Είναι αυτά που επισημαίνονται στον κώδικα του προηγούμενου παραδείγματος. Αρχικά, στη γραμμή 5, παίρνουμε ένα διάνυσμα αντικειμένων SVG ως παράμετρος. Αυτό το διάνυσμα θα περιέχει τα σύμβολα που πρέπει να επανατοποθετηθούν στους νέους κόμβους του γραφήματος.
Στις γραμμές 39 και 40 εκχωρούνται οι νέες συντεταγμένες του κέντρου, cx
y cy
, σε εκείνες των αξιών που αντιπροσωπεύονται. Εάν το σύμβολο δεν βασιζόταν στο κέντρο, πιθανότατα θα χρειαστεί να προσθέσετε μια μετατόπιση cx
το μισό πλάτος και μέσα cy
του μισού ύψους για να τα επανατοποθετήσετε ακριβώς στον κόμβο του γραφήματος.
Στις γραμμές 57 έως 61, τα σημεία που αντιστοιχούν σε συντεταγμένες που δεν σχεδιάζονται επειδή αποκόπτονται από το αριστερό άκρο επανατοποθετούνται εκτός του γραφήματος. Η συντεταγμένη του cy
στο μηδέν και αυτό του cx
σε οποιονδήποτε αρνητικό αριθμό (μεγαλύτερο από το ίδιο το σημείο) έτσι ώστε να μην εμφανίζεται όταν κόβεται, όπως το αριστερό μέρος του γραφήματος, από το παράθυρο του SVG.
Διαχειριστείτε το γράφημα από ένα αντικείμενο με JavaScript
Όλες οι λειτουργίες που έχουν επεξηγηθεί μέχρι τώρα μπορούν να ενσωματωθούν σε ένα αντικείμενο για τη διαχείριση του γραφήματος με ένα στυλ πιο χαρακτηριστικό των νέων εκδόσεων του το JavaScript. Αυτή η εναλλακτική υλοποίησης έχει το πρόσθετο πλεονέκτημα της απλοποίησης της ενσωμάτωσης πολλών γραφημάτων, διαφορετικών τιμών, στην ίδια ιστοσελίδα.
Πριν συζητήσουμε την υλοποίηση, ας δούμε τους πιο συνηθισμένους τρόπους δημιουργίας αντικειμένων με το JavaScript και ορισμένες από τις ιδιαιτερότητες των λειτουργιών που επηρεάζουν την πρόταση σχεδίασης γραφικών αισθητήρων IoT.
Είχε ήδη εξηγηθεί ότι ο νέος τρόπος δημιουργίας αντικειμένων σε το JavaScript (διαθέσιμο από την έκδοση 5 του ECMAScript) αποτελείται από τη χρήση Object.create
, το οποίο θα πρέπει να συνηθίσει να χρησιμοποιεί αντί για το "κλασικό" new
, το οποίο βέβαια εξακολουθεί να λειτουργεί σωστά, αν και σκοπός του είναι περισσότερο η προσομοίωση του στυλ των γλωσσών με αντικείμενα που βασίζονται σε τάξη (το JavaScript βασίζει τη δημιουργία αντικειμένων σε πρωτότυπα) παρά μια λειτουργική εναλλακτική.
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();
}
|
Ο προηγούμενος κώδικας σάς επιτρέπει να θυμάστε τις διαφορές μεταξύ της δημιουργίας των αντικειμένων με Object.create
o con new
. Χρησιμεύει επίσης για να τονίσει ότι, ενώ η συνάρτηση με την οποία δημιουργείται το αντικείμενο με new
μπορεί να βρίσκεται οπουδήποτε στον κώδικα, το αντικείμενο πρέπει να υπάρχει ήδη για να μπορέσει να δημιουργηθεί με αυτό Object.create
(Το αντικείμενο ES5_Object δεν είναι συνάρτηση).
Στις γραμμές 3 και 4, για να ορίσετε μια προεπιλεγμένη τιμή στις ιδιότητες στη συνάρτηση με την οποία δημιουργείται το αντικείμενο new
, κάθε ιδιότητα εκχωρείται στην τιμή του αντίστοιχου ορίσματος ή (||
), εάν δεν έχουν περάσει ορίσματα, δηλαδή εάν δεν είναι καθορισμένα (undefined
), καθώς η περίσταση αυτή αξιολογείται ως false
, εκχωρείται η προεπιλεγμένη τιμή.
Το πλαίσιο στο οποίο εκτελείται μια συνάρτηση το JavaScript εγείρει δύο ζητήματα που είναι σημαντικό να έχετε κατά νου και που μπορεί επίσης να δημιουργήσουν σύγχυση κατά τη χρήση αυτής της γλώσσας προγραμματισμού αφού έχετε εργαστεί με άλλους, όπως π.χ. C o C + +, στην περίπτωσή μας. Το πλαίσιο περιλαμβάνει τις μεταβλητές που ορίζονται στο εύρος της συνάρτησης (και τις καθολικές), οι οποίες, παρεμπιπτόντως, εγείρουν μια ενδιαφέρουσα έννοια, τα «κλείσιμο» που καθιερώνει ένα ολόκληρο στυλ προγραμματισμού σε το JavaScript. Τούτου λεχθέντος, θα ήταν αναμενόμενο this
, το οποίο αναφέρεται στο αντικείμενο όταν χρησιμοποιείται στον κώδικα που το ορίζει, διατηρείται το περιβάλλον εκτέλεσης στο οποίο έχει οριστεί, αλλά αυτό που χρησιμοποιεί είναι το περιβάλλον από το οποίο καλείται η συνάρτηση. Αυτή η συμπεριφορά είναι διαφανής στις περισσότερες περιπτώσεις, αλλά υπάρχουν δύο περιπτώσεις στις οποίες μπορεί να προκαλέσει σύγχυση: μια συνάρτηση που ορίζεται μέσα σε μια άλλη συνάρτηση και μια μέθοδος που καλείται από ένα συμβάν του αντικειμένου. 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
*/
|
Κατά την εκτέλεση του προηγούμενου κώδικα, το κείμενο που σχολιάστηκε στο τέλος εμφανίζεται στην κονσόλα. Οι δύο σημειωμένες γραμμές αντικατοπτρίζουν συμπεριφορά που μπορεί να προκαλέσει σύγχυση: το πλαίσιο εκτέλεσης της συνάρτησης probar_dentro()
δεν probar()
, όπως αναμενόταν, αλλά window
, που εμφανίζει τις καθολικές μεταβλητές και όχι τις ιδιότητες με το ίδιο όνομα. Εάν δεν θέλετε αυτή τη συμπεριφορά, απλώς δημιουργήστε μια μεταβλητή στη συνάρτηση υψηλότερου επιπέδου και αντιστοιχίστε την this
, όπως στον παρακάτω κώδικα.
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
*/
|
Για τον έλεγχο του περιβάλλοντος εκτέλεσης όταν μια μέθοδος καλείται από ένα συμβάν window
, για παράδειγμα με την αλλαγή μεγέθους του παραθύρου του προγράμματος περιήγησης, μια άλλη ιδιαιτερότητα του το JavaScript: η δυνατότητα προγραμματισμού "function factories", δηλαδή συναρτήσεων που δημιουργούν άλλες συναρτήσεις, επιστρέφοντάς τες με 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
|
Στο παραπάνω παράδειγμα κώδικα, η μέθοδος llamar()
των αντικειμένων Contexto
Δεν κάνει τη δουλειά, αλλά επιστρέφει μια ανώνυμη λειτουργία που τη φροντίζει. Για να επαληθεύσετε ότι όλα λειτουργούν όπως αναμένεται, υπάρχει μια καθολική μεταβλητή με το ίδιο όνομα με την ιδιότητα που εμφανίζει η συνάρτηση στην κονσόλα. Εάν το περιβάλλον είναι σωστό, θα εμφανιστεί η τιμή της ιδιότητας και όχι η τιμή της καθολικής μεταβλητής.
το JavaScript Προσπαθήστε να διορθώσετε τα σημάδια του ερωτηματικού που παραλείπουμε στο τέλος των προτάσεων. Αυτό επιτρέπει ένα χαλαρό στυλ γραφής, αλλά είναι ένα δίκοπο μαχαίρι που πρέπει να αντιμετωπιστεί προσεκτικά. Στις περισσότερες περιπτώσεις, για να αποφύγετε τα ανεπιθύμητα αποτελέσματα που αυτό προκαλεί σε εκφράσεις που καταλαμβάνουν πολλές γραμμές, μπορείτε να χρησιμοποιήσετε παρενθέσεις ή να προηγηθείτε του τρόπου με τον οποίο το JavaScript θα ερμηνεύσει τον κώδικα. Γι' αυτό η γραμμή 8 του παραδείγματος περιλαμβάνει function
στο πίσω μέρος του return
, αν είχα χρησιμοποιήσει άλλη γραμμή το νόημα θα ήταν πολύ διαφορετικό. Κατά τη γνώμη μου, η πιο ευανάγνωστη λύση είναι η χρήση μιας ενδιάμεσης μεταβλητής όπως στην ακόλουθη έκδοση. Προφανώς, μόλις γίνει κατανοητή η συμπεριφορά, η απόφαση αντιστοιχεί στον προγραμματιστή.
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);
|
Με την ίδια έννοια της αξιολόγησης μιας έκφρασης ως συνάρτησης, δηλαδή επιστροφή μιας συνάρτησης και όχι της τιμής που επιστρέφει η συνάρτηση. στη γραμμή 21 του τελευταίου παραδείγματος (ήταν στη γραμμή 19 του προηγούμενου) σταματά με clearInterval
η συνάρτηση που καλείται με setInterval
. Για να δράσει για 30 δευτερόλεπτα, η διακοπή αναβάλλεται με setTimeout
, το οποίο με τη σειρά του χρειάζεται μια συνάρτηση ως πρώτο όρισμα. να παραδώσει την εκτέλεση ως παράμετρο clearInterval
με τη μεταβλητή που περιέχει την περιοδική κλήση (και όχι τη συνάρτηση clearInterval
) είναι για το οποίο δημιουργείται η ανώνυμη συνάρτηση στην τελευταία γραμμή.
Η επιλογή μεταξύ της σύνταξης του κώδικα που ενσωματώνει τον ορισμό της συνάρτησης, πιο συμπαγούς (όπως στη γραμμή 21) ή χρησιμοποιώντας μια βοηθητική μεταβλητή, κατά τη γνώμη μου, πιο ευανάγνωστη (όπως στις γραμμές 19 και 20) ποικίλλει ελάχιστα σε απόδοση και εξαρτάται περισσότερο από το στυλ και την αναγνωσιμότητα για συντήρηση.
Για να ελέγξετε τον κώδικα, πριν έχετε δεδομένα στον διακομιστή, μπορείτε να χρησιμοποιήσετε μια γεννήτρια τυχαίων τιμών στο επιθυμητό εύρος ή να προετοιμάσετε πίνακες με ελεγχόμενες τιμές που προσομοιώνουν τη λειτουργία υπό τις επιθυμητές συνθήκες. Το παρακάτω παράδειγμα χρησιμοποιεί μια απλή γεννήτρια δεδομένων σε όλο το εύρος, γι' αυτό φαίνονται λίγο υπερβολικά.
Για δοκιμή, μπορείτε κατεβάστε τον πλήρη κώδικα του παραδείγματος σχηματίζεται από μια ιστοσελίδα γραμμένη σε HTML, το στυλ CSS και τον κώδικα το JavaScript. Το τελευταίο είναι το πιο σχετικό, καθώς τα άλλα στοιχεία είναι ελάχιστη υποστήριξη, πολύ απλοποιημένα και είναι πολύ πιο ανεπτυγμένα στα άρθρα των αντίστοιχων ενοτήτων.
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);
}
|
Δημοσίευση σχολίου