JavaScript
Funktionen in onDataUpdated()
In diesem Widget möchten wir einige Gerätedaten in eine für Menschen besser lesbare Form umwandeln. Dazu implementieren wir unsere eigenen Funktionen innerhalb vononDataUpdated()
.function hoursToPretty(value) {Wenn wir nun einen Stundenwert anzeigen möchten, können wir ihn einfach durch diese Funktion leiten, um die Ausgabe lesbarer zu machen.
if (value < 24) { //if less than a day show hours and minutes
const minutes = Math.floor((value % 1) * 60);
const hours = Math.floor(value);
return `${hours}h ${minutes}m`;
} else if (value < 720) {//if less than a month show days and hours
const days = Math.floor(value / 24);
const hours = Math.floor(value % 24);
return `${days}d ${hours}h`;
} else { //if more than a month show month and days
const months = Math.floor(value/720);
const days = Math.floor((value/24) % 30);
return `${months} months ${days}d`;
}
}
Ähnlich verhält es sich mit der Funktion
MBtoPretty()
und der Funktion map()
.Implementierung von onResize()
Das Widget in seiner aktuellen Form ist hinsichtlich des Layouts recht unflexibel. Um dieses Problem zu beheben, implementieren wir unsere eigene FunktiononResize()
, die das Widget auf eine Hochformatversion umstellt, damit alle Informationen richtig angezeigt werden, wenn es schmaler als hoch ist.Dies ist recht einfach und erfordert lediglich eine if-Anweisung und einige CSS-Regeln.
Um das aktuelle Seitenverhältnis unseres Widgets zu bestimmen, vergleichen wir
self.ctx.height
mit self.ctx.width
.Wenn wir feststellen, dass das Widget höher als breit ist, wenden wir die Klasse
portrait
auf den Container des Widgets an und entfernen die Klasse landscape
. Umgekehrt wenden wir die Klasse landscape
an und entfernen die Klasse portrait
, wenn das Widget breiter als hoch ist:self.onResize = function() {Innerhalb des CSS unseres Widgets definieren wir zwei neue Regelsätze:
const container = self.ctx.$container;
if (self.ctx.height > self.ctx.width) {
container.removeClass('landscape');
container.addClass('portrait');
} else {
container.removeClass('portrait');
container.addClass('landscape');
}
}
.landscape .gauge_container {Dadurch ändert sich automatisch die Ausrichtung unserer Messgeräte. Natürlich müssen wir nun auch unseren ursprünglichen Regelsatz aktualisieren:
flex-direction: row;
}
.portrait .gauge_container {
flex-direction: column;
}
.gauge_container {Wir haben
display: flex;
justify-content: center;
align-items: center;
}
align-items: center;
hinzugefügt, um unsere Anzeigen im Hochformat horizontal zu zentrieren.Um sicherzustellen, dass unser Widget beim Laden in ein Dashboard (d. h. ohne aktive Größenänderung) nicht das falsche Layout erhält, rufen wir am Ende von
onInit()
unsere Funktion onResize()
auf.Implementierung einer neuen Methode
Um die Statusanzeige in der Titelleiste mit einer Farbe zu beleuchten, die den Gesamtstatus des Widgets darstellt, habe ich mich entschlossen, eine neue Methode zu implementieren.Die Deklaration ist ganz einfach:
self.setStatus = function(...statuses) {
...
}
Diese Funktion kann dann von onDataUpdated aus aufgerufen werden, aber auch an jeder anderen Stelle im Widget mit
self.setStatus()
.Ressourcen importieren
Um mehr Informationen darüber zu liefern, warum ein Widget einen bestimmten Status hat, möchte ich dem Indikator einen Tooltip hinzufügen, der beim Darüberfahren mit der Maus eine Meldung anzeigt.Zum Erstellen eines Tooltips verwende ich Tippy.js, eine Javascript-Bibliothek, die die Erstellung von Tooltips vereinfacht.
Da Tippy eine Bibliothek eines Drittanbieters ist, müssen wir sie über die Registerkarte „Ressourcen” zu unserem Widget hinzufügen. Dort fügen wir einfach die von Tippy bereitgestellten Links hinzu – so einfach ist das.
Jetzt können wir die Tippy-Funktion aufrufen, um mit
tippy(‚#CPUstatusLight‘, {content: ‚Initializing...‘});
einen Tooltip für die Statusanzeige zu erstellen.Definieren eines Einstellungsschemas
Um dem Benutzer mehr Optionen zur Verfügung zu stellen, können wir Einstellungen implementieren, die eine Anpassung des Widgets ermöglichen. In diesem Beispiel fügen wir eine einfache Umschaltfunktion für die Anzeige des Zeitstempels hinzu. Öffnen Sie dazu die Registerkarte „Einstellungsschema“ und erstellen Sie ein Schema:{
"schema": {
"type": "object",
"title": "Settings",
"properties": {
"show_time": {
"title": "Show timestamp",
"type": "boolean",
"default": true
}
}
},
"form": [{
"key": "show_time",
"type": "boolean"
}]
}
Der Inhalt lässt sich in zwei Hauptbereiche unterteilen: das Schema und das Formular. Das Schema definiert, welche Variablen vorhanden sind, wie sie benannt werden sollen, welchen Typ sie haben und vieles mehr. Das Formular beschreibt, was dem Benutzer in den Einstellungen des Widgets angezeigt wird.
Unsere Einstellungen sind über das Kontextobjekt unter
self.ctx.settings
zugänglich. Um den Zeitstempel auszublenden, überprüfen wir in onInit()
, ob die Einstellung aktiviert oder deaktiviert ist, und blenden ihn entsprechend aus:if (!self.ctx.settings.show_time) {
self.ctx.$container.find('.metainfo').css("display", "none");
}
Erstellen benutzerdefinierter Testdaten
Manchmal sind die Standard-Testdaten für das Widget, an dem Sie arbeiten, einfach nicht sinnvoll. In diesem Fall können Sie die Testdaten, mit denen Ihr Widget gespeist wird, anpassen.Klicken Sie einfach auf die Schaltfläche „Bearbeiten“ in der oberen rechten Ecke der Widget-Vorschau und dann auf das Bearbeitungssymbol in Ihrem Widget.
Das Overlay zeigt Ihnen die aktuellen Datenquellen und Datenschlüssel des Widgets an. Um das Verhalten eines Datenschlüssels zu ändern, klicken Sie auf das Bearbeitungssymbol des Datenschlüssels und scrollen Sie nach unten zum Abschnitt „Funktion“ am Ende der Konfiguration.
Dort können Sie Ihre eigene Javascript-Funktion implementieren, um Testdaten zurückzugeben. In diesem Fall möchten wir beispielsweise eine zufällige ganze Zahl zwischen 0 und 100. Ich habe einfach eine Beispielfunktion aus den MDN-Webdokumenten genommen und das Ergebnis zurückgegeben:
function getRandomIntInclusive(min, max) {
const minCeiled = Math.ceil(min);
const maxFloored = Math.floor(max);
return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled); // The maximum is inclusive and the minimum is inclusive
}
return getRandomIntInclusive(0,100);