Komponenty strony internetowej SVG dla IoT i twórców (część 1)

Opublikowany: 2022-03-10
Krótkie podsumowanie ↬ IoT rozwija się, obejmując wiele urządzeń z wieloma właścicielami. Twórcy stron internetowych staną przed problemem znalezienia sposobów na umożliwienie właścicielom interakcji z ich urządzeniami. Ale ten problem rodzi wiele interesów. Przyjrzyjmy się niektórym aspektom tworzenia stron internetowych dla Internetu rzeczy (IoT), na które już istnieje zapotrzebowanie.

Rynek IoT jest wciąż na wczesnym etapie, ale nabiera rozpędu. Jesteśmy u szczytu historii IoT. Rynki rozwijają się czterokrotnie w ciągu pięciu lat, od 2015 do 2020 roku. Dla twórców stron internetowych ten wzrost IoT jest znaczący. Już teraz istnieje duże zapotrzebowanie na techniki internetowe IoT.

Wiele urządzeń będzie rozmieszczonych geoprzestrzennie, a ich właściciele będą chcieli zdalnego sterowania i zarządzania. Aby móc tworzyć kanały do ​​teleoperacji, należy wykonać pełne stosy sieciowe. Ponadto interakcja będzie odbywać się jednocześnie z jednym lub większą liczbą urządzeń IoT. Interakcja musi odbywać się w czasie rzeczywistym świata fizycznego.

Ta dyskusja zagłębia się w wymagania interfejsu przy użyciu Vue.js jako katalizatora i ilustruje jedną z wielu metod komunikacji między stronami internetowymi z wielu substytucji.

Oto niektóre z celów zaplanowanych w tej dyskusji:

  1. Utwórz jednostronicową aplikację internetową SPWA, która obsługuje grupy interfejsów człowiek-maszyna IoT (możemy nazywać te „grupy paneli”);
  2. Wyświetlanie list identyfikatorów grup paneli w wyniku odpytywania serwera;
  3. Wyświetl panele wybranej grupy w wyniku zapytania;
  4. Upewnij się, że wyświetlacz panelu jest ładowany leniwie i szybko się animuje;
  5. Upewnij się, że panele synchronizują się z urządzeniami IoT.
Więcej po skoku! Kontynuuj czytanie poniżej ↓

IoT i szybki rozwój stron internetowych

Prezentacja grafiki do wizualizacji i zdalnej kontroli sprzętu wraz z synchronizacją stron internetowych z fizycznymi procesami w czasie rzeczywistym są w sferze rozwiązywania problemów ze stronami internetowymi nieodłącznie związanych z przyszłością Internetu Rzeczy.

Wielu z nas rozpoczyna poszukiwania technik prezentacji IoT, ale istnieje kilka standardów internetowych wraz z kilkoma technikami prezentacji, których możemy zacząć używać już teraz. Gdy wspólnie badamy te standardy i techniki, możemy dołączyć do fali Internetu Rzeczy.

Kokpity i wizualizacja danych są pożądane. Ponadto istnieje duże zapotrzebowanie na wykraczanie poza strony internetowe zawierające formularze, listy wyświetlania lub treści tekstowe. Kokpity dla IoT muszą być piktograficzne, animowane. Animacje muszą być zsynchronizowane z procesami fizycznymi w czasie rzeczywistym, aby zapewnić użytkownikom rzeczywisty widok stanu maszyny. Stan maszyny, taki jak płomień lub brak płomienia, przewyższa stan aplikacji i dostarcza operatorom krytyczne informacje, być może nawet informacje dotyczące bezpieczeństwa.

Kokpity wymagają czegoś więcej niż wizualizacji danych. Musimy pamiętać, że rzeczy częścią IoT to urządzenia, które nie tylko mają czujniki, ale także interfejsy sterujące. W implementacjach sprzętowych MCU są rozszerzone o przełączniki, przełączniki progowe, ustawienia parametrów i nie tylko. Mimo to strony internetowe mogą zastąpić te elementy sterowania sprzętem .

Nic nowego. Interfejsy komputerowe dla sprzętu istnieją już od dłuższego czasu, ale szybki wzrost wykorzystania stron internetowych dla tych interfejsów jest częścią naszego obecnego doświadczenia. WebRTC i Speech API są na ścieżce rozwoju, która rozpoczęła się w 2012 roku. WebSockets rozwijał się w podobnym czasie.

IoT był w naszych głowach od dawna. IoT jest częścią ludzkiego dialogu od 1832 roku. Ale IoT i łączność bezprzewodowa, jak zaczynamy wiedzieć, zostały wyobrażone przez Teslę około 1926 roku. Artykuł, który zainteresuje twórców stron internetowych, przedstawia pulpity nawigacyjne:

„Wcześniejsi użytkownicy lub zwolennicy IoT nadają priorytet pulpitom nawigacyjnym, raportom, przypadkom użycia IoT, które zapewniają strumienie danych integralne z analizą, zaawansowaną wizualizacją i eksploracją danych”.

Rynek IoT jest ogromny. Ten artykuł dotyczący wielkości rynku podaje prognozę dotyczącą liczby urządzeń, które się pojawią: 2018: 23,14 miliarda ⇒ 2025: 75,44 miliarda. I próbuje umieścić na nim dane finansowe: 2014: \2,99 bln USD ⇒ 2020: 8,90 bln USD. Zapotrzebowanie na umiejętności IoT będzie najszybciej rosło: IoT in Demand.

Gdy opracowujemy przejrzyste interfejsy do sterowania i monitorowania urządzeń, napotykamy nowy problem w rozwoju naszych interfejsów. Wszystkie miliardy urządzeń będą własnością wielu osób (lub organizacji). Ponadto każda osoba może posiadać dowolną liczbę urządzeń. Być może nawet część urządzeń zostanie udostępniona.

Nowoczesne interfejsy, które zostały stworzone do sterowania maszynami, często mają dobrze zdefiniowany układ, specyficzny dla konkretnej maszyny lub instalacji kilku maszyn. Na przykład w inteligentnym domu, wysokiej klasy system będzie miał wyświetlacz LCD z panelami na starannie rozmieszczone urządzenia. Jednak wraz z rozwojem sieciowej wersji IoT pojawi się dowolna liczba paneli dla dynamicznego, a nawet mobilnego strumienia urządzeń.

Zarządzanie panelami urządzeń przypomina zarządzanie połączeniami społecznościowymi w serwisach społecznościowych.

„Nasze interfejsy użytkownika będą musiały być dynamiczne w zarządzaniu, które silnie animowane panele czasu rzeczywistego muszą być wyświetlane w dowolnym momencie dla każdego konkretnego użytkownika”.

Pulpit nawigacyjny to pojedyncza aplikacja internetowa SPWA. I możemy sobie wyobrazić bazę paneli. Tak więc, jeśli pojedynczy użytkownik zamierza uzyskać dostęp do wielu paneli i konfiguracji dla swoich urządzeń rozsianych po całej planecie, SPWA musi uzyskać dostęp do komponentów panelu na żądanie. Panele i niektóre obsługujące je JavaScript będą musiały ładować się leniwie.

„Nasze interfejsy będą musiały współpracować z frameworkami stron internetowych, które umożliwiają włączenie asynchronicznych powiązań komponentów bez ponownego inicjowania ich frameworków”.

Użyjmy Vue.js, WebSockets, MQTT i SVG, aby wejść na rynek IoT.

Zalecana literatura : Tworzenie interaktywnej infografiki za pomocą Vue.js

Architektura wysokiego poziomu dla aplikacji internetowej IoT

Projektując interfejs dla strony internetowej IoT, zawsze mamy wiele możliwości. Jedną z opcji może być dedykowanie jednej strony jednemu urządzeniu. Strona może być nawet renderowana po stronie serwera. Serwer miałby za zadanie wysłać zapytanie do urządzenia, aby uzyskać wartości z czujników, a następnie umieścić je w odpowiednich miejscach w ciągu HTML.

Wielu z nas zna narzędzia, które umożliwiają pisanie szablonów HTML ze specjalnymi znacznikami, które wskazują, gdzie umieścić wartości zmiennych. Zobaczenie {{temperature}} w takim szablonie mówi nam i silnikowi widoku , aby pobrać temperaturę z urządzenia i zastąpić nią symbol {{temperature}} . Tak więc po odczekaniu, aż serwer zapyta urządzenie, urządzenie odpowie, wyrenderuje stronę i dostarczy stronę, użytkownik w końcu będzie mógł zobaczyć temperaturę raportowaną przez urządzenie.

W przypadku tej strony według architektury urządzenia, użytkownik może następnie chcieć wysłać polecenie do urządzenia. Nie ma problemu, może wypełnić formularz HTML i przesłać. Serwer może nawet mieć trasę tylko dla urządzenia, a może, nieco sprytniej, trasę dla typu urządzenia i identyfikatora urządzenia. Serwer przetłumaczyłby następnie dane z formularza na komunikat do wysłania do urządzenia, zapisałby go do jakiegoś programu obsługi urządzenia i czekał na potwierdzenie. Następnie serwer może w końcu odpowiedzieć na żądanie postu i poinformować użytkownika, że ​​wszystko jest w porządku z urządzeniem.

Architektura strony internetowej do traktowania IoT jako serwera formularzy - szukanie czegoś lepszego.
Architektura strony internetowej do traktowania IoT jako serwera formularzy — szukanie czegoś lepszego. (duży podgląd)

Wiele systemów CMS działa w ten sposób w celu aktualizacji wpisów na blogu i tym podobnych. Nic w tym nie wydaje się dziwne. Wygląda na to, że HTML przez HTTP zawsze miał konstrukcję umożliwiającą pobieranie wyrenderowanych stron i wysyłanie danych formularzy do obsługi przez serwer WWW. Co więcej, do wyboru są tysiące CMS-ów. Tak więc, aby uruchomić nasz system IoT, rozsądne wydaje się przebrnięcie przez te tysiące CMS-ów, aby zobaczyć, który z nich jest odpowiedni do pracy. Albo możemy na początek zastosować jeden filtr na CMS-ach.

Musimy wziąć pod uwagę naturę tego, z czym mamy do czynienia w czasie rzeczywistym. Tak więc, chociaż HTML w swojej oryginalnej formie jest całkiem dobry do wielu zadań korporacyjnych, potrzebuje trochę pomocy, aby stać się mechanizmem dostarczania do zarządzania IoT. Potrzebujemy więc CMS lub niestandardowego serwera WWW, który pomoże HTMLowi wykonać tę pracę IoT. Możemy również pomyśleć o serwerze, ponieważ założymy, że CMS zapewnia funkcjonalność serwera. Musimy tylko pamiętać, że serwer musi zapewnić animację sterowaną zdarzeniami, więc strona nie może być w 100% sfinalizowana w postaci statycznego wydruku.

Oto kilka parametrów, które mogą kierować wyborami naszej strony internetowej połączonej z urządzeniem, czynności, które powinna zrobić:

  1. Odbieraj dane z czujników i inne komunikaty o stanie urządzenia asynchronicznie ;
  2. Renderuj dane z czujnika dla strony w kliencie (prawie w następstwie do 1);
  3. Publikuj polecenia na określonym urządzeniu lub grupie urządzeń asynchronicznie ;
  4. Opcjonalnie wyślij polecenia przez serwer lub omiń go.
  5. Bezpiecznie utrzymuj relację własności między urządzeniem a użytkownikiem;
  6. Zarządzaj działaniem urządzeń o znaczeniu krytycznym, nie ingerując ani nie nadpisując.

Lista ta przychodzi na myśl, gdy myślimy o jednej stronie pełniącej rolę interfejsu do wybranego urządzenia . Chcemy móc swobodnie komunikować się z urządzeniem, jeśli chodzi o polecenia i dane.

Jeśli chodzi o stronę, wystarczy raz poprosić o nią serwer WWW. Oczekujemy, że serwer WWW (lub powiązana aplikacja) zapewni bezpieczną ścieżkę komunikacji. A ścieżka nie musi przebiegać przez serwer, a może powinna całkowicie omijać serwer, ponieważ serwer może mieć zadania o wyższym priorytecie inne niż dbanie o komunikację jednej strony dla danych pochodzących z czujników.

W rzeczywistości możemy sobie wyobrazić dane przychodzące z czujnika raz na sekundę i nie spodziewalibyśmy się, że sam serwer sieciowy zapewni stałą sekundę do drugiej aktualizacji dla tysięcy pojedynczych strumieni czujników pomnożonych przez tysiące widzów. Oczywiście serwer sieciowy można podzielić na partycje lub skonfigurować w ramach równoważenia obciążenia, ale istnieją inne usługi dostosowane do dostarczania czujników i przekazywania poleceń do sprzętu.

Serwer sieciowy będzie musiał dostarczyć pewien pakiet, aby strona mogła ustanowić bezpieczne kanały komunikacji z urządzeniem. Musimy uważać na wysyłanie wiadomości na kanałach, które nie zapewniają pewnego zarządzania rodzajem przesyłanych wiadomości. Musi istnieć pewna wiedza na temat tego, czy urządzenie jest w trybie, który może zostać przerwany, czy też może wystąpić żądanie działania użytkownika, jeśli urządzenie wymknie się spod kontroli. Tak więc serwer WWW może pomóc klientowi w uzyskaniu odpowiednich zasobów, które mogą dowiedzieć się więcej o urządzeniu. Przesyłanie wiadomości może odbywać się za pomocą czegoś w rodzaju serwera MQTT. I mogą istnieć pewne usługi przygotowania serwera MQTT, które mogą zostać uruchomione, gdy użytkownik uzyska dostęp do swojego panelu za pośrednictwem serwera WWW.

Ze względu na świat fizyczny z jego wymaganiami w czasie rzeczywistym oraz ze względu na dodatkowe względy bezpieczeństwa, nasz diagram różni się nieco od oryginału.

Aplikacja z jedną stroną, która komunikuje się z jednym MCU.
Aplikacja z jedną stroną, która komunikuje się z jednym MCU. Teraz współdziała asynchronicznie z MCU niezależnie od serwera strony internetowej. (duży podgląd)

Nie możemy się tutaj zatrzymać. Konfiguracja jednej strony na urządzenie, nawet jeśli jest responsywna i dobrze obsługuje komunikację, nie jest tym, o co prosiliśmy. Musimy założyć, że użytkownik zaloguje się na swoje konto i uzyska dostęp do swojego pulpitu nawigacyjnego. Stamtąd poprosi o listę projektów dotyczących treści (najprawdopodobniej projektów, nad którymi pracuje). Każda pozycja na liście będzie odnosić się do pewnej liczby zasobów. Gdy wybierze element poprzez kliknięcie lub dotknięcie, uzyska dostęp do kolekcji paneli, z których każdy będzie zawierał informacje o konkretnym zasobie lub urządzeniu IoT.

Dowolna liczba paneli dostarczonych w odpowiedzi na zapytanie wygenerowane w wyniku działania interfejsu użytkownika może być panelami, które współdziałają z urządzeniami na żywo. Tak więc, gdy tylko pojawi się panel, oczekuje się, że będzie wykazywał aktywność w czasie rzeczywistym i był w stanie wysłać polecenie do urządzenia.

To, jak panele są postrzegane na stronie, jest decyzją projektową. Mogą to być pływające okna lub pudełka na przewijanym tle. Niezależnie od tego, jak się to przedstawia, panele będą odliczać czas, temperaturę, ciśnienie, prędkość wiatru lub cokolwiek innego, co możesz sobie wyobrazić. Spodziewamy się, że panele będą animowane w różnych skalach graficznych. Temperaturę można przedstawić jako termometr, prędkość jako półokrągły wskaźnik prędkości, dźwięk jako przebieg strumienia i tak dalej.

Serwer sieciowy ma za zadanie dostarczać właściwe panele właściwemu użytkownikowi, podając zapytania do bazy danych paneli i biorąc pod uwagę, że urządzenia muszą być fizycznie dostępne. Co więcej, biorąc pod uwagę, że będzie wiele różnych rodzajów urządzeń, panele dla każdego urządzenia będą prawdopodobnie różne. Tak więc serwer WWW powinien być w stanie dostarczyć informacje piktograficzne potrzebne do renderowania panelu. Jednak strona HTML pulpitu nawigacyjnego nie powinna być ładowana ze wszystkimi możliwymi panelami. Nie ma pojęcia, ile ich będzie.

Oto kilka parametrów, które mogą kierować wyborami na naszej stronie pulpitu nawigacyjnego, rzeczy, które powinna zrobić:

  1. Zaprezentuj sposób wyboru grup powiązanych paneli urządzeń;
  2. Korzystaj z mechanizmów jednoczesnej komunikacji urządzeń dla pewnej liczby urządzeń;
  3. Aktywuj panele urządzeń, gdy użytkownik ich zażąda;
  4. Włącz leniwie załadowaną grafikę, aby uzyskać unikalne projekty paneli;
  5. Korzystaj z tokenów bezpieczeństwa i parametrów w odniesieniu do każdego panelu;
  6. Zachowaj synchronizację ze wszystkimi urządzeniami pod kontrolą użytkownika.
Aplikacja jednostronicowa, która komunikuje się z wieloma MCU, asynchronicznie i niezależnie od serwera strony internetowej.
Aplikacja jednostronicowa, która komunikuje się z wieloma MCU, asynchronicznie i niezależnie od serwera strony internetowej. (duży podgląd)

Możemy zacząć widzieć, jak zmienia się gra, ale w świecie projektowania pulpitów, gra od jakiegoś czasu zmienia się tu i tam. Musimy tylko zawęzić się do niektórych aktualnych i przydatnych narzędzi do tworzenia stron, aby zacząć działać.

Zacznijmy od tego, jak możemy wyrenderować panele. To już wydaje się być dużym zadaniem. Wyobrażamy sobie wiele różnych rodzajów paneli. Ale jeśli kiedykolwiek korzystałeś z muzycznego DAW, zobaczysz, jak wykorzystali grafikę, aby panele wyglądały jak urządzenia analogowe używane przez zespoły dawno temu. Wszystkie panele w DAW są rysowane przez wtyczki działające na dźwięku. W rzeczywistości wiele z tych wtyczek DAW może używać SVG do renderowania swoich interfejsów. Ograniczamy się więc do obsługi interfejsów SVG, którymi z kolei może być dowolna grafika, jaką możemy sobie wyobrazić.

Wybór SVG dla paneli

Oczywiście lubię DAWy i użyłbym tego jako przykładu, ale SVG jest standardem dla stron internetowych. SVG to standard W3C. Służy do przenoszenia rysunków liniowych na strony internetowe. SVG był kiedyś obywatelem drugiej kategorii na stronie internetowej, wymaganym do życia w iFrame. Ale od czasu HTML5 jest obywatelem pierwszej klasy. Być może, gdy SVG2 wyjdzie, będzie mógł korzystać z elementów formularzy. Na razie elementy formularza są obiektami obcymi w SVG. Ale to nie powinno nas powstrzymać przed zrobieniem SVG jako podłoża dla paneli.

SVG można rysować, przechowywać do wyświetlania i można go leniwie ładować. W rzeczywistości, gdy będziemy badać system komponentów, zobaczymy, że SVG może być używane w szablonach komponentów. W tej dyskusji będziemy używać Vue.js do tworzenia komponentów dla paneli.

Rysowanie SVG nie jest trudne, ponieważ istnieje wiele programów do rysowania linii, które są łatwe do zdobycia. Jeśli wydasz pieniądze, możesz pobrać Adobe Illustrator, który eksportuje SVG. Inkscape był od jakiegoś czasu goto do tworzenia SVG. Jest open source i działa dobrze w systemie Linux, ale można go również uruchomić na komputerach Mac i Windows. Następnie istnieje kilka programów do edycji stron internetowych SVG, które są open source, a także niektóre wersje SaaS.

Rozglądałem się za internetowym edytorem SVG o otwartym kodzie źródłowym. Po pewnym rozejrzeniu się natknąłem na SVG-Edit. Możesz umieścić go na swoich stronach internetowych, na przykład jeśli tworzysz blog oparty na SVG lub coś takiego.

Schemat elektryczny w SVG gotowy do animacji.
Schemat elektryczny jest dość szczegółowy, ale możemy go łatwo uzyskać w SVG i animować za pomocą niewielkiego kodu. (duży podgląd)

Gdy zapisujesz swoją pracę do pliku, SVG-Edit pobiera ją w przeglądarce i możesz pobrać plik z katalogu pobierania.

Rysunek, który narysowałem, pokazuje bramkę AND kontrolującą integrator. To nie jest to, czego zwykle można by się spodziewać w panelu dla MCU. Panel może mieć przycisk do zasilania jednego z wejść bramki AND. Wtedy może mieć wyświetlacz z ADC, który odczytuje dane wyjściowe integratora. Być może będzie to wykres liniowy na osi czasu. Większość paneli będzie miała grafikę, która pozwoli użytkownikowi odnieść się do tego, co dzieje się wewnątrz MCU. A jeśli nasz obwód będzie żył gdziekolwiek, będzie to wewnątrz MCU.

Mimo to nasz schemat elektroniczny może być wykorzystany do omówienia animacji. To, co chcemy zrobić, to spojrzeć na SVG i zobaczyć, gdzie możemy znaleźć niektóre tagi DOM, które chcielibyśmy w jakiś sposób zmienić. Następnie możemy animować SVG za pomocą małego JavaScriptu i timera. Sprawmy, aby bramka AND mrugała różnymi kolorami.

Plik SVG, którego szukamy, znajduje się w poniższym polu kodu. Nie wygląda to zbyt przyjaźnie dla programisty, chociaż użytkownik będzie całkiem zadowolony. Niemniej jednak nadal istnieje kilka wskazówek, aby znaleźć element DOM, na którym chcemy operować. Po pierwsze, większość narzędzi do rysowania SVG ma sposób na uzyskanie właściwości obiektu, w szczególności atrybutu id . SVG-Edit też ma swój sposób. W edytorze wybierz bramkę AND i obserwuj pasek narzędzi. Zobaczysz również pole na id i class CSS.

Jedno z narzędzi do rysowania SVG ze sposobem przechwytywania identyfikatora obiektu za pomocą dostarczonego interfejsu.
Jedno z narzędzi do rysowania SVG ze sposobem przechwytywania identyfikatora obiektu za pomocą dostarczonego interfejsu. (duży podgląd)

Jeśli z jakiegoś powodu nie możesz dostać się do narzędzia do edycji, możesz otworzyć SVG w przeglądarce i sprawdzić DOM. W każdym razie stwierdziliśmy, że nasza brama miała id = „svg_1”.

 <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>

Wszystko czego teraz potrzebujemy to trochę JavaScript. Najpierw zwracamy uwagę, że atrybut elementu „fill” jest obecny. Następnie jest tylko prosty program, który następuje:

 <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>

Zauważ, że mamy minimalną stronę HTML. Możesz wyciąć i wkleić kod do swojego ulubionego edytora. A potem nie zapomnij wyciąć i wkleić SVG, aby zastąpić komentarz. Moja wersja przeglądarki Chrome wymaga, aby strona była w formacie HTML, aby zawierała sekcję JavaScript. Jest to więc jedna przeglądarka, która nadal traktuje SVG jako coś oddzielnego. Ale to długa droga od czasów <iframe> .

Jeśli dobrze wytniesz i wkleisz, możesz wywołać stronę i zobaczyć, jak bramka AND zmienia się z czerwonego na zielony w kółko.

Zalecana literatura : Rozkład okręgów SVG na ścieżki

Panele budowlane z komponentów VUE

Jesteśmy już na dobrej drodze, aby ożywić każdy pojedynczy panel, ale jeśli chcemy zarządzać dużymi zbiorami paneli w rozsądny sposób, nasza praca jest dla nas cięta. Byłoby tak szczególnie w przypadku, gdybyśmy po prostu budowali na naszym pierwszym przykładzie.

Chociaż pierwszy przykład pokazuje nam, jak możemy asynchronicznie zmienić widok obiektu, nie pokazuje nam, jak powiązać widok ze stanem dowolnego obiektu danych, nie mówiąc już o tym, który zarządza maszyną. Z pewnością możemy zrozumieć, w jaki sposób demonstracja setInterval może zostać zastąpiona przez program obsługi fetch , ale możemy nawet nie uzyskać stanu maszyny z serwera WWW, który obsługuje stronę zawierającą SVG. Ponadto, gdy otrzymujemy dane, nasze programy muszą teraz znać strukturę DOM danej strony.

Na szczęście frameworki takie jak Vue stały się popularne i mogą zaoszczędzić nam dużo pracy.

Łatwo się dowiedzieć o Vue. Dokumentacja Vue jest bardzo przystępna. Tak więc, jeśli ta dyskusja wyskoczy zbyt daleko, możesz spędzić trochę czasu na nauce o Vue na jego własnej stronie internetowej. Ale na stronach Smashing są bardzo dobre dyskusje. Krutie Patel napisał wspaniały artykuł na temat tworzenia infografiki. Souvik Sarkar mówi nam, jak zbudować pulpit pogodowy za pomocą Vue.

Wybór grupy powiązanych paneli

W pierwszym kroku powinniśmy zająć się wyszukiwaniem grup paneli. Jednym z powodów, dla których robimy to najpierw, jest to, że odbywa się to na poziomie ramowym naszych ludzkich interakcji.

Użytkownik szuka czegoś, co go interesuje. Być może interesują go wszystkie urządzenia w lokalizacjach w jednym mieście. Być może ma wiele partii produktów płynnych i chce zawęzić się do jednego rodzaju produktu, z każdą partią zarządzaną przez niewielką kolekcję urządzeń IoT. Tak więc użytkownik najpierw wyszuka małą listę.

Oto proces:

  1. Wyszukaj grupy paneli według cech/parametrów.
  2. Wyświetl listę ikon reprezentujących grupy.
  3. Wybierz ikonę (kliknij/dotknij).
  4. Zacznij używać paneli oznaczonych ikoną, gdy się pojawią.

Innym powodem, dla którego jest to dobry pierwszy krok, jest to, że możemy używać Vue w najprostszej formie. Nie są potrzebne żadne narzędzia do budowania. Po prostu vue.js z tagiem skryptu w HTML. W rzeczywistości nie musimy go nawet pobierać. Istnieje witryna, na której udostępniana jest robocza kopia vue.js

Wszystko czego potrzebujemy to następujący tag:

 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

Skopiowałem tag script bezpośrednio z dokumentacji Vue dotyczącej instalacji.

Teraz potrzebujemy strony internetowej, która może ładować ikony i przekształcać je w coś, co klika. Vue bardzo to ułatwia. Właściwie to właśnie napisałem małą aplikację do zarządzania listą Twittera za pomocą Vue. Po prostu zarządza polami tekstowymi. Ponieważ jest to trochę prostsze niż SPWA przy użyciu ikon, możemy rzucić na niego okiem, a następnie zmienić go, aby był pożądanym frameworkiem aplikacji jednostronicowej.

Oto część tego, jak wygląda strona:

Strona tekstowa, która będzie punktem wyjścia do tworzenia aplikacji graficznej.
Strona tekstowa, która będzie punktem wyjścia do tworzenia aplikacji graficznej. (duży podgląd)

Wygląda to na dość prostą stronę. Każdy zewnętrzny wpis numeryczny to przedział czasowy z jednym lub dwoma tweetami. Drugi tweet jest opcjonalny. Jeśli edytujesz tweeta, mechanizmy Vue aktualizują obiekt JavaScript. Ta strona pozostawia użytkownikowi kliknięcie przycisku „aktualizuj wpisy”, aby poinformować serwer, że coś się zmieniło, za pomocą funkcji obsługi przycisku.

Aby funkcja obsługi przycisku przekazywała dane do serwera, musi zmienić obiekt danych Vue na ciąg JSON. Teraz możesz się zastanawiać, jak trudne będzie tłumaczenie obiektu Vue na JSON. Okazuje się, że to jedna linijka kodu. Możesz znaleźć wiersz w poniższym kodzie źródłowym, ale jeśli chcesz go znaleźć szybciej, jest on podświetlony w akapicie po kodzie źródłowym.

Strona wygląda na prostą. Wygląd może mylić. Oczywiście strona wygląda na prostą, ale czy kod jest prosty? Tak, rzeczywiście tak jest! Korzystając z Vue, strona zarządza zawartością pól niemal magicznie. Oto kod:

 <!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>

Tak więc, aby podkreślić niesamowite linie, które mówią o sile frameworka, powtórzmy tutaj:

A. To jest wyciąganie danych.

 postOptionsObject.body = JSON.stringify(twtApp.tweets);

B. To jest umieszczenie danych w Vue i wyświetlenie aktualizacji ekranu:

 twtApp.tweets = JSON.parse(text) // text is the server response

Ile to kosztuje?

Wygląda na to, że będzie dobry sposób na wyrażenie, w jaki sposób dane będą aktualizować panele dla IoT.

Teraz zamieńmy tweety w klikalne ikony przeznaczone do pobierania komponentów z serwera WWW.

Od tweetów do ikon pobierania paneli

Ludzie lubią używać SVG do ikon. Lubią to używać do SVG bardziej niż do innych rzeczy, o ile wiem. Idę tylko do wielu stron internetowych, które sprzedają lub rozdają ikony wykonane w SVG. Cechą charakterystyczną jest to, że grafika liniowa ma mniej bajtów niż obrazy. A gdybym miał prosić o listy zdjęć z zachowaniem podobnym do przycisków, mogłem złapać pliki PNG lub JPEG w czasach, gdy SVG było w iframe. 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.

Vue will quote the HTML an insert it as text.
Vue will quote the HTML an insert it as text. (duży podgląd)

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> 
Using the right directive, Vue inserts DOM, resulting in the rendering of desired graphics.
Using the right directive, Vue inserts DOM, resulting in the rendering of desired graphics. (duży podgląd)

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:

Icons that might be returned from a search for MCU groups.
An artistic idea suggesting how search could return icons indicating certain groups of MCU's to interact with. (duży podgląd)

The data being sent is an array with the following kind of structure:

{ "style" : { "color" : "red", "backgroundColor" : "yellow" }, "icon" : svg1, "name" : "thermos" },

Tutaj svg1 to SVG pobrany z pliku. Oczywiście prawy serwer wziąłby strukturę z bazy danych, w której byłby przechowywany plik SVG.

Oto fragment powyższego kodu. To jest kod, który pobiera JSON i umieszcza tablicę struktur w aplikacji Vue. Możesz zobaczyć strukturę fetch w użyciu. Tekst jest analizowany, aw następnym wierszu zakodowany plik SVG jest dekodowany. Jeszcze jedna linijka i Vue aktualizuje stronę. Liczba przycisków na pasku przycisków będzie równa długości tablicy 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) }); // the page update right away with new data. iconApp.iconList = newData; }); });

Teraz jeszcze tylko dwa fragmenty. Aplikacja Vue. Czytelnik zauważy, że do przycisków została dołączona dyrektywa @click . Element danych, iconEntry.name , jest przekazywany do metody w cudzysłowie.

Metoda jest zdefiniowana w aplikacji Vue:

 <div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> </div>

Oto fragment definicji metod. Obiekt methods jest dodawany tuż za obiektem data w obiekcie parametru aplikacji:

 , methods: { goGetPanel: (pname) => { // `this` inside methods points to the Vue instance alert('Hello ' + pname + '!') } }

Czytelnik powinien znaleźć definicję goGetPanel , a użycie jej zostało wskazane dla obsługi @click . W naszej finalnej aplikacji wywołanie alert można zastąpić funkcją pobierającą panele z serwera.

Biblioteka komponentów dla paneli IoT

Moglibyśmy po prostu zdecydować, że panele, które pobieramy z serwera, mogą być HMTL lub po prostu rysunkami SVG, ale jeśli będzie wiele rodzajów paneli, mamy nadzieję, że zadanie tworzenia paneli można uprościć dzięki posiadaniu bibliotek komponentów do wybrać z. Możemy sobie wyobrazić, że edytory SVG można by ulepszyć, aby umożliwić upuszczanie komponentów biblioteki na obrazy w ramach edycji. Następnie, jeśli edytor SVG mógłby wyprowadzić wersję obrazu z tagami komponentów, użycie Vue pozwoliłoby na stworzenie obrazu przy jednoczesnym zapewnieniu, że automatyzacja i animacja JavaScript są ze sobą zgrabnie splecione. W naszej dyskusji może nam pomóc trochę ręcznej edycji.

Jeśli chcemy tworzyć panele z komponentów Vue, lepiej wymyślmy, jak je wykonać, a następnie zebrać je w coś użytecznego. Będziemy musieli przejść do korzystania z narzędzi wiersza poleceń dostarczonych przez Vue i uporządkować nasz przepływ pracy.

składniki

Dokumentacja Vue wskazuje, że sekcja data komponentu (podobiekt) definicji komponentu musi być funkcją, która zwraca dane. Powodem tego jest to, że Vue musi przechowywać dane oddzielnie między instancjami. Tak więc, przechodząc od inicjalizacji aplikacji Vue do definicji komponentu, następuje kolejna mała zmiana w kodzie.

W tym pierwszym fragmencie kodu inicjowana jest aplikacja Vue:

 var iconApp = new Vue({ el: '#iconApp', data: { // this is the data field that can be easily updated }, methods : { ... } });

W tym nowym fragmencie kodu jest definiowany i rejestrowany komponent. Po pierwsze, zauważ, że zamiast tworzyć new Vue , rejestrowany jest komponent o nazwie iconic . Następnie pole data zwraca niestandardowe dane dla dowolnej iconic instancji stworzonej przez aplikację Vue. Wreszcie pole template jest obecne na końcu rejestracji składnika. Dowolny kod HTML, który mógł zostać napisany na stronie internetowej w celu wyświetlenia komponentu, może być częścią template .

 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>' });

Możemy więc wyobrazić sobie panel z termometrami. Tak więc, jeśli ktoś dostarczyłby komponent thermometer , oczekiwalibyśmy definicji komponentu gdzieś w naszym kodzie. Takie jak:

 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>' });

Staramy się stworzyć coś, co wygląda tak:

Animowana aplikacja termometru w Vue przed eksploracją komponentów.
Animowana aplikacja termometru w Vue przed eksploracją komponentów. (duży podgląd)

Komponent termometru jest bardzo podobny do pierwszych komponentów, które napotkasz w samouczkach Vue. Ale trochę trudno jest dowiedzieć się, jak to zaktualizować. Istnieje lepszy sposób definiowania komponentu pod kątem reaktywności za pomocą właściwości. A to jest w następujący sposób:

 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' })

Więc zamiast przedstawiać temperaturę jako element danych. Jest reprezentowana jako własność pod props . Następnie pojawia się nowa sekcja, obliczona , która dostarcza zmienne będące funkcjami właściwości. Widzimy, że this.temperature jest używane zarówno dla y , jak i dla height . Te obliczone zmienne są używane w SVG jako atrybuty prostokąta.

W SVG y rośnie od góry do dołu. Tak więc, gdy chcemy, aby prostokąt na dole termometru był mały, y czerwonego pola musi być mniejsze, a wysokość musi być zmniejszona, aby ( y + height ) pozostało na zero termometru.

Zwróć uwagę na pole template w definicji komponentów. W rzeczywistości jest to identyfikator elementu dokumentu. Element, do którego się odwołujemy, to sekcja skryptu o specjalnym typie: type="text/x-template" . Element script to miejsce, w którym znajduje się plik SVG dla termometrów. Ponadto SVG wykorzystuje zmienne Vue i terminy kontrolne, aby można było zdefiniować reaktywność.

Oto niektóre z 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"

Czytelnik może znaleźć id="thermometer-template" na górze, a patrząc dalej w dół do elementów rect , można znaleźć obliczone zmienne.

Tutaj zastosowania zmiennych są oddzielone. Używana jest skrócona składnia Vue dla v-bind , z :height="height" i taka sama dla y :

 x="111.90748" :height="height" :y="y"

Kiedy rodzic elementów SVG ustawia zmienne, które działają jako dane wejściowe dla temperature właściwości termometru, Vue ponownie oblicza height i y . W rezultacie zmienia się pozycja i wysokość czerwonego pola.

Pomocne jest posiadanie listy aplikacji Vue, która korzysta z termometru.

 <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>

To wszystko. Istnieją trzy przyciski, które wywołują metodę updateTemp aplikacji thermoApp Vue. Sekcja danych ma dwie zmienne temperatury. I każdy thermometer aktualizuje swoją temperaturę, gdy wartości się zmieniają.

Kod dla dwóch wymienionych poniżej termometrów można znaleźć w kodzie HTML przypisanym do aplikacji Vue.

 <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer>

Zauważ, że aplikacja używa formalizmu function dla definicji metody. Zdefiniowanie updateTemp ten sposób updateTemp: function (tval1,tval2) umożliwia dostęp do zmiennej instancji this .

Również zdefiniowanie updateTemp ten sposób updateTemp: (tval1,tval2) => przypisuje this do wewnętrznej struktury danych, która nie reaguje i nie aktualizuje widoku.

Montaż panelu

Każdy panel IoT może być komponentem. Vue zapewnia sposób definiowania komponentów za pomocą podkomponentów. Alternatywnie istnieje mechanizm slotów, który może być użyty do uzyskania komponentu, który może zawijać się wokół dowolnej treści HTML.

W kilku kolejnych akapitach przyjrzyjmy się tworzeniu panelu z podkomponentów. Z naszych przykładów szybko wynikają dwie formy. W jednym przypadku termometry mogą być podkomponentami wywoływanymi w JavaScript. W innym przypadku komponenty są definiowane niezależnie, ale są wymienione w kodzie HTML.

W obu przypadkach w szablonie można użyć tego samego kodu HTML. Oto nasz panel jako szablon:

 <script type="text/x-template"> <div> <thermometer :temperature="temp1" ></thermometer> <thermometer :temperature="temp2" ></thermometer> </div> </script>

Jedyną różnicą między pierwszymi szczegółami aplikacji jest to, że element div otacza dwa termometry. Vue zgłosi błąd, jeśli w szablonie brakuje elementu DOM najwyższego poziomu. div spełnia wymagania Vue, a wiele elementów może być w nim zawartych.

Teraz możemy zobaczyć dwa termometry obok siebie. Przekazywanie temperatur od góry do końcowego termometru ma wartości kaskadowe w dół. Na najwyższym poziomie panel dołącza się do aplikacji, gdy w DOM aplikacji znajduje się pojedyncza linia.

 <themo-panel :temp1="temp1" :temp2="temp2" ></themo-panel>

Szablon panelu, choć prosty, wydaje się wskazywać, że panele można łatwo projektować pod względem komponentów. To tak, jakby możliwy był język tylko dla komponentów IoT.

Teraz definicja szablonu panelu jest dość prosta. Oto z podkomponentami zdefiniowanymi niezależnie:

 Vue.component('thermo-panel', { props: ['temp1','temp2'], template: '#thermo-panel-template' });

To mniej więcej tyle, ile potrzeba, aby panel działał. Prawdą jest, że ta wersja opiera się na długiej liście właściwości do definiowania wartości, które mają być aktualizowane w miarę pojawiania się wiadomości na stronie. Ale to dobry początek. Aktualizacja obiektu data na najwyższym poziomie ma na celu animację termometrów. Jednak ponieważ panele stają się skomplikowane, może zaistnieć potrzeba wprowadzenia innej metody wykazania zmian.

Wspominając o innych sposobach określania podkomponentów, dla panelu powinniśmy się temu przyjrzeć. Oto on:

 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) } } } } });

Z pewnością jest więcej kodu, ale to dlatego, że JavaScript dla komponentu thermometer znajduje się na liście komponentów thermo-panel . Te dwa podejścia wykonują tę samą pracę, ale oferują różne sposoby definiowania komponentów pakowania.

W tej chwili preferuję pierwszą drogę. Powinno być znacznie łatwiej przeglądać panele i pobierać je dynamicznie, jeśli wymagana jest tylko zmiana szablonu i właściwości. W tym celu niezależnie zdefiniowane komponenty tworzą bibliotekę komponentów. Ale chociaż wydaje się to lepsze, w dalszej części wygodniej jest użyć drugiego, pozornie bardziej szczegółowego sposobu.

Biorąc pod uwagę, że możemy tworzyć responsywne panele z komponentów w jasno określony sposób, w dalszej części mojego artykułu wyjaśnię, jak możemy nimi zarządzać jako bazą danych, która może wykonywać proste zapytania.