SVG-Webseitenkomponenten für IoT und Maker (Teil 1)
Veröffentlicht: 2022-03-10Der IoT-Markt steckt noch in den Kinderschuhen, nimmt aber Fahrt auf. Wir stehen an einem Höhepunkt in der Geschichte des IoT. Die Märkte vervierfachen sich im Laufe von fünf Jahren, 2015 bis 2020. Für Webentwickler ist dieses IoT-Wachstum erheblich. Es gibt bereits eine große Nachfrage nach IoT-Webtechniken.
Viele Geräte werden geografisch verteilt sein, und ihre Besitzer werden eine Fernsteuerung und -verwaltung wünschen. Es müssen vollständige Webstacks erstellt werden, um Kanäle für die Teleoperation zu schaffen. Außerdem findet die Interaktion mit einem oder mehreren IoT-Geräten gleichzeitig statt. Die Interaktion muss in Echtzeit der physischen Welt erfolgen.
Diese Diskussion befasst sich mit den Schnittstellenanforderungen unter Verwendung von Vue.js als Katalysator und veranschaulicht eine Methode der Kommunikation zwischen Webseite und Gerät aus vielen Substitutionen.
Hier sind einige der Ziele, die für diese Diskussion geplant sind:
- Erstellen Sie eine Single-Page-Web-App-SPWA, die Gruppen von IoT-Mensch-Maschine-Schnittstellen hostet (wir können diese „Panel-Gruppen“ nennen);
- Anzeigen von Listen von Bedienfeldgruppenkennungen als Ergebnis der Abfrage eines Servers;
- Anzeigen der Panels einer ausgewählten Gruppe als Ergebnis einer Abfrage;
- Stellen Sie sicher, dass die Panel-Anzeige träge geladen und schnell animiert wird;
- Stellen Sie sicher, dass Panels mit IoT-Geräten synchronisiert werden.
IoT und das schnelle Wachstum von Webseiten
Die Darstellung von Grafiken zur Visualisierung und Fernsteuerung von Hardware sowie die Synchronisierung von Webseiten mit physikalischen Echtzeitprozessen gehören zum Bereich der Webseiten-Problemlösung, die dieser IoT-Zukunft innewohnt.
Viele von uns beginnen mit der Suche nach IoT-Präsentationstechniken, aber es gibt einige Webstandards zusammen mit einigen Präsentationstechniken, mit denen wir jetzt beginnen können. Wenn wir diese Standards und Techniken gemeinsam erforschen, können wir uns dieser IoT-Welle anschließen.
Dashboards und Datenvisualisierung sind gefragt. Darüber hinaus ist die Nachfrage hoch, über Webseiten hinauszugehen, die Formulare oder Anzeigelisten oder Textinhalte bereitstellen. Die Dashboards für IoT müssen bildhaft und animiert sein. Animationen müssen mit physikalischen Prozessen in Echtzeit synchronisiert werden, um den Benutzern eine wahrheitsgemäße Ansicht des Maschinenzustands zu bieten. Der Maschinenzustand, z. B. ob eine Flamme brennt oder nicht, übertrumpft den Anwendungszustand und liefert dem Bediener wichtige Informationen, möglicherweise sogar Sicherheitsinformationen.
Die Dashboards erfordern mehr als die Visualisierung von Daten. Wir müssen bedenken, dass die Dinge , die Teil des IoT sind, Geräte sind, die nicht nur Sensoren, sondern auch Steuerschnittstellen haben. In Hardwareimplementierungen werden MCUs mit Schaltern, Schwellwertschaltern, Parametereinstellungen und mehr erweitert. Dennoch können Webseiten den Platz dieser Hardware-Steuerungskomponenten einnehmen .
Nichts Neues. Computerschnittstellen für Hardware gibt es schon seit langem, aber das schnelle Wachstum der Nutzung von Webseiten für diese Schnittstellen ist Teil unserer gegenwärtigen Erfahrung. WebRTC und Speech API befinden sich auf einem Entwicklungspfad, der 2012 begann. WebSockets wurde in einem ähnlichen Zeitrahmen entwickelt.
IoT ist schon lange in unseren Köpfen. IoT ist seit 1832 Teil des menschlichen Dialogs. Aber IoT und Wireless, wie wir sie heute kennen, wurden von Tesla um 1926 ins Auge gefasst. Forbes 2018 State of Iot zeigt uns den aktuellen Marktfokus für IoT. Der für Webentwickler interessante Artikel ruft Dashboards auf:
„Early Adopters oder Befürworter des IoT priorisieren Dashboards, Berichte und IoT-Anwendungsfälle, die Datenströme bereitstellen, die für Analysen, erweiterte Visualisierung und Data Mining von wesentlicher Bedeutung sind.“
Der IoT-Markt ist riesig. Dieser Artikel zur Marktgröße gibt eine Prognose für die Anzahl der Geräte, die erscheinen werden: 2018: 23,14 Milliarden ⇒ 2025: 75,44 Milliarden. Und es wird versucht, eine finanzielle Zahl zu nennen: 2014: \$2,99 Billionen ⇒ 2020: $8,90 Billionen. Die Nachfrage nach IoT-Fähigkeiten wird am schnellsten wachsen: IoT in Demand.
Während wir klare Schnittstellen zur Steuerung und Überwachung von Geräten entwickeln, stoßen wir auf ein neues Problem bei der Entwicklung unserer Schnittstellen. All die vielen Milliarden Geräte werden vielen Menschen (oder Organisationen) gehören. Außerdem kann jede Person eine beliebige Anzahl von Geräten besitzen. Vielleicht werden sogar einige der Geräte geteilt.
Moderne Schnittstellen, die für Maschinensteuerungen hergestellt wurden, haben oft ein gut definiertes Layout, das spezifisch für eine bestimmte Maschine oder die Installation einiger weniger Maschinen ist. In einem intelligenten Haus verfügt ein High-End-System beispielsweise über ein LCD mit Panels für sorgfältig platzierte Geräte. Aber wenn wir mit der Webversion von IoT wachsen, wird es eine beliebige Anzahl von Panels für einen dynamischen und sogar mobilen Stream von Geräten geben.
Die Verwaltung von Panels für Geräte ähnelt der Verwaltung sozialer Verbindungen auf sozialen Websites.
„Unsere Benutzeroberflächen müssen dynamisch verwalten, welches hoch animierte Echtzeit-Panel für jeden einzelnen Benutzer zu jedem Zeitpunkt angezeigt werden muss.“
Das Dashboard ist eine Single Page Web App SPWA. Und wir können uns eine Datenbank mit Panels vorstellen. Wenn also ein einzelner Benutzer auf eine Reihe von Panels und Konfigurationen für seine auf der ganzen Welt verstreuten Geräte zugreifen möchte, muss die SPWA bei Bedarf auf Panel-Komponenten zugreifen. Die Panels und einige ihrer unterstützenden JavaScripts müssen träge geladen werden.
„Unsere Schnittstellen müssen mit Webseiten-Frameworks funktionieren, die es ermöglichen, asynchrone Komponentenbindungen einzubinden, ohne ihre Frameworks neu zu initialisieren.“
Lassen Sie uns Vue.js, WebSockets, MQTT und SVG verwenden, um unseren Schritt in den IoT-Markt zu machen.
Empfohlene Lektüre : Erstellen einer interaktiven Infografik mit Vue.js
High-Level-Architektur für eine IoT-Web-App
Bei der Gestaltung der Oberfläche für die IoT-Webseite hat man immer viele Möglichkeiten. Eine Option könnte darin bestehen, eine einzelne Seite einem einzelnen Gerät zu widmen. Die Seite kann sogar serverseitig gerendert werden. Der Server hätte die Aufgabe, das Gerät abzufragen, um seine Sensorwerte zu erhalten, und die Werte dann an den entsprechenden Stellen in der HTML-Zeichenfolge einzufügen.
Viele von uns sind mit Tools vertraut, mit denen HTML-Vorlagen mit speziellen Markierungen geschrieben werden können, die angeben, wo Variablenwerte platziert werden sollen. {{temperature}}
in einer solchen Vorlage zu sehen, weist uns und die View -Engine an, die von einem Gerät abgefragte Temperatur zu nehmen und das Symbol {{temperature}}
damit zu ersetzen. Nachdem der Benutzer also darauf gewartet hat, dass der Server das Gerät abfragt, das Gerät antwortet, die Seite rendert und die Seite liefert, kann der Benutzer endlich die vom Gerät gemeldete Temperatur sehen.
Für diese Seite-pro-Gerät-Architektur möchte der Benutzer dann möglicherweise einen Befehl an das Gerät senden. Kein Problem, er kann ein HTML-Formular ausfüllen und absenden. Der Server könnte sogar eine Route nur für das Gerät haben, oder etwas cleverer eine Route für den Gerätetyp und die Geräte-ID. Der Server übersetzt dann die Formulardaten in eine Nachricht, die an das Gerät gesendet wird, schreibt sie an einen Gerätehandler und wartet auf eine Bestätigung. Dann kann der Server schließlich auf die Post-Anforderung antworten und dem Benutzer mitteilen, dass mit dem Gerät alles in Ordnung ist.
Viele CMS arbeiten auf diese Weise, um Blogeinträge und dergleichen zu aktualisieren. Nichts scheint daran seltsam zu sein. Es scheint, dass HTML über HTTP schon immer darauf ausgelegt war, gerenderte Seiten abzurufen und Formulardaten zu senden, die vom Webserver verarbeitet werden. Darüber hinaus stehen Tausende von CMS zur Auswahl. Um unser IoT-System zum Laufen zu bringen, scheint es also sinnvoll, sich durch Tausende von CMS zu wühlen, um zu sehen, welches das Richtige für den Job ist. Oder wir wenden zunächst einen Filter auf CMS an.
Wir müssen die Echtzeitnatur dessen berücksichtigen, womit wir es zu tun haben. Obwohl HTML in seiner ursprünglichen Form für viele Unternehmensaufgaben ziemlich gut ist, braucht es ein wenig Hilfe, um zum Bereitstellungsmechanismus für das IoT-Management zu werden. Wir brauchen also ein CMS oder einen benutzerdefinierten Webserver, der HTML bei dieser IoT-Aufgabe unterstützt. Wir können auch einfach an den Server denken, wenn wir davon ausgehen, dass CMS Serverfunktionen bereitstellen. Wir müssen nur bedenken, dass der Server eine ereignisgesteuerte Animation bereitstellen muss, sodass die Seite nicht zu 100 % statisch gedruckt werden kann.
Hier sind einige Parameter, die die Auswahl für unsere geräteverknüpfte Webseite leiten könnten, Dinge, die sie tun sollte:
- Sensordaten und andere Gerätestatusmeldungen asynchron empfangen;
- Rendern Sie die Sensordaten für die Seite im Client (fast logische Folge zu 1);
- asynchrones Veröffentlichen von Befehlen für ein bestimmtes Gerät oder eine Gruppe von Geräten;
- Senden Sie optional Befehle über den Server oder umgehen Sie ihn.
- Sichere Aufrechterhaltung der Eigentumsverhältnisse zwischen dem Gerät und dem Benutzer;
- Verwalten Sie den kritischen Gerätebetrieb, indem Sie entweder nicht stören oder außer Kraft setzen.
Die Liste kommt einem in den Sinn, wenn man an nur eine Seite denkt, die als Schnittstelle zu einem ausgewählten Gerät fungiert . Wir wollen mit dem Gerät frei kommunizieren können, wenn es um Befehle und Daten geht.
Was die Seite betrifft, müssen wir den Webserver nur einmal danach fragen. Wir würden erwarten, dass der Webserver (oder die zugehörige Anwendung) einen sicheren Kommunikationspfad bereitstellt. Und der Pfad muss nicht über den Server verlaufen oder sollte den Server vielleicht ganz vermeiden, da der Server möglicherweise andere Aufgaben mit höherer Priorität hat, als sich um die Kommunikation einer Seite für Daten zu kümmern, die von Sensoren kommen.
Tatsächlich können wir uns vorstellen, dass Daten einmal pro Sekunde von einem Sensor eingehen, und wir würden nicht erwarten, dass der Webserver selbst eine konstante Aktualisierung von Sekunde zu Sekunde für Tausende von einzelnen Sensorströmen bereitstellt, die mit Tausenden von Zuschauern multipliziert werden. Natürlich kann ein Webserver partitioniert oder in einem Load-Balancing-Framework eingerichtet werden, aber es gibt andere Dienste, die für die Bereitstellung von Sensoren und das Marshallen von Befehlen an die Hardware angepasst sind.
Der Webserver muss einige Pakete liefern, damit die Seite sichere Kommunikationskanäle mit dem Gerät aufbauen kann. Wir müssen beim Senden von Nachrichten auf Kanälen vorsichtig sein, die keine Verwaltung der Art von Nachrichten bieten, die durchlaufen werden. Es muss ein gewisses Wissen darüber vorhanden sein, ob sich ein Gerät in einem Modus befindet, der unterbrochen werden kann, oder ob eine Benutzeraktion erforderlich ist, wenn ein Gerät außer Kontrolle gerät. So kann der Webserver dem Client helfen, die entsprechenden Ressourcen zu erhalten, die mehr über das Gerät wissen können. Messaging könnte mit so etwas wie einem MQTT-Server erfolgen. Und es könnte einige Dienste zur Vorbereitung des MQTT-Servers geben, die gestartet werden können, wenn der Benutzer über den Webserver Zugriff auf sein Panel erhält.
Aufgrund der physikalischen Welt mit ihren Echtzeitanforderungen und aufgrund zusätzlicher Sicherheitsüberlegungen weicht unser Diagramm ein wenig vom Original ab.
Wir dürfen hier nicht aufhören. Das Einrichten einer einzelnen Seite pro Gerät, auch wenn diese reaktionsschnell ist und die Kommunikation gut handhabt, ist nicht das, wonach wir gefragt haben. Wir müssen davon ausgehen, dass sich ein Benutzer bei seinem Konto anmeldet und auf sein Dashboard zugreift. Von dort wird er nach einer Liste von Inhaltsprojekten fragen (höchstwahrscheinlich Projekte, an denen er arbeitet). Jedes Element in der Liste bezieht sich auf eine Reihe von Ressourcen. Wenn er ein Element durch Klicken oder Tippen auswählt, erhält er Zugriff auf eine Sammlung von Panels, von denen jedes einige Informationen über eine bestimmte Ressource oder ein bestimmtes IoT-Gerät enthält.
Eine beliebige Anzahl von Panels, die als Antwort auf die Abfrage geliefert werden, die als Ergebnis der Schnittstellenaktion des Benutzers erzeugt wird, kann jene Panels sein, die mit Live-Geräten interagieren. Sobald also ein Panel erscheint, wird erwartet, dass es Echtzeitaktivitäten anzeigt und in der Lage ist, einen Befehl an ein Gerät zu senden.
Wie die Panels auf der Seite zu sehen sind, ist eine Designentscheidung. Dies können schwebende Fenster oder Felder auf einem scrollbaren Hintergrund sein. Wie auch immer das präsentiert wird, die Panels werden Zeit, Temperatur, Druck, Windgeschwindigkeit oder was auch immer Sie sich vorstellen können, abhaken. Wir erwarten, dass die Panels in Bezug auf verschiedene Grafikmaßstäbe animiert werden. Die Temperatur kann als Thermometer dargestellt werden, die Geschwindigkeit als halbkreisförmige Geschwindigkeitsanzeige, Schall als Streaming-Wellenform und so weiter.
Der Webserver hat die Aufgabe, bei Anfragen an eine Datenbank mit Panels und bei physischer Verfügbarkeit der Geräte die richtigen Panels an den richtigen Benutzer zu liefern. Angesichts der Tatsache, dass es viele verschiedene Arten von Geräten geben wird, werden die Panels für jedes Gerät wahrscheinlich unterschiedlich sein. Der Webserver sollte also in der Lage sein, die zum Rendern eines Panels erforderlichen piktografischen Informationen zu liefern. Allerdings soll die HTML-Seite für das Dashboard nicht mit allen möglichen Panels geladen werden müssen. Keine Ahnung, wie viele es sein werden.
Hier sind einige Parameter, die die Auswahl für unsere Dashboard-Seite leiten könnten, Dinge, die sie tun sollte:
- Präsentieren Sie eine Möglichkeit, Gruppen verwandter Gerätefelder auszuwählen;
- Verwenden Sie gleichzeitige Gerätekommunikationsmechanismen für eine bestimmte Anzahl von Geräten;
- Gerätepanels aktivieren, wenn der Benutzer sie anfordert;
- Integrieren Sie träge geladene Grafiken für einzigartige Panel-Designs;
- Verwenden Sie Sicherheitstoken und Parameter in Bezug auf jedes Panel;
- Halten Sie die Synchronität mit allen Geräten unter Benutzerkontrolle aufrecht.
Wir können allmählich sehen, wie sich das Spiel ändert, aber in der Welt des Dashboard-Designs hat sich das Spiel hier und da seit einiger Zeit ein wenig geändert. Wir müssen uns nur auf einige aktuelle und nützliche Seitenentwicklungstools beschränken, um uns auf den Weg zu bringen.
Beginnen wir damit, wie wir die Panels rendern können. Das scheint schon eine große Aufgabe zu sein. Wir stellen uns viele verschiedene Arten von Paneelen vor. Aber wenn Sie jemals eine Musik-DAW verwendet haben, würden Sie sehen, wie sie Grafiken verwendet haben, um Panels so aussehen zu lassen, wie die analogen Geräte, die von Bands vor langer Zeit verwendet wurden. Alle Panels in DAWs werden von den Plugins gezeichnet, die mit Sound arbeiten. Tatsächlich könnten viele dieser DAW-Plugins SVG verwenden, um ihre Schnittstellen zu rendern. Wir beschränken uns also auf den Umgang mit SVG-Schnittstellen, die wiederum jede erdenkliche Grafik sein können.
Auswahl von SVG für Panels
Natürlich mag ich DAWs und würde das als Beispiel verwenden, aber SVG ist ein Webseiten-Standard. SVG ist ein W3C-Standard. Es dient zum Übertragen von Strichzeichnungen auf die Webseiten. SVG war früher ein Bürger zweiter Klasse auf der Webseite, der in iFrames leben musste. Aber seit HTML5 ist es ein Bürger erster Klasse. Wenn SVG2 herauskommt, kann es vielleicht Formularelemente verwenden. Vorerst sind Formularelemente in SVG Fremdobjekte. Aber das sollte uns nicht davon abhalten, SVG zum Substrat für Panels zu machen.
SVG kann gezeichnet, zur Anzeige gespeichert und träge geladen werden. Wenn wir das Komponentensystem untersuchen, werden wir tatsächlich sehen, dass SVG für Komponentenvorlagen verwendet werden kann. In dieser Diskussion werden wir Vue.js verwenden, um Komponenten für die Panels zu erstellen.
Das Zeichnen von SVG ist nicht schwierig, da es viele Strichzeichnungsprogramme gibt, die leicht zu bekommen sind. Wenn Sie das Geld ausgeben, können Sie Adobe Illustrator erwerben, das SVG exportiert. Inkscape ist seit einiger Zeit ein Muss für die SVG-Erstellung. Es ist Open Source und funktioniert gut unter Linux, kann aber auch auf Mac und Windows ausgeführt werden. Dann gibt es mehrere Webseiten-SVG-Bearbeitungsprogramme, die Open Source sind, und auch einige SaaS-Versionen.
Ich habe mich nach einem webbasierten Open-Source-SVG-Editor umgesehen. Nach einigem Stöbern bin ich auf SVG-Edit gestoßen. Sie können es in Ihre eigenen Webseiten einfügen, vielleicht wenn Sie ein SVG-basiertes Blog oder ähnliches erstellen.
Wenn Sie Ihre Arbeit in einer Datei speichern, lädt SVG-Edit sie in Ihren Browser herunter und Sie können die Datei aus Ihrem Download-Verzeichnis abrufen.
Das Bild, das ich gezeichnet habe, zeigt ein UND-Gatter, das einen Integrator steuert. Das ist normalerweise nicht das, was man in einem Panel für eine MCU erwarten würde. Das Panel könnte vielleicht eine Taste haben, um einen der UND-Gatter-Eingänge zu speisen. Dann könnte es eine Anzeige von einem ADC haben, der die Ausgabe des Integrators liest. Vielleicht wird das ein Liniendiagramm auf einer Zeitachse sein. Die meisten Panels verfügen über Grafiken, die es dem Benutzer ermöglichen, sich auf das zu beziehen, was in der MCU vor sich geht. Und wenn unsere Schaltung irgendwo leben wird, wird sie innerhalb der MCU sein.
Trotzdem kann unser elektronisches Diagramm verwendet werden, um Animationen zu diskutieren. Was wir tun möchten, ist, einen Blick auf das SVG zu werfen und zu sehen, wo wir an einige der DOM-Tags gelangen können, die wir auf irgendeine Weise ändern möchten. Wir können das SVG dann mit ein wenig Vanille-JavaScript und einem Timer animieren. Lassen Sie uns das UND-Gatter in verschiedenen Farben blinken.
Das gesuchte SVG befindet sich in der folgenden Codebox. Es sieht für den Programmierer nicht sehr freundlich aus, obwohl der Benutzer ziemlich zufrieden sein wird. Trotzdem gibt es noch einige Hinweise, um herauszufinden, welches DOM-Element wir bearbeiten möchten. Erstens haben die meisten SVG-Zeichenwerkzeuge eine Möglichkeit, Objekteigenschaften abzurufen, insbesondere das id
Attribut. SVG-Edit hat auch einen Weg. Wählen Sie im Editor das UND-Gatter aus und beobachten Sie die Symbolleiste. Sie sehen auch ein Feld für die id
und die CSS class
.
Wenn Sie aus irgendeinem Grund nicht zu einem Bearbeitungstool gelangen, können Sie das SVG in einem Browser öffnen und das DOM untersuchen. Auf jeden Fall haben wir festgestellt, dass unser Gate id
= „svg_1“ hatte.
<svg width="640" height="480" xmlns="https://www.w3.org/2000/svg" xmlns:svg="https://www.w3.org/2000/svg"> <g class="layer"> <title>Layer 1</title> <path d="m80.59881,87.020171l14.714795,0m-14.714793,-11.938687l14.714797,0.000004m-0.033867,-6.543869l0,24.758504c42.377882,2.221929 43.364812,-27.139117 0,-24.758504zm47.366321,12.333056l-15.303943,0m-48.188699,-6.489897l1.454753,0l0,1.454751l-1.454753,0l0,-1.454751zm-0.068425,11.869359l1.454753,0l0,1.454753l-1.454753,0l0,-1.454753zm63.545246,-6.089294l1.454751,0l0,1.454751l-1.454751,0l0,-1.454751z" fill="#FF0000" stroke="#000000"/> <path d="m48.58886,119.662231l18.234678,0l2.523043,-7.173309l4.128604,13.808613l4.587337,-13.987948l4.013933,13.808613l4.35797,-13.629278l4.35797,13.718944l2.408353,-6.72497l18.349357,0m-64.482612,-0.623112l1.515724,0l0,1.515728l-1.515724,0l0,-1.515728zm64.484275,-0.103111l1.515721,0l0,1.515728l-1.515721,0l0,-1.515728z" fill="#FF0000" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="rotate(90.3367 80.0675 119.304)"/> <polygon cx="108.5" cy="79.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="#000000"/> <polygon cx="215.5" cy="192.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="165.5" cy="164.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="161.5" cy="138.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <polygon cx="160.5" cy="161.5" edge="0" fill="#ffffff" orient="x" shape="regularPoly" sides="3" strokeWidth="null" strokecolor="none"/> <g> <path d="m225.016923,53.008793l0,3.419331m-4.558966,-1.709666l9.11791,0m10.303228,4.235512l-25.770656,0m-34.429182,0l24.544724,0m0.220544,-4.058194l1.543807,0l0,8.164451l-1.543807,0l0,-8.164451zm7.939567,-4.473673l1.543805,0l0,16.999955l-1.543805,0l0,-16.999955zm-34.176663,8.126854l1.474036,0l0,0.747515l-1.474036,0l0,-0.747515zm61.677552,0.018809l1.474038,0l0,0.747515l-1.474038,0l0,-0.747515z" fill="#FF0000" sides="3" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/> <polygon cx="171.5" cy="159.5" edge="43.256342" fill="#ffffff" orient="x" points="223.47406005859375,91.5 186.01296997070312,113.128173828125 186.01296997070312,69.871826171875 223.47406005859375,91.5 " shape="regularPoly" sides="3" stroke="#000000" stroke-width="null" strokeWidth="null" strokecolor="#000000"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171" x2="186" y1="103.5" y2="103.5"/> <path d="m130.801817,80.659041l15.333707,0l2.12165,-4.564833l3.47178,8.787299l3.857534,-8.901421l3.375353,8.787299l3.664657,-8.673176l3.664657,8.730237l2.025206,-4.279526l15.430142,0m-54.224016,-0.396526l1.274586,0l0,0.964554l-1.274586,0l0,-0.964554zm54.225414,-0.065616l1.274584,0l0,0.964554l-1.274584,0l0,-0.964554z" fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="171.5" x2="171.5" y1="103.75" y2="135.388167"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="177.75" x2="177.75" y1="58.75" y2="80.255951"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="223.75" x2="266.854524" y1="91.75" y2="91.75"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="241.75" x2="241.75" y1="59.75" y2="91.754167"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="168.25" x2="180.75" y1="135.75" y2="135.75"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-width="null" x1="169.75" x2="179.25" y1="138.5" y2="138.5"/> <line fill="none" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" x1="171" x2="179.75" y1="141.25" y2="141.25"/> </g> </g> </svg>
Jetzt brauchen wir nur noch ein wenig JavaScript. Wir nehmen zunächst zur Kenntnis, dass das Elementattribut „fill“ vorhanden ist. Dann gibt es nur das einfache Programm, das folgt:
<html> <head> </head> <body> <!-- ALL THE SVG FROM ABOVE GOES HERE --> </body> <html> </svg> <script> // Set up a timer interval flash the color. var gateElement = document.getElementById("svg_1"); if ( gateElement ) { setInterval( () => { var fillC = gateElement.getAttribute("fill"); gateElement.setAttribute("fill", (fillC == "#00FF00") ? "#FF0000" : "#00FF00" ); }, 2000 ) } </script>
Beachten Sie, dass wir eine minimale HTML-Seite haben. Sie können den Code ausschneiden und in Ihren bevorzugten Editor einfügen. Und dann vergessen Sie nicht, das SVG auszuschneiden und einzufügen, um den Kommentar zu ersetzen. Meine Version von Chrome erfordert, dass die Seite HTML ist, um den JavaScript-Bereich zu haben. Das ist also ein Browser, der SVG immer noch als etwas separates behandelt. Aber es ist ein langer Weg von den <iframe>
.
Wenn Sie genau richtig ausschneiden und einfügen, können Sie die Seite aufrufen und sehen, wie das UND-Gatter immer wieder von Rot zu Grün wechselt.
Empfohlene Lektüre : SVG Circle Decomposition to Paths
Bauplatten von VUE Components
Wir sind bereits auf dem Weg, jedes einzelne Panel zum Leben zu erwecken, aber wenn wir große Sammlungen von Panels auf sinnvolle Weise verwalten wollen, hätten wir unsere Arbeit vor uns. Das wäre insbesondere dann der Fall, wenn wir einfach auf unserem ersten Beispiel aufbauen würden.
Während uns das erste Beispiel zeigt, wie wir eine Objektansicht asynchron ändern können, zeigt es uns nicht, wie wir die Ansicht an den Zustand eines beliebigen Datenobjekts binden können, ganz zu schweigen von einem, das eine Maschine verwaltet. Wir können sicherlich verstehen, wie die setInterval
Demonstration durch einen fetch
ersetzt werden kann, aber wir erhalten möglicherweise nicht einmal den Zustand einer Maschine vom Webserver, der die SVG-enthaltende Seite bereitstellt. Wenn wir die Daten erhalten, müssen unsere Programme jetzt auch die DOM-Struktur der angegebenen Seite kennen.
Glücklicherweise sind Frameworks wie Vue populär geworden und können uns viel Arbeit ersparen.
Es ist ganz einfach, sich über Vue zu informieren. Die Vue-Dokumentation ist sehr zugänglich. Wenn diese Diskussion also zu weit nach vorne springt, können Sie einige Zeit damit verbringen, sich auf der eigenen Website über Vue zu informieren. Aber es gibt sehr gute Diskussionen auf den Smashing-Seiten. Krutie Patel hat einen beeindruckenden Artikel über das Erstellen einer Infografik geschrieben. Souvik Sarkar erklärt uns, wie man mit Vue ein Wetter-Dashboard erstellt.
Gruppenauswahl verwandter Bedienfelder
Für den ersten Schritt sollten wir uns mit der Suche nach Gruppen von Panels befassen. Ein Grund dafür, dies zuerst zu tun, ist, dass es sich um die Rahmenebene unserer menschlichen Interaktionen handelt.
Der Benutzer sucht nach etwas, das ihn interessiert. Vielleicht interessiert er sich für alle Geräte an Standorten in einer Stadt. Vielleicht hat er viele Chargen flüssiger Produkte und möchte sich auf einen Produkttyp beschränken, wobei jede Charge von einer kleinen Sammlung von IoT-Geräten gesteuert wird. Der Benutzer wird also zuerst suchen, um eine kleine Liste zu erhalten.
Hier ist der Prozess:
- Suchen Sie nach Gruppen von Panels nach Merkmalen/Parametern.
- Zeigen Sie eine Liste mit Symbolen an, die Gruppen darstellen.
- Wählen Sie ein Symbol aus (klicken/tippen).
- Beginnen Sie mit der Verwendung von Panels, die mit dem Symbol gekennzeichnet sind, wenn sie angezeigt werden.
Ein weiterer Grund, warum dies ein guter erster Schritt ist, ist, dass wir Vue in seiner einfachsten Form verwenden können. Keine Build-Tools erforderlich. Wir fügen einfach vue.js
mit einem script-Tag in HTML ein. Tatsächlich müssen wir es nicht einmal herunterladen. Es gibt eine Website, auf der eine Arbeitskopie von vue.js
wird.
Alles, was wir brauchen, ist das folgende Tag:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
Ich habe das Skript-Tag direkt aus der Vue-Dokumentation zur Installation kopiert.
Jetzt brauchen wir eine Webseite, die Symbole laden und sie zu etwas machen kann, das klickt. Vue macht das ganz einfach. Tatsächlich habe ich gerade eine kleine App geschrieben, um eine Twitter-Liste mit Vue zu verwalten. Es verwaltet nur Textfelder. Da es ein bisschen einfacher ist als ein SPWA mit Symbolen, können wir es uns ansehen und es dann in unser gewünschtes Single-Page-App-Framework ändern.
So sieht die Seite teilweise aus:
Dies sieht aus wie eine ziemlich einfache Seite. Jeder äußere numerische Eintrag ist ein Zeitfenster mit einem oder zwei Tweets darin. Der zweite Tweet ist optional. Wenn Sie einen Tweet bearbeiten, aktualisieren Vue-Mechanismen ein JavaScript-Objekt. Diese Seite überlässt es dem Benutzer, auf die Schaltfläche „Einträge aktualisieren“ zu klicken, um dem Server über seine Schaltflächen-Handler-Funktion mitzuteilen, dass sich etwas geändert hat.
Damit der Button-Handler Daten an den Server weiterleiten kann, muss er das Vue-Datenobjekt in einen JSON-String umwandeln. Jetzt fragen Sie sich vielleicht, wie schwierig es sein wird, ein Vue-Objekt in JSON zu übersetzen. Es stellt sich heraus, dass es sich um eine Codezeile handelt. Sie finden die Zeile im folgenden Quellcode, aber wenn Sie sie schneller finden möchten, ist sie im Absatz nach dem Quellcode hervorgehoben.
Die Seite sieht einfach aus. Der Schein kann trügen. Natürlich sieht die Seite einfach aus, aber ist der Code einfach? Ja, das ist es tatsächlich! Mit Vue verwaltet die Seite die Inhalte der Felder fast wie von Zauberhand. Hier ist der Code:
<!DOCTYPE html> <html lang="en" prefix="og: https://ogp.me/ns#"> <!-- define microdata scope and type --> <head itemscope itemtype="https://schema.org/Article"> <title>Tweet Keeper</title> <style> body { margin: 2em; } .entryart { border: solid 1px navy; width: 80%; padding: 2px; padding-left: 6px; margin-bottom: 3px; background-color: #EEF4EE; } </style> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> </head> <body onload="GetTweets()"> <!-- some old fashioned handling --> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div> <!-- Recognize the name from the Vue doc --> <div itemscope itemtype="https://schema.org/Article"> <h1 itemprop="name">mangage tweets</h1> <p itemprop="description">My personal Tweet engine. This page accesses a personal tweet page that belongs to {{tweetOwner}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button>Update Entries</button> </div> <!-- Here is a Vue loop for generating a lit --> <ol> <li v-for="tweet in tweets"> <!-- here is the first tweet represented as an object with a lable and tweet text --> <div class="entryart"> <input v-model="tweet.def[0].label" /> <input v-model="tweet.def[0].tweet" /> </div> <!-- here is the second tweet in the slot. But, notice that it is optional. --> <div class="entryart" v-if="tweet.def.length > 1"> <input v-model="tweet.def[1].label"/> <input v-model="tweet.def[1].tweet"/> </div> </li> </ol> </div> <script> var twtApp = new Vue({ el: '#tweetAppDiv', data: { tweets: [ // Where is the data? Still on the server.s ], tweetOwner : "Lucky Dude" // picked a name for demo } }); </script> </body> </html> <script> // Notice that you don't have to do everything in the Vue framework. // Here we are using some native API calls var gDefaultPostInfo = { // there server is beyond simple - an example from node.js docs method: 'POST', // or 'PUT' mode: "cors", // no-cors, cors, *same-origin cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached credentials: "same-origin", // include, *same-origin, omit redirect: "follow", // manual, *follow, error referrer: "no-referrer", // no-referrer, *client body: "", headers:{ 'Content-Type': 'application/json' } } // // // recall the "onload" function GetTweets(event) { var url = "https://localhost:8080/twitlist1.json" // We have a fixed file name. fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. twtApp.tweets = newData // the page update right away with new data. }); }); } function sendTweets() { // recall the button up above. This is not a Vue style button, but still in the Vue app. var url = "https://localhost:8080/" var data = twtApp.tweets; // GET THE DATA OUT OF VUE. That's all folks. // // so happens that Vue pulls out the right data and stringifies it. var jdata = JSON.stringify(data); // data can be `string` or {object}! // gDefaultPostInfo.body = jdata; // that's for fetch - not Vue related // fetch(url,gDefaultPostInfo).then(res => { // We use fetch to POST as well as GET res.json() }).then(response => { console.log('Success:', JSON.stringify(response)) // promises }).catch(error => { console.error('Error:', error) }); } // // // </script>
Um also nur die erstaunlichen Zeilen hervorzuheben, die für die Kraft des Frameworks sprechen, wiederholen wir hier:
A. Dies zieht die Daten heraus.
postOptionsObject.body = JSON.stringify(twtApp.tweets);
B. Dadurch werden die Daten in Vue eingegeben und die Bildschirmaktualisierung angezeigt:
twtApp.tweets = JSON.parse(text) // text is the server response
Wie viel Arbeit ist das?
Es sieht so aus, als würde es eine schöne Möglichkeit geben, auszudrücken, wie Daten Panels für IoT aktualisieren.
Lassen Sie uns nun die Tweets in anklickbare Symbole umwandeln, die dazu dienen, Komponenten vom Webserver abzurufen.
Von Tweets bis hin zu Panel-Abrufsymbolen
Die Leute verwenden gerne SVG für Symbole. Sie mögen diese Verwendung für SVG mehr als für andere Dinge, soweit ich das beurteilen kann. Ich gehe nur auf die Anzahl der Websites ein, die in SVG erstellte Symbole verkaufen oder verschenken. Das Verkaufsargument ist, dass Liniengrafiken weniger Bytes haben als Bilder. Und wenn ich nach Listen von Bildern mit schaltflächenähnlichem Verhalten fragen wollte, hätte ich vielleicht nach PNGs oder JPEGs gegriffen, als SVG in Iframes war. But, we can even find libraries in the Vue contributor lists that help us to a serving of icons.
We can turn the tweets page into an icon list returned as a search result. Just a little code has to be changed. Of course, there are a few things to be careful about if we want SVG icons to be loaded as buttons. Vue provides mechanisms for putting HTML into the application. These mechanisms have to be used or DOM elements fetched from the server don't get interpreted.
Here is the kind of rendering you can get from view if you follow your first impulse in creating a handlebars style variable location in the application DOM.
Here is the code that produces the result in the picture:
<div> <div class="entryart"> <span class="oneItem" v-for="icon in iconList"> {{icon}} </span> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } }); </script>
Notice that we have gone from looping over tweets to looping over icons. tweet in tweets
changed into icon in iconList
. Our twtApp
hooks into the DOM element #tweetAppDiv
, while our iconApp
hooks into the DOM element #iconAppTry
. Within the Vue option object, the data
subobject has a tweets
in the first app, and iconList
in the second. The fields are both empty arrays that receive data when the fetch
routine does its job.
But, we have imitated our tweet app too closely. In the code above, the iconList is an array, and the server is expected to send an array of strings. So, let's say the server has sent us HTML, and we have it properly decoded with the array assigned to data.iconList
. Then, the picture above can be seen.
Now, let's change the code just a little. In this revised code, we can see the following:
v-html="icon">
Vue responds to the v-html syntax by putting in the DOM of the icon
element. Notice that the syntax is included after the loop directive as another attribute to the span
tag.
By removing the handlebars
syntax and using v-html
, our picture changes to something more comprehensible:
<div> <div class="entryart"> <span class="oneItem" v-for="icon in iconList" v-html="icon"> </span> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry2', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo } }); </script>
While v-html
is a quick way to do things, the Vue team recommends using components to get the desired HTML into the page. That seems like a good idea, and we shall soon set about doing that.
But, let's use the v-html
syntax for our next example.
It's time to set up our working example for fetching SVG icons. Let's have those icons be responsive to a button click. Once those are working, we can get the panels associated with an icon.
Let's suppose that the SVG required for icons is stored in a database. For our example, we can just fetch a JSON file from the server. The grown-up version of the icon server would store many such files in a database, and deliver them to the page with the same mechanisms.
Also, it's best if the SVG arrives on the page URL encoded since we will be using JSON parse. The SVG can be decoded by calling JavaScript's decodeURIComponent
function.
In order to simulate the response to searching, we can make use of several JSON files. The page can have one button for each file. Here is the code for the page:
<!DOCTYPE html> <html lang="en" prefix="og: https://ogp.me/ns#"> <!-- define microdata scope and type --> <head itemscope itemtype="https://schema.org/Article"> <title>Search Bar</title> <style> body { margin: 2em; } div { margin: 6px; } .entryart { border: solid 1px navy; width: 80%; padding: 2px; padding-left: 6px; margin: 2px; margin-bottom: 3px; background-color: #EEF4EE; } .oneItem { background-color: #EEFFFF; margin: 2px; padding: 4px; border: solid 1px purple; } </style> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> </head> <body> <!-- some old fashioned handling --> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Request MCU Groups</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button>Find All</button> <button>Find 5 Point</button> <button>Find 6 Point</button> </div> <!-- Here is a Vue loop for generating a lit --> <div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div> <script> var iconApp = new Vue({ el: '#iconAppTry', data: { iconList: [ // Where is the data? Still on the server. ], queryToken : "Thermo Batches" // picked a name for demo }, methods : { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } } }); </script> </body> </html> <script> // // recall the "onclick" on the <buttons> function GetIcons(points) { // special file names instead of search parameters // var url = (points == 11) ? "https://localhost:8080/batchQuery-all.json" : ((points == 5) ? "https://localhost:8080/batchQuery-five.json" : "https://localhost:8080/batchQuery-six.json") fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. newData = newData.map(obj => { obj.icon = decodeURIComponent(obj.icon); return(obj) }); iconApp.iconList = newData; // the page update right away with new data. }); }); } </script>
Here is one display of icons that have been fetched from the server:
The data being sent is an array with the following kind of structure:
{ "style" : { "color" : "red", "backgroundColor" : "yellow" }, "icon" : svg1, "name" : "thermos" },
Hier ist svg1
SVG aus einer Datei. Natürlich hätte ein rechtschaffener Server die Struktur aus einer Datenbank genommen, wo das SVG in der Struktur gespeichert wäre.
Hier ist ein Ausschnitt aus dem obigen Code. Dies ist der Code, der den JSON abruft und das Array von Strukturen in der Vue-App platziert. Sie können die Promise-Struktur von fetch
in use sehen. Der Text wird geparst und in der nächsten Zeile wird das codierte SVG decodiert. Eine weitere Zeile und Vue aktualisiert die Seite. Die Anzahl der Schaltflächen in der Schaltflächenleiste entspricht der Länge des JSON-Arrays.
fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = JSON.parse(text); // DATA UPDATE! This is it. newData = newData.map(obj => { obj.icon = decodeURIComponent(obj.icon); return(obj) }); // the page update right away with new data. iconApp.iconList = newData; }); });
Jetzt nur noch zwei Schnipsel. Die Vue-App. Der Leser wird bemerken, dass die @click
Direktive in die Schaltflächen eingefügt wurde. Das Datenelement iconEntry.name
wird in Anführungszeichen an eine Methode übergeben.
Die Methode wird in der Vue-App definiert:
<div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div>
Hier ist das Snippet für die Definition von Methoden. Das methods
wird direkt nach dem data
innerhalb des App-Parameterobjekts hinzugefügt:
, methods: { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } }
Der Leser sollte die goGetPanel
Definition finden, auf deren Verwendung für den @click
Handler hingewiesen wurde. In unserer letzten Anwendung kann der alert
durch eine Funktion ersetzt werden, die Panels vom Server abruft.
Eine Komponentenbibliothek für IoT-Panels
Wir könnten einfach entscheiden, dass Panels, die wir vom Server abrufen, HMTL- oder nur SVG-Zeichnungen sein können, aber wenn es viele Arten von Panels geben wird, würden wir hoffen, dass die Aufgabe des Erstellens von Panels durch Bibliotheken mit Komponenten vereinfacht werden könnte wähle aus. Wir können uns vorstellen, dass SVG-Editoren verbessert werden könnten, damit Bibliothekskomponenten als Teil der Bearbeitung auf Bilder gezogen werden können. Wenn der SVG-Editor dann eine Version des Bildes mit Komponenten-Tags ausgeben könnte, würde die Verwendung von Vue die Erstellung des Bildes ermöglichen und gleichzeitig sicherstellen, dass die JavaScript-Automatisierung und -Animation sauber miteinander verwoben sind. Für unsere Diskussion kann uns etwas Handbearbeitung helfen, dorthin zu gelangen.
Wenn wir Panels aus Vue-Komponenten erstellen wollen, sollten wir besser herausfinden, wie wir die Komponenten herstellen und sie dann zu etwas Nützlichem zusammenfügen. Wir müssen auf die von Vue bereitgestellten Befehlszeilentools umsteigen und unseren Workflow organisieren.
Komponenten
Die Vue-Dokumentation weist darauf hin, dass der Komponentendatenabschnitt (Unterobjekt) der Komponentendefinition eine Funktion sein muss, die data
zurückgibt. Der Grund dafür ist, dass Vue die Daten zwischen den Instanzen getrennt halten muss. Beim Übergang von einer Vue-Anwendungsinitialisierung zu einer Komponentendefinition gibt es also eine weitere kleine Codeänderung.
In diesem ersten Codeschnipsel wird eine Vue-Anwendung initialisiert:
var iconApp = new Vue({ el: '#iconApp', data: { // this is the data field that can be easily updated }, methods : { ... } });
In diesem neuen Codeausschnitt wird eine Komponente definiert und registriert. Beachten Sie zunächst, dass statt einer new Vue
Instanz eine Komponente mit dem Namen iconic
registriert wird. Dann gibt das data
benutzerdefinierte Daten für jede iconic
Instanz zurück, die die Vue-App erstellt. Schließlich ist das template
am Ende der Komponentenregistrierung vorhanden. Jeder HTML-Code, der möglicherweise auf der Webseite geschrieben wurde, um die Komponente anzuzeigen, kann Teil der template
sein.
Vue.component('iconic', data: () => { var instanceData = { // data fields named for the // variables appearing in the template onevar : "test" } return(instanceData); }, methods : { ... }, template: '<div>This appears in every instance {{onevar}}</div>' });
Wir können uns also ein Panel mit Thermometern vorstellen. Wenn also jemand eine thermometer
bereitstellt, würden wir irgendwo in unserem Code eine Komponentendefinition erwarten. So wie:
Vue.component('thermometer', data: () => { var instanceData = { // data fields named for the // variables appearing in the template temperature : 0 } return(instanceData); }, methods : { ... }, template: '<div>Some SVG will go here</div>' });
Wir versuchen, etwas zu erstellen, das so aussieht:
Die Thermometer-Komponente ist den ersten Komponenten sehr ähnlich, auf die Sie in den Vue-Tutorials stoßen werden. Aber es ist ein wenig schwierig herauszufinden, wie man es aktualisiert. Es gibt eine bessere Möglichkeit, die Komponente für die Reaktivität mithilfe von Eigenschaften zu definieren. Und zwar im Folgenden:
Vue.component('thermometer', { props: ['temperature'], computed : { y: function() { var t = this.temperature/100; var h = 54.724472; var y_bar = 41.176476 // starts near the top // pretend the scale is 1 to 100, so that the temperature is a precentage return((1 - t)*h + y_bar) }, height : function() { var t = this.temperature/100; var h = 54.724472; // as high as the whole range var y_bar = 41.176476 // pretend the scale is 1 to 100, so that the temperature is a precentage return(t*h) } }, template: '#thermometer-template' })
Anstatt also die Temperatur als Datenelement darzustellen. Es wird als Eigenschaft unter props
dargestellt. Dann gibt es einen neuen Abschnitt, computed , der Variablen bereitstellt, die Funktionen der Eigenschaft sind. Wir sehen, dass this.temperature
sowohl für y
als auch für height
verwendet wird. Diese berechneten Variablen werden im SVG als Attribute für ein Rechteck verwendet.
In SVG wächst y
von oben nach unten. Wenn wir also wollen, dass das Rechteck am unteren Rand des Thermometers klein ist, muss das y
des roten Kästchens niedriger sein, und die Höhe muss reduziert werden, sodass ( y + height
) auf dem Nullpunkt des Thermometers bleibt.
Beachten Sie das template
in der Definition der Komponenten. Es ist tatsächlich eine Dokumentelement-ID. Das Element, auf das verwiesen wird, ist ein Skriptabschnitt mit dem speziellen Typ: type="text/x-template"
. Das script-Element ist dort, wo sich das SVG für die Thermometer befindet. Und das SVG verwendet Vue-Variablen und Steuerbegriffe, sodass die Reaktivität definiert werden kann.
Hier sind einige der SVG:
<script type="text/x-template"> <svg xmlns:svg="https://www.w3.org/2000/svg" xmlns="https://www.w3.org/2000/svg" width="20" height="70" version="1.1" > <g transform="translate(0,-180)"> <g transform="matrix(2.0111869,0,0,1.0489665,-215.11053,144.5592)"> <rect stroke-linecap="null" stroke-linejoin="null" width="2.9665921" height="54.724472" x="111.90748" y="41.176476" /> <rect stroke-linecap="null" stroke-linejoin="null" width="2.9665921" x="111.90748" :height="height" :y="y" /> <g transform="matrix(0.76503813,0,0,1,26.586929,0)"> <line y2="57.306953" y1="57.306953" x2="113.15423" x1="107.22105" stroke-linejoin="null" stroke-linecap="null" /> <line y2="74.408356" y1="74.408356" x2="113.15423" x1="107.22105" stroke-linejoin="null" stroke-linecap="null"
Der Leser kann oben id="thermometer-template"
finden, und weiter unten zu den rect
-Elementen können die berechneten Variablen gefunden werden.
Hier werden die variablen Verwendungen getrennt. Die Vue-Kurzsyntax für v-bind
wird verwendet, mit :height="height"
und dasselbe für y
:
x="111.90748" :height="height" :y="y"
Wenn das übergeordnete Element der SVG-Elemente Variablen festlegt, die als Eingabe für die Thermometereigenschaft temperature
dienen, berechnet Vue height
und y
neu. Dadurch ändern sich Position und Höhe des roten Kästchens.
Es ist hilfreich, eine Auflistung der Vue-App zu haben, die das Thermometer verwendet.
<body> <!-- The Vue app starts here. This is the HTML part of the Vue object --> <div> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Set Temperature</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <!-- {{tweetOwner}} is in the data model. --> <button @click="updateTemp(50,50)">mid</button> <button @click="updateTemp(20,80)">low</button> <button @click="updateTemp(80,20)">high</button> </div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> <script> var thermoApp = new Vue({ el: '#thermoApp', data: { temp1 : 30, temp2 : 60, queryToken : "HEAT" }, methods : { updateTemp: function (tval1,tval2) { this.temp1 = tval1; this.temp2 = tval2; } } }); </script> </body>
Das ist das Ganze. Es gibt drei Schaltflächen, die die updateTemp
-Methode der thermoApp
Vue-Anwendung aufrufen. Der Datenabschnitt hat zwei Temperaturvariablen. Und jedes thermometer
aktualisiert seine Temperatur, wenn sich die Werte ändern.
Den Code für die beiden unten genannten Thermometer finden Sie in dem der Vue-App zugewiesenen HTML.
<thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer>
Beachten Sie, dass die Anwendung den function
für die Methodendefinition verwendet. updateTemp
auf diese Weise definieren updateTemp: function (tval1,tval2)
ermöglicht den Zugriff auf die Instanzvariable this
.
Wenn Sie updateTemp
auf diese Weise definieren, updateTemp: (tval1,tval2) =>
weist this
einer internen Datenstruktur zu, die nicht reagiert und die Ansicht aktualisiert.
Zusammenbau eines Panels
Jedes IoT-Panel kann eine Komponente sein. Vue bietet eine Möglichkeit, Komponenten mit Unterkomponenten zu definieren. Alternativ gibt es einen Slot-Mechanismus, der verwendet werden kann, um eine Komponente zu erhalten, die jeden HTML-Inhalt umschließen kann.
Sehen wir uns in den folgenden Abschnitten an, wie ein Panel aus Unterkomponenten erstellt wird. Es gibt zwei Formen, die sich schnell aus unseren Beispielen ergeben. In einem Fall können die Thermometer Unterkomponenten sein, die in JavaScript aufgerufen werden. In einem anderen Fall werden die Komponenten unabhängig voneinander definiert, aber im HTML erwähnt.
In beiden Fällen kann das gleiche HTML für die Vorlage verwendet werden. Hier unser Panel als Vorlage:
<script type="text/x-template"> <div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> </script>
Der einzige Unterschied zwischen der ersten Detaillierung der Anwendung besteht darin, dass ein div
Element die beiden Thermometer umgibt. Vue gibt einen Fehler aus, wenn der Vorlage ein DOM-Element der obersten Ebene fehlt. Das div
erfüllt die Vue-Anforderung und die mehreren Elemente können darin enthalten sein.
Jetzt können wir die beiden Thermometer nebeneinander sehen. Wenn die Temperaturen von oben zum letzten Thermometer geleitet werden, kaskadieren die Werte nach unten. Auf der obersten Ebene tritt das Panel der Anwendung bei, wenn eine einzelne Zeile im Anwendungs-DOM enthalten ist.
<themo-panel :temp1="temp1" :temp2="temp2" ></themo-panel>
Die Vorlage für das Panel scheint, obwohl einfach, darauf hinzudeuten, dass Panels in Bezug auf Komponenten einfach entworfen werden können. Es ist, als ob eine Sprache nur für IoT-Komponenten möglich wäre.
Jetzt ist die Vorlagendefinition für das Panel einfach genug. Hier ist es mit den unabhängig voneinander definierten Unterkomponenten:
Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template' });
Das ist ungefähr so viel, wie erforderlich ist, um das Panel funktionsfähig zu machen. Es stimmt, dass diese Version auf einer langen Liste von Eigenschaften beruht, um Werte zu definieren, die aktualisiert werden, wenn Nachrichten auf der Seite eingehen. Aber das ist ein guter Anfang. Das Aktualisieren des data
auf der obersten Ebene erledigt die Aufgabe, die Thermometer zu animieren. Wenn die Panels jedoch komplizierter werden, muss möglicherweise eine andere Methode zum Anzeigen von Änderungen gefunden werden.
Nachdem wir die anderen Möglichkeiten zur Angabe von Unterkomponenten für das Panel erwähnt haben, sollten wir uns diese ansehen. Hier ist es:
Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template', components: { // a sub component for the labels 'thermometer': { props: { temperature: Number, }, template: '#thermometer-template', computed : { y: function() { var t = this.temperature/100; var h = 54.724472; var y_bar = 41.176476 // starts near the top // pretend the scale is 1 to 100, so that the temperature is a precentage return((1 - t)*h + y_bar) }, height : function() { var t = this.temperature/100; var h = 54.724472; // as high as the whole range var y_bar = 41.176476 // pretend the scale is 1 to 100, so that the temperature is a precentage return(t*h) } } } } });
Es gibt sicherlich mehr Code, aber das liegt daran, dass das JavaScript für die thermometer
-Komponente in der Komponentenliste von thermo-panel
enthalten ist. Die beiden Ansätze erfüllen die gleiche Aufgabe, bieten jedoch unterschiedliche Möglichkeiten zum Packen von Komponentendefinitionen.
Im Moment bevorzuge ich den ersten Weg. Es sollte wesentlich einfacher sein, Panels zu überarbeiten und sie dynamisch abrufen zu lassen, wenn nur Vorlagen und Eigenschaften geändert werden müssen. Dazu bilden die eigenständig definierten Komponenten eine Komponentenbibliothek. Aber obwohl das besser erscheint, wird es im Folgenden bequemer, die zweite, scheinbar ausführlichere Methode zu verwenden.
Da wir responsive Panels auf klar definierte Weise aus Komponenten erstellen können, werde ich im nächsten Teil meines Artikels erklären, wie wir sie als Datenbank verwalten können, die einfache Abfragen durchführen kann.