Componentes de página da Web SVG para IoT e criadores (parte 1)

Publicados: 2022-03-10
Resumo rápido ↬ A IoT está crescendo para incluir muitos dispositivos com muitos proprietários. Os desenvolvedores da Web enfrentarão o problema de encontrar maneiras de permitir que os proprietários interajam com seus dispositivos. Mas, este problema dá origem a uma grande quantidade de negócios. Vamos explorar alguns aspectos do desenvolvimento de páginas da Web para a Internet das Coisas (IoT) que já estão em demanda.

O mercado de IoT ainda está em seus estágios iniciais, mas ganhando força. Estamos em um ápice na história da IoT. Os mercados estão quadruplicando ao longo de cinco anos, de 2015 a 2020. Para desenvolvedores da Web, esse crescimento de IoT é significativo. Já existe uma grande demanda por técnicas da web de IoT.

Muitos dispositivos serão espalhados geoespacialmente e seus proprietários desejarão controle e gerenciamento remotos. As pilhas de web completas devem ser feitas para criar canais para teleoperação. Além disso, a interação será com um ou mais dispositivos IoT por vez. A interação deve ser em tempo real do mundo físico.

Esta discussão aprofunda os requisitos de interface usando o Vue.js como um catalisador e ilustra um método de comunicação entre a página da Web e o dispositivo em várias substituições.

Aqui estão alguns dos objetivos planejados para esta discussão:

  1. Criar um aplicativo web de página única SPWA que hospede grupos de interfaces homem-máquina de IoT (podemos chamar esses “grupos de painéis”);
  2. Exibir listas de identificadores de grupo de painéis como resultado de uma consulta a um servidor;
  3. Exibir os painéis de um grupo selecionado como resultado de uma consulta;
  4. Certifique-se de que a tela do painel seja carregada lentamente e fique animada rapidamente;
  5. Certifique-se de que os painéis sejam sincronizados com os dispositivos IoT.
Mais depois do salto! Continue lendo abaixo ↓

IoT e o rápido crescimento das páginas da Web

A apresentação de gráficos para visualização e controle remoto de hardware, juntamente com a sincronização de páginas da Web com processos físicos em tempo real, estão dentro do domínio da resolução de problemas de páginas da Web inerentes a este futuro da IoT.

Muitos de nós estão começando nossa busca por técnicas de apresentação de IoT, mas existem alguns padrões da Web, além de algumas técnicas de apresentação, que podemos começar a usar agora. À medida que exploramos esses padrões e técnicas juntos, podemos nos juntar a essa onda de IoT.

Painéis e visualização de dados estão em demanda. Além disso, a demanda por ir além das páginas da web que fornecem formulários ou listas de exibição ou conteúdo textual é alta. Os painéis para IoT precisam ser pictográficos, animados. As animações devem ser sincronizadas com processos físicos em tempo real para fornecer uma visão verídica do estado da máquina aos usuários. O estado da máquina, como uma chama acesa ou não, supera o estado da aplicação e fornece informações críticas aos operadores, talvez até informações de segurança.

Os dashboards exigem mais do que a visualização de dados. Temos que ter em mente que as coisas que fazem parte da IoT são dispositivos que não apenas possuem sensores, mas também controlam interfaces. Nas implementações de hardware, os MCUs são estendidos com switches, switches de limite, configurações de parâmetros e muito mais. Ainda assim, as páginas da Web podem substituir esses componentes de controle de hardware .

Nada de novo. As interfaces de computador para hardware existem há muito tempo, mas o rápido crescimento do uso de páginas da Web para essas interfaces faz parte de nossa experiência atual. WebRTC e Speech API estão em um caminho de desenvolvimento que começou em 2012. O WebSockets vem se desenvolvendo em um período de tempo semelhante.

A IoT está em nossas mentes há muito tempo. A IoT faz parte do diálogo humano desde 1832. Mas, a IoT e a rede sem fio, como estamos conhecendo, foram imaginadas por Tesla por volta de 1926. A Forbes 2018 State of Iot nos diz o foco atual do mercado para a IoT. De interesse para desenvolvedores da web, o artigo destaca os painéis:

“Os primeiros adeptos ou defensores da IoT priorizam painéis, relatórios, casos de uso de IoT que fornecem fluxos de dados integrados a análises, visualização avançada e mineração de dados.”

O mercado de IoT é enorme. Este artigo Market Size fornece uma previsão para o número de dispositivos que aparecerão: 2018: 23,14 bilhões ⇒ 2025: 75,44 bilhões. E tenta colocar um valor financeiro: 2014: \$2,99 trilhões ⇒ 2020: $8,90 trilhões. A demanda por habilidades de IoT será a que mais crescerá: IoT in Demand.

À medida que desenvolvemos interfaces claras para dispositivos de controle e monitoramento, encontramos um novo problema para desenvolver nossas interfaces. Todos os muitos bilhões de dispositivos serão de propriedade de muitas pessoas (ou organizações). Além disso, cada pessoa pode possuir qualquer número de dispositivos. Talvez até alguns dos dispositivos sejam compartilhados.

As interfaces modernas que foram feitas para controles de máquina geralmente têm um layout bem definido específico para uma determinada máquina ou instalação de algumas máquinas. Por exemplo, em uma casa inteligente, um sistema de ponta terá um LCD com painéis para dispositivos cuidadosamente posicionados. Mas, à medida que crescemos com a versão web da IoT, haverá qualquer número de painéis para um fluxo de dispositivos dinâmico e até móvel.

O gerenciamento de painéis para dispositivos torna-se semelhante ao gerenciamento de conexões sociais em sites sociais.

“Nossas interfaces de usuário terão que ser dinâmicas no gerenciamento de qual painel em tempo real altamente animado deve ser exibido a qualquer momento para cada usuário em particular.”

O painel é um aplicativo da web SPWA de página única. E, podemos imaginar um banco de dados de painéis. Portanto, se um único usuário for acessar vários painéis e configurações para seus dispositivos espalhados pelo planeta, o SPWA precisa acessar os componentes do painel sob demanda. Os painéis e alguns de seus JavaScripts de suporte terão que carregar lentamente.

“Nossas interfaces terão que trabalhar com estruturas de páginas da Web que possam permitir a incorporação de associações de componentes assíncronas sem reinicializar suas estruturas.”

Vamos usar Vue.js, WebSockets, MQTT e SVG para entrar no mercado de IoT.

Leitura recomendada : Construindo um infográfico interativo com Vue.js

Arquitetura de alto nível para um aplicativo Web IoT

Ao projetar a interface para a página da Web IoT, sempre há muitas opções. Uma opção pode ser dedicar uma única página a um único dispositivo. A página pode até ser renderizada no lado do servidor. O servidor teria a tarefa de consultar o dispositivo para obter seus valores de sensor e, em seguida, colocar os valores nos locais apropriados na string HTML.

Muitos de nós estão familiarizados com ferramentas que permitem que modelos HTML sejam escritos com marcadores especiais que indicam onde colocar os valores das variáveis. Ver {{temperature}} em tal modelo nos diz e ao mecanismo de visualização para obter a temperatura consultada de um dispositivo e substituir o símbolo {{temperature}} por ele. Assim, depois de esperar o servidor consultar o dispositivo, o dispositivo responder, renderizar a página e entregar a página, o usuário finalmente poderá ver a temperatura informada pelo dispositivo.

Para esta página por arquitetura de dispositivo, o usuário pode então desejar enviar um comando para o dispositivo. Não tem problema, ele pode preencher um formulário HTML e enviar. O servidor pode até ter uma rota apenas para o dispositivo, ou talvez um pouco mais inteligente, uma rota para o tipo de dispositivo e o ID do dispositivo. O servidor então traduziria os dados do formulário em uma mensagem para enviar ao dispositivo, escreveria para algum manipulador de dispositivo e aguardaria uma confirmação. Então, o servidor pode finalmente responder à solicitação de postagem e informar ao usuário que está tudo bem com o dispositivo.

Uma arquitetura de página da Web para tratar a IoT como um servidor de formulário - procurando algo melhor.
Uma arquitetura de página da Web para tratar a IoT como um servidor de formulário - procurando algo melhor. (Visualização grande)

Muitos CMSs funcionam dessa maneira para atualizar entradas de blog e similares. Nada parece estranho nisso. Parece que HTML sobre HTTP sempre teve o design para obter páginas que foram renderizadas e para enviar dados de formulário para serem manipulados pelo servidor web. Além disso, existem milhares de CMSs para escolher. Portanto, para colocar nosso sistema IoT em funcionamento, parece razoável percorrer esses milhares de CMSs para ver qual é o certo para o trabalho. Ou podemos aplicar um filtro nos CMSs para começar.

Temos que levar em consideração a natureza em tempo real do que estamos lidando. Portanto, embora o HTML em sua forma original seja bastante bom para muitas tarefas corporativas, ele precisa de uma pequena ajuda para se tornar o mecanismo de entrega para o gerenciamento de IoT. Portanto, precisamos de um CMS ou servidor web personalizado que ajude o HTML a fazer esse trabalho de IoT. Também podemos pensar no servidor, pois assumimos que o CMS fornece a funcionalidade do servidor. Só precisamos ter em mente que o servidor precisa fornecer animação orientada a eventos, para que a página não possa ser 100% finalizada em impressão estática.

Aqui estão alguns parâmetros que podem orientar as escolhas para nossa página da Web vinculada ao dispositivo, coisas que ela deve fazer:

  1. Receba dados do sensor e outras mensagens de status do dispositivo de forma assíncrona ;
  2. Renderize os dados do sensor para a página no cliente (quase corolário de 1);
  3. Publique comandos para um determinado dispositivo ou grupo de dispositivos de forma assíncrona ;
  4. Opcionalmente, envie comandos por meio do servidor ou ignore-o.
  5. Manter com segurança a relação de propriedade entre o dispositivo e o usuário;
  6. Gerencie a operação crítica do dispositivo, não interferindo ou substituindo.

A lista vem à mente quando se pensa em apenas uma página atuando como interface para um dispositivo selecionado . Queremos poder comunicar livremente com o dispositivo quando se trata de comandos e dados.

Quanto à página, precisamos solicitá-la ao servidor web uma vez. Esperaríamos que o servidor web (ou aplicativo associado) fornecesse um caminho de comunicação seguro. E o caminho não precisa ser através do servidor, ou talvez deva evitar o servidor completamente, pois o servidor pode ter tarefas de maior prioridade além de cuidar da comunicação de uma página para dados provenientes de sensores.

Na verdade, podemos imaginar dados vindos de um sensor uma vez por segundo, e não esperaríamos que o próprio servidor da web fornecesse uma atualização constante segundo a segundo para milhares de fluxos de sensores individuais multiplicados por milhares de espectadores. É claro que um servidor web pode ser particionado ou configurado em uma estrutura de balanceamento de carga, mas existem outros serviços que são personalizados para entrega de sensores e comandos de empacotamento para hardware.

O servidor web precisará entregar algum pacote para que a página estabeleça canais de comunicação seguros com o dispositivo. Temos que ter cuidado ao enviar mensagens em canais que não fornecem algum gerenciamento dos tipos de mensagens que passam. Deve haver algum conhecimento sobre se um dispositivo está em um modo que pode ser interrompido ou pode haver uma demanda por ação do usuário se um dispositivo estiver fora de controle. Assim, o servidor web pode ajudar o cliente a obter os recursos apropriados que podem saber mais sobre o dispositivo. As mensagens podem ser feitas com algo como um servidor MQTT. E, pode haver alguns serviços para preparar o servidor MQTT que podem ser iniciados quando o usuário obtém acesso ao seu painel através do servidor web.

Devido ao mundo físico com seus requisitos em tempo real e devido a considerações adicionais de segurança, nosso diagrama se torna um pouco diferente do original.

Um aplicativo de página única que fala com um MCU.
Um aplicativo de página única que fala com um MCU. Ele agora interage de forma assíncrona com o MCU independentemente do servidor de página da web. (Visualização grande)

Não podemos parar aqui. Configurar uma única página por dispositivo, mesmo que seja responsivo e lide bem com a comunicação, não é o que pedimos. Temos que assumir que um usuário fará login em sua conta e acessará seu painel. A partir daí, ele pedirá uma lista de projetos de conteúdo (projetos mais prováveis ​​em que está trabalhando). Cada item da lista se referirá a um número de recursos. Quando ele seleciona um item clicando ou tocando, ele terá acesso a uma coleção de painéis, cada um dos quais terá algumas informações sobre um determinado recurso ou dispositivo IoT.

Qualquer número de painéis entregues em resposta à consulta gerada como resultado da ação da interface do usuário pode ser aqueles painéis que interagem com dispositivos ativos. Assim, assim que um painel aparecer, espera-se que ele mostre atividade em tempo real e seja capaz de enviar um comando para um dispositivo.

Como os painéis são vistos na página é uma decisão de design. Eles podem ser janelas flutuantes ou podem ser caixas em um plano de fundo rolável. Seja como for, os painéis estarão marcando tempo, temperatura, pressão, velocidade do vento ou qualquer outra coisa que você possa imaginar. Esperamos que os painéis sejam animados em várias escalas gráficas. A temperatura pode ser apresentada como um termômetro, a velocidade como um medidor de velocidade semicircular, o som como uma forma de onda de fluxo e assim por diante.

O servidor web tem a função de entregar os painéis certos para o usuário certo, dadas consultas a um banco de dados de painéis e desde que os dispositivos tenham que estar fisicamente disponíveis. Além disso, como haverá muitos tipos diferentes de dispositivos, os painéis para cada dispositivo provavelmente serão diferentes. Assim, o servidor web deve ser capaz de entregar as informações pictográficas necessárias para renderizar um painel. No entanto, a página HTML do painel não deve ser carregada com todos os painéis possíveis. Não há previsão de quantos serão.

Aqui estão alguns parâmetros que podem orientar as escolhas para nossa página de painel, coisas que ela deve fazer:

  1. Apresentar uma forma de selecionar grupos de painéis de dispositivos relacionados;
  2. Fazer uso de mecanismos de comunicação simultânea de dispositivos para alguns dispositivos;
  3. Ativar painéis de dispositivos quando o usuário os solicitar;
  4. Incorpore gráficos carregados lentamente para designs de painel exclusivos;
  5. Fazer uso de tokens e parâmetros de segurança em relação a cada painel;
  6. Mantenha a sincronicidade com todos os dispositivos sob inspeção do usuário.
Um aplicativo de página única que se comunica com vários MCUs, de forma assíncrona e independente do servidor de página da web.
Um aplicativo de página única que se comunica com vários MCUs, de forma assíncrona e independente do servidor de página da web. (Visualização grande)

Podemos começar a ver como o jogo muda, mas no mundo do design de painéis, o jogo vem mudando um pouco aqui e ali há algum tempo. Nós apenas temos que nos restringir a algumas ferramentas de desenvolvimento de páginas úteis e atualizadas para nos colocarmos em ação.

Vamos começar com como podemos renderizar os painéis. Isso já parece um grande trabalho. Estamos imaginando muitos tipos diferentes de painéis. Mas, se você já usou um DAW de música, você veria como eles usaram gráficos para fazer os painéis parecerem com os dispositivos analógicos usados ​​por bandas de muito tempo atrás. Todos os painéis nas DAW's são desenhados pelos plugins que operam no som. Na verdade, muitos desses plugins de DAW podem usar SVG para renderizar suas interfaces. Assim, nos limitamos a lidar com interfaces SVG, que por sua vez podem ser qualquer gráfico que possamos imaginar.

Escolhendo SVG para Painéis

Claro, eu gosto de DAWs e usaria isso como exemplo, mas SVG é um padrão de página da web. SVG é um padrão W3C. É para transportar desenhos de linha para as páginas da web. O SVG costumava ser um cidadão de segunda classe na página da web, obrigado a viver em iFrames. Mas, desde HTML5, tem sido um cidadão de primeira classe. Talvez, quando o SVG2 for lançado, ele poderá usar elementos de formulário. Por enquanto, elementos de formulário são Objetos Estrangeiros em SVG. Mas isso não deve nos impedir de fazer do SVG o substrato para painéis.

SVG pode ser desenhado, armazenado para exibição e pode ser carregado lentamente. Na verdade, à medida que exploramos o sistema de componentes, veremos que o SVG pode ser usado para modelos de componentes. Nesta discussão, usaremos o Vue.js para criar componentes para os painéis.

Desenhar SVG não é difícil, porque existem muitos programas de desenho de linha que são fáceis de obter. Se você gastar o dinheiro, poderá obter o Adobe Illustrator, que exporta SVG. O Inkscape tem sido uma opção para a criação de SVG há algum tempo. É de código aberto e funciona bem em Linux, mas também pode ser executado em Mac e Windows. Depois, existem vários programas de edição de SVG de páginas da Web que são de código aberto e algumas versões de SaaS também.

Eu tenho procurado um editor SVG baseado na web de código aberto. Depois de algumas pesquisas, encontrei o SVG-Edit. Você pode incluí-lo em suas próprias páginas da web, talvez se estiver criando um blog baseado em SVG ou algo assim.

Diagrama elétrico em SVG pronto para animação.
Um diagrama elétrico é bastante detalhado, mas podemos obtê-lo facilmente em SVG e animá-lo com apenas um pequeno código. (Visualização grande)

Quando você salva seu trabalho em um arquivo, o SVG-Edit o baixa em seu navegador e você pode pegar o arquivo no diretório de download.

A imagem que desenhei mostra uma porta AND controlando um integrador. Isso não é o que normalmente se esperaria ver em um painel para um MCU. O painel pode ter um botão para alimentar uma das entradas da porta AND, talvez. Então ele pode ter um display de um ADC que lê a saída do integrador. Talvez seja um gráfico de linhas em um eixo de tempo. A maioria dos painéis terá gráficos que permitem ao usuário se relacionar com o que está acontecendo dentro do MCU. E, se nosso circuito for viver em qualquer lugar, será dentro do MCU.

Mesmo assim, nosso diagrama eletrônico pode ser usado para discutir animação. O que queremos fazer é dar uma olhada no SVG e ver onde podemos obter algumas das tags DOM que gostaríamos de alterar de alguma forma. Podemos então animar o SVG usando um pouco de JavaScript vanilla e um cronômetro. Vamos fazer a porta AND piscar em cores diferentes.

O SVG que estamos procurando está na caixa de código a seguir. Não parece muito amigável para o programador, embora o usuário fique bastante feliz. No entanto, ainda existem algumas pistas para descobrir em qual elemento DOM desejamos operar. Primeiro, a maioria das ferramentas de desenho SVG tem uma maneira de acessar as propriedades do objeto, em particular, o atributo id . SVG-Edit também tem um jeito. No editor, selecione a porta AND e observe a barra de ferramentas. Você verá um campo para o id e a class CSS também.

Uma das ferramentas de desenho SVG com uma maneira de capturar o id do objeto usando a interface fornecida.
Uma das ferramentas de desenho SVG com uma maneira de capturar o id do objeto usando a interface fornecida. (Visualização grande)

Se você não conseguir acessar uma ferramenta de edição por algum motivo, poderá abrir o SVG em um navegador e inspecionar o DOM. De qualquer forma, descobrimos que nosso portão tinha 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>

Tudo o que precisamos agora é um pouco de JavaScript. Observamos primeiro que o atributo de elemento “fill” está presente. Depois, há apenas o programa simples que se segue:

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

Observe que o que temos é uma página HTML mínima. Você pode recortar e colar o código em seu editor favorito. E não esqueça de recortar e colar o SVG para substituir o comentário. Minha versão do Chrome requer que a página seja HTML para ter a seção JavaScript. Então, esse é um navegador que ainda trata o SVG como algo separado. Mas, está muito longe dos dias de <iframe> .

Se você recortar e colar corretamente, poderá abrir a página e ver o portão AND passar de vermelho para verde repetidamente.

Leitura recomendada : SVG Circle Decomposition To Paths

Construindo Painéis de Componentes VUE

Já estamos a caminho de dar vida a qualquer painel, mas se quisermos gerenciar grandes coleções de painéis de maneira sensata, teremos nosso trabalho cortado para nós. Esse seria especialmente o caso se simplesmente construíssemos nosso primeiro exemplo.

Embora o primeiro exemplo nos mostre como podemos alterar uma visualização de objeto de forma assíncrona, ele não nos mostra como vincular a visualização ao estado de qualquer objeto de dados e muito menos um que gerencia uma máquina. Certamente podemos entender como a demonstração setInterval pode ser substituída por um manipulador de fetch , mas podemos nem mesmo obter o estado de uma máquina do servidor web que atende à página que contém o SVG. Além disso, quando obtemos os dados, nossos programas agora precisam conhecer a estrutura DOM da página fornecida.

Felizmente, frameworks como o Vue se tornaram populares e podem nos poupar muito trabalho.

É fácil descobrir sobre o Vue. A documentação do Vue é muito acessível. Portanto, se esta discussão for muito avançada, você pode gastar algum tempo aprendendo sobre o Vue em seu próprio site. Mas há discussões muito boas nas páginas do Smashing. Krutie Patel escreveu um artigo impressionante sobre como fazer um infográfico. Souvik Sarkar nos diz como construir um painel meteorológico com Vue.

Seleção de Grupo de Painéis Relacionados

Para a primeira etapa, devemos abordar a busca por grupos de painéis. Uma razão para fazer isso primeiro é que está no nível da estrutura de nossas interações humanas.

O usuário procura algo que o interessa. Talvez ele esteja interessado em todos os dispositivos em locais de uma cidade. Talvez ele tenha muitos lotes de produtos líquidos e queira restringir a um tipo de produto com cada lote governado por uma pequena coleção de dispositivos IoT. Assim, o usuário primeiro pesquisará para obter uma pequena lista.

Aqui está o processo:

  1. Pesquise grupos de painéis por recursos/parâmetros.
  2. Veja uma lista de ícones que representam grupos.
  3. Selecione um ícone (clique/toque).
  4. Comece a usar os painéis identificados com o ícone quando eles aparecerem.

Outra razão pela qual este é um bom primeiro passo é que podemos usar o Vue em sua forma mais simples. Não são necessárias ferramentas de construção. Vamos apenas incluir vue.js com uma tag de script em HTML. Na verdade, nem precisamos baixá-lo. Há um site onde uma cópia de trabalho do vue.js está sendo veiculada.

Tudo o que precisamos é a seguinte tag:

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

Copiei a tag script diretamente da documentação do Vue sobre instalação.

Agora, precisamos de uma página da web que possa carregar ícones e transformá-los em algo que clique. Vue torna isso muito fácil. Na verdade, acabei de escrever um pequeno aplicativo para gerenciar uma lista do Twitter usando Vue. Ele apenas gerencia campos de texto. Como é um pouco mais simples do que um SPWA usando ícones, podemos dar uma olhada nele e alterá-lo para ser nossa estrutura de aplicativo de página única desejada.

Aqui está parte da aparência da página:

Uma página baseada em texto para usar como ponto de partida para criar um aplicativo gráfico.
Uma página baseada em texto para usar como ponto de partida para criar um aplicativo gráfico. (Visualização grande)

Esta parece uma página bastante simples. Cada entrada numérica externa é um intervalo de tempo com um ou dois tweets. O segundo tweet é opcional. Se você editar um tweet, os mecanismos Vue atualizam um objeto JavaScript. Esta página deixa para o usuário clicar no botão “atualizar entradas” para informar ao servidor que algo mudou, por meio de sua função de manipulador de botão.

Para que o manipulador de botão retransmita dados para o servidor, ele deve alterar o objeto de dados Vue em uma string JSON. Agora, você pode se perguntar o quão difícil será traduzir um objeto Vue para JSON. Acontece que é uma linha de código. Você pode encontrar a linha no código-fonte a seguir, mas se quiser encontrá-la mais rapidamente, ela será destacada no parágrafo após o código-fonte.

A página parece simples. As aparências podem enganar. Claro, a página parece simples, mas o código é simples? Sim, de fato é! Usando o Vue, a página gerencia o conteúdo dos campos quase que magicamente. Aqui está o código:

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

Então, apenas para destacar as linhas incríveis que falam sobre o poder do framework, vamos repetir aqui:

A. Isso está retirando os dados.

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

B. Isso é colocar os dados no Vue e ver a atualização da tela:

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

Quanto trabalho é isso?

Parece que haverá uma boa maneira de expressar como os dados atualizarão os painéis para IoT.

Agora, vamos transformar os tweets em ícones clicáveis ​​projetados para buscar componentes do servidor web.

De Tweets a ícones de busca de painel

As pessoas gostam de usar SVG para ícones. Eles gostam mais desse uso para SVG do que para outras coisas, pelo que posso dizer. Estou indo apenas para o número de sites que vendem ou doam ícones feitos em SVG. O ponto de venda é que os gráficos de linha têm menos bytes do que as imagens. E, se eu fosse pedir listas de imagens com comportamento semelhante a um botão, eu poderia ter pego PNGs ou JPEGs nos dias em que o SVG estava em iframes. 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. (Visualização grande)

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. (Visualização grande)

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. (Visualização grande)

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

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

Aqui, svg1 é SVG obtido de um arquivo. É claro que um servidor íntegro teria tirado a estrutura de um banco de dados, onde o SVG seria armazenado na estrutura.

Aqui está um trecho do código acima. Este é o código que busca o JSON e coloca o array de estruturas no aplicativo Vue. Você pode ver a estrutura de promessa de fetch em uso. O texto é analisado e, na próxima linha, o SVG codificado é decodificado. Mais uma linha, e o Vue atualiza a página. O número de botões na barra de botões será igual ao comprimento da matriz 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; }); });

Agora, apenas mais dois trechos. O aplicativo Vue. O leitor notará que a diretiva @click foi incluída nos botões. O elemento de dados, iconEntry.name , é passado para um método entre aspas.

O método é definido dentro do aplicativo Vue:

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

Aqui está o trecho para a definição de métodos. O objeto de methods é adicionado logo após o objeto de data dentro do objeto de parâmetro do aplicativo:

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

O leitor deve encontrar a definição goGetPanel , e o uso dela foi apontado para o manipulador @click . Em nossa aplicação final, a chamada de alert pode ser substituída por uma função que busca painéis do servidor.

Uma biblioteca de componentes para painéis IoT

Poderíamos apenas decidir que os painéis que buscamos do servidor podem ser HMTL ou apenas desenhos SVG, mas se houver muitos tipos de painéis, esperamos que o trabalho de criação de painéis possa ser simplificado com bibliotecas de componentes para escolher. Podemos imaginar que os editores SVG poderiam ser melhorados para permitir que os componentes da biblioteca fossem colocados nas imagens como parte da edição. Então, se o editor SVG pudesse produzir uma versão da imagem com tags de componentes, o uso do Vue permitiria que a imagem fosse criada, garantindo que a automação e a animação do JavaScript fossem perfeitamente entrelaçadas. Para nossa discussão, alguma edição manual pode nos ajudar a chegar lá.

Se quisermos criar painéis a partir de componentes Vue, é melhor descobrirmos como fazer os componentes e depois reuni-los em algo útil. Teremos que passar a usar as ferramentas de linha de comando fornecidas pelo Vue e organizar nosso fluxo de trabalho.

Componentes

A documentação do Vue aponta que a seção de data do componente (subobjeto) da definição do componente precisa ser uma função que retorne dados. A razão para isso é que o Vue precisa manter os dados separados entre as instâncias. Assim, ao passar de uma inicialização de aplicativo Vue para uma definição de componente, há outra pequena alteração no código.

Neste primeiro trecho de código uma aplicação Vue está sendo inicializada:

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

Neste novo trecho de código, um componente está sendo definido e registrado. Primeiro, observe que ao invés de criar uma new Vue , um componente chamado iconic está sendo registrado. Em seguida, o campo de data retorna dados personalizados para qualquer instância iconic que o aplicativo Vue cria. Por fim, o campo template está presente ao final do cadastro do componente. Qualquer HTML que possa ter sido escrito na página da Web para exibir o componente pode fazer parte do 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>' });

Assim, podemos imaginar um painel com termômetros. Portanto, se alguém fornecesse um componente de thermometer , esperaríamos uma definição de componente em algum lugar em nosso código. Como tal:

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

Estamos tentando criar algo parecido com isso:

Aplicativo de termômetro animado em Vue antes de explorar componentes.
Aplicativo de termômetro animado em Vue antes de explorar componentes. (Visualização grande)

O componente do termômetro é muito semelhante aos primeiros componentes que você encontrará nos tutoriais do Vue. Mas, é um pouco complicado descobrir como atualizá-lo. Existe uma maneira melhor de definir o componente para reatividade usando propriedades. E, isso está no seguinte:

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

Então, em vez de representar a temperatura como um elemento de dados. Ele é representado como uma propriedade em props . Em seguida, há uma nova seção, computed , que fornece variáveis ​​que são funções da propriedade. Vemos this.temperature sendo usado para y e height . Essas variáveis ​​computadas estão sendo usadas no SVG como atributos para um retângulo.

Em SVG, y cresce de cima para baixo. Então, quando queremos que o retângulo seja pequeno na parte inferior do termômetro, o y da caixa vermelha deve ser menor e a altura deve ser reduzida para que ( y + height ) permaneça no zero do termômetro.

Observe o campo template na definição dos componentes. Na verdade, é um ID de elemento de documento. O elemento referido é uma seção de script com o tipo especial: type="text/x-template" . O elemento script é onde está o SVG para os termômetros. E, o SVG faz uso de variáveis ​​Vue e termos de controle para que a reatividade possa ser definida.

Aqui estão alguns dos SVGs:

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

O leitor pode encontrar id="thermometer-template" no topo, e olhando mais para baixo para os elementos rect , as variáveis ​​calculadas podem ser encontradas.

Aqui os usos das variáveis ​​são separados. A sintaxe abreviada do Vue para v-bind está em uso, com :height="height" e o mesmo para y :

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

Quando o pai dos elementos SVG define as variáveis ​​que atuam como entrada para a temperatura da propriedade do temperature , o Vue recalcula a height e y . Como resultado, a posição e a altura da caixa vermelha mudam.

Ajuda ter uma lista do aplicativo Vue que faz uso do termômetro.

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

Essa é a coisa toda. Existem três botões que chamam o método updateTemp do aplicativo thermoApp Vue. A seção de dados tem duas variáveis ​​de temperatura. E, cada thermometer atualiza sua temperatura quando os valores mudam.

O código para os dois termômetros citados abaixo pode ser encontrado no HTML atribuído ao aplicativo Vue.

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

Observe que o aplicativo usa o formalismo da function para a definição do método. Definindo updateTemp desta forma updateTemp: function (tval1,tval2) permite que a variável de instância this seja acessada.

Além disso, definir updateTemp desta forma updateTemp: (tval1,tval2) => atribui this a uma estrutura de dados interna que não reage e atualiza a exibição.

Montagem de um painel

Cada painel IoT pode ser um componente. Vue fornece uma maneira de definir componentes com subcomponentes. Alternativamente, existe um mecanismo de slot que pode ser usado para produzir um componente que pode envolver qualquer conteúdo HTML.

Nos próximos parágrafos, vamos ver como fazer um painel de subcomponentes. Existem duas formas que seguem rapidamente de nossos exemplos. Em um caso, os termômetros podem ser subcomponentes chamados em JavaScript. Em outro caso, os componentes são definidos independentemente, mas são mencionados no HTML.

Em ambos os casos, o mesmo HTML pode ser usado para o modelo. Aqui está o nosso painel como modelo:

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

A única diferença entre o primeiro detalhamento do aplicativo é que um elemento div está envolvendo os dois termômetros. O Vue lançará um erro se o template estiver faltando um elemento DOM de nível superior. A div passa pelo requisito do Vue, e os vários elementos podem ser incluídos dentro dela.

Agora, podemos ver os dois termômetros lado a lado. Passar as temperaturas do topo para o termômetro final tem valores em cascata. No nível superior, o painel une o aplicativo quando uma única linha é incluída no DOM do aplicativo.

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

O modelo do painel, embora simples, parece indicar que os painéis podem ser facilmente desenhados em termos de componentes. É como se uma linguagem apenas para componentes de IoT fosse possível.

Agora, a definição do modelo para o painel é bastante simples. Aqui está com os subcomponentes definidos independentemente:

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

Isso é o que é necessário para tornar o painel funcional. É verdade que esta versão conta com uma longa lista de propriedades para definir valores a serem atualizados à medida que as mensagens chegam à página. Mas, este é um bom começo. A atualização do objeto de data no nível superior faz o trabalho de animar os termômetros. No entanto, à medida que os painéis se tornam complicados, pode ser necessário haver outro método para mostrar a mudança.

Tendo feito menção às outras formas de especificar subcomponentes, para o painel, devemos dar uma olhada nele. Aqui está:

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

Certamente há mais código, mas isso ocorre porque o JavaScript para o componente de thermometer está incluído na lista de componentes de thermo-panel . As duas abordagens fazem o mesmo trabalho, mas oferecem maneiras diferentes de empacotar definições de componentes.

No momento, minha preferência é pela primeira maneira. Deve ser consideravelmente mais fácil revisar painéis e recuperá-los dinamicamente se for necessário apenas alterar o modelo e as propriedades. Para este fim, os componentes definidos independentemente formam uma biblioteca de componentes. Mas, embora isso pareça melhor, a seguir torna-se mais conveniente usar a segunda maneira, aparentemente mais detalhada.

Dado que podemos criar painéis responsivos a partir de componentes de maneiras claramente definidas, explicarei como podemos gerenciá-los como um banco de dados que pode fazer consultas simples na próxima parte do meu artigo.