Componentes de página web SVG para IoT y fabricantes (Parte 1)

Publicado: 2022-03-10
Resumen rápido ↬ IoT está creciendo para incluir muchos dispositivos con muchos propietarios. Los desarrolladores web se enfrentarán al problema de encontrar formas de permitir que los propietarios interactúen con sus dispositivos. Pero, este problema da lugar a una gran cantidad de negocios. Exploremos algunos aspectos del desarrollo de páginas web para Internet de las cosas (IoT) que ya están en demanda.

El mercado de IoT aún se encuentra en sus primeras etapas, pero cobra fuerza. Estamos en una cúspide en la historia de IoT. Los mercados se están cuadruplicando en el transcurso de cinco años, de 2015 a 2020. Para los desarrolladores web, este crecimiento de IoT es significativo. Ya existe una gran demanda de técnicas web IoT.

Muchos dispositivos se distribuirán geoespacialmente y sus propietarios desearán el control y la gestión a distancia. Se deben realizar pilas web completas para crear canales para la teleoperación. Además, la interacción será con uno o más dispositivos IoT a la vez. La interacción debe ser en el tiempo real del mundo físico.

Esta discusión profundiza en los requisitos de la interfaz usando Vue.js como catalizador e ilustra un método de comunicación entre la página web y el dispositivo entre muchas sustituciones.

Estos son algunos de los objetivos previstos para esta discusión:

  1. Cree una aplicación web SPWA de una sola página que aloje grupos de interfaces hombre-máquina de IoT (podemos llamarlos "grupos de paneles");
  2. Mostrar listas de identificadores de grupos de paneles como resultado de consultar un servidor;
  3. Mostrar los paneles de un grupo seleccionado como resultado de una consulta;
  4. Asegúrese de que la pantalla del panel se cargue lentamente y se anime rápidamente;
  5. Asegúrese de que los paneles se sincronicen con los dispositivos IoT.
¡Más después del salto! Continúe leyendo a continuación ↓

IoT y el rápido crecimiento de las páginas web

La presentación de gráficos para visualización y control remoto de hardware junto con la sincronización de páginas web con procesos físicos en tiempo real están dentro del ámbito de la resolución de problemas de páginas web inherentes a este futuro de IoT.

Muchos de nosotros estamos comenzando nuestra búsqueda de técnicas de presentación de IoT, pero existen algunos estándares web junto con algunas técnicas de presentación que podemos comenzar a usar ahora. A medida que exploramos estos estándares y técnicas juntos, podemos unirnos a esta ola de IoT.

Los tableros y la visualización de datos están en demanda. Además, la demanda de ir más allá de las páginas web que brindan formularios o muestran listas o contenido textual es alta. Los tableros para IoT deben ser pictográficos, animados. Las animaciones deben sincronizarse con procesos físicos en tiempo real para proporcionar una vista verídica del estado de la máquina a los usuarios. El estado de la máquina, como una llama encendida o no, prevalece sobre el estado de la aplicación y proporciona información crítica a los operadores, tal vez incluso información de seguridad.

Los tableros requieren más que la visualización de datos. Tenemos que tener en cuenta que las cosas que forman parte de IoT son dispositivos que no solo tienen sensores sino también interfaces de control. En las implementaciones de hardware, las MCU se amplían con interruptores, interruptores de umbral, configuración de parámetros y más. Aun así, las páginas web pueden ocupar el lugar de esos componentes de control de hardware .

Nada nuevo. Las interfaces informáticas para hardware existen desde hace mucho tiempo, pero el rápido crecimiento del uso de páginas web para estas interfaces es parte de nuestra experiencia actual. WebRTC y Speech API se encuentran en una ruta de desarrollo que comenzó en 2012. WebSockets se ha estado desarrollando en un marco de tiempo similar.

IoT ha estado en nuestras mentes durante mucho tiempo. IoT ha sido parte del diálogo humano desde 1832. Pero, IoT e inalámbrico, tal como lo estamos conociendo, fue imaginado por Tesla alrededor de 1926. Forbes 2018 State of Iot nos dice el enfoque actual del mercado para IoT. De interés para los desarrolladores web, el artículo menciona los tableros:

“Los primeros usuarios o defensores de IoT priorizan los tableros, los informes y los casos de uso de IoT que brindan flujos de datos integrales para el análisis, la visualización avanzada y la extracción de datos”.

El mercado de IoT es enorme. Este artículo de Market Size brinda una predicción de la cantidad de dispositivos que aparecerán: 2018: 23,14 mil millones ⇒ 2025: 75,44 mil millones. E intenta ponerle una cifra financiera: 2014: \$2,99 billones ⇒ 2020: $8,90 billones. La demanda de habilidades de IoT será la de más rápido crecimiento: IoT en demanda.

A medida que desarrollamos interfaces claras para controlar y monitorear dispositivos, nos encontramos con un nuevo problema para desarrollar nuestras interfaces. Todos los miles de millones de dispositivos serán propiedad de muchas personas (u organizaciones). Además, cada persona puede poseer cualquier número de dispositivos. Quizás incluso algunos de los dispositivos serán compartidos.

Las interfaces modernas que se han creado para los controles de máquinas a menudo tienen un diseño bien definido específico para una máquina en particular o una instalación de algunas máquinas. Por ejemplo, en una casa inteligente, un sistema de gama alta tendrá una pantalla LCD con paneles para dispositivos cuidadosamente colocados. Pero, a medida que crecemos con la versión web de IoT, habrá una gran cantidad de paneles para un flujo dinámico e incluso móvil de dispositivos.

La gestión de paneles para dispositivos se vuelve similar a la gestión de conexiones sociales en sitios web sociales.

“Nuestras interfaces de usuario tendrán que ser dinámicas en la gestión de qué panel en tiempo real altamente animado debe mostrarse en cualquier momento para cada usuario en particular”.

El tablero es una aplicación web SPWA de una sola página. Y, podemos imaginar una base de datos de paneles. Por lo tanto, si un solo usuario va a acceder a varios paneles y configuraciones para sus dispositivos esparcidos por el planeta, la SPWA necesita acceder a los componentes del panel a pedido. Los paneles y algunos de sus JavaScript de soporte tendrán que cargarse lentamente.

“Nuestras interfaces tendrán que funcionar con marcos de páginas web que puedan permitir la incorporación de enlaces de componentes asíncronos sin reiniciar sus marcos”.

Usemos Vue.js, WebSockets, MQTT y SVG para dar nuestro paso hacia el mercado de IoT.

Lectura recomendada : Creación de una infografía interactiva con Vue.js

Arquitectura de alto nivel para una aplicación web de IoT

Al diseñar la interfaz para la página web de IoT, uno siempre tiene muchas opciones. Una opción podría ser dedicar una sola página a un solo dispositivo. La página podría incluso mostrarse en el lado del servidor. El servidor tendría el trabajo de consultar el dispositivo para obtener los valores de sus sensores y luego colocar los valores en los lugares apropiados en la cadena HTML.

Muchos de nosotros estamos familiarizados con herramientas que permiten escribir plantillas HTML con marcadores especiales que indican dónde colocar los valores de las variables. Ver {{temperature}} en dicha plantilla nos dice a nosotros y al motor de visualización que tomemos la temperatura consultada de un dispositivo y reemplacemos el símbolo {{temperature}} con ella. Entonces, después de esperar a que el servidor consulte el dispositivo, el dispositivo responda, renderice la página y entregue la página, el usuario finalmente podrá ver la temperatura informada por el dispositivo.

Para esta arquitectura de página por dispositivo, el usuario puede desear enviar un comando al dispositivo. No hay problema, puede completar un formulario HTML y enviarlo. El servidor podría incluso tener una ruta solo para el dispositivo, o quizás de manera un poco más inteligente, una ruta para el tipo de dispositivo y la identificación del dispositivo. Luego, el servidor traduciría los datos del formulario en un mensaje para enviar al dispositivo, lo escribiría en algún controlador de dispositivo y esperaría un reconocimiento. Luego, el servidor finalmente puede responder a la solicitud de publicación y decirle al usuario que todo está bien con el dispositivo.

Una arquitectura de página web para tratar el IoT como un servidor de formularios: buscando algo mejor.
Una arquitectura de página web para tratar el IoT como un servidor de formularios: buscando algo mejor. (Vista previa grande)

Muchos CMS funcionan de esta manera para actualizar entradas de blog y similares. Nada parece extraño al respecto. Parece que HTML sobre HTTP siempre ha tenido el diseño para obtener páginas que se han renderizado y para enviar datos de formulario para que sean manejados por el servidor web. Además, hay miles de CMS para elegir. Entonces, para poner en marcha nuestro sistema IoT, parece razonable examinar esos miles de CMS para ver cuál es el adecuado para el trabajo. O bien, podríamos aplicar un filtro en los CMS para empezar.

Tenemos que tener en cuenta la naturaleza en tiempo real de lo que estamos tratando. Entonces, si bien HTML en su forma original es bastante bueno para muchas tareas empresariales, necesita un poco de ayuda para convertirse en el mecanismo de entrega para la administración de IoT. Por lo tanto, necesitamos un CMS o un servidor web personalizado que ayude a HTML a realizar este trabajo de IoT. También podemos pensar en el servidor cuando asumimos que proporciona la funcionalidad del servidor de CMS. Solo debemos tener en cuenta que el servidor debe proporcionar animación basada en eventos, por lo que la página no puede ser una impresión estática finalizada al 100%.

Aquí hay algunos parámetros que pueden guiar las opciones para nuestra página web vinculada al dispositivo, cosas que debería hacer:

  1. Reciba datos del sensor y otros mensajes de estado del dispositivo de forma asíncrona ;
  2. Renderizar los datos del sensor para la página en el cliente (casi corolario de 1);
  3. Publicar comandos en un dispositivo en particular o en un grupo de dispositivos de forma asíncrona ;
  4. Opcionalmente, envíe comandos a través del servidor u omítalo.
  5. Mantener de forma segura la relación de propiedad entre el dispositivo y el usuario;
  6. Administre el funcionamiento crítico del dispositivo al no interferir o anularlo.

La lista viene a la mente cuando se piensa en una sola página que actúa como interfaz para un dispositivo seleccionado . Queremos poder comunicarnos con el dispositivo libremente cuando se trata de comandos y datos.

En cuanto a la página, solo necesitamos pedirla una vez al servidor web. Esperaríamos que el servidor web (o la aplicación asociada) proporcionara una vía de comunicación segura. Y, la ruta no tiene que ser a través del servidor, o tal vez debería evitar el servidor por completo, ya que el servidor puede tener tareas de mayor prioridad además de cuidar la comunicación de una página para los datos provenientes de los sensores.

De hecho, podemos imaginar que los datos provienen de un sensor una vez por segundo, y no esperaríamos que el servidor web en sí mismo proporcione una actualización constante segundo a segundo para miles de flujos de sensores individuales multiplicados por miles de espectadores. Por supuesto, un servidor web puede particionarse o configurarse en un marco de equilibrio de carga, pero existen otros servicios que se personalizan para la entrega de sensores y la clasificación de comandos al hardware.

El servidor web deberá entregar algún paquete para que la página pueda establecer canales de comunicación seguros con el dispositivo. Tenemos que tener cuidado con el envío de mensajes en canales que no brindan alguna gestión de los tipos de mensajes que se transmiten. Tiene que haber algún conocimiento sobre si un dispositivo está en un modo que puede ser interrumpido o si puede haber una demanda de acción del usuario si un dispositivo está fuera de control. Entonces, el servidor web puede ayudar al cliente a obtener los recursos apropiados que pueden saber más sobre el dispositivo. La mensajería se puede hacer con algo como un servidor MQTT. Y podría haber algunos servicios para preparar el servidor MQTT que se pueden iniciar cuando el usuario accede a su panel a través del servidor web.

Debido al mundo físico con sus requisitos en tiempo real y debido a consideraciones de seguridad adicionales, nuestro diagrama se vuelve un poco diferente del original.

Una aplicación de una sola página que habla con una MCU.
Una aplicación de una sola página que habla con una MCU. Ahora interactúa de forma asíncrona con la MCU independientemente del servidor de la página web. (Vista previa grande)

No podemos detenernos aquí. Configurar una sola página por dispositivo, incluso si responde y maneja bien la comunicación, no es lo que pedimos. Tenemos que asumir que un usuario iniciará sesión en su cuenta y accederá a su tablero. A partir de ahí, pedirá una lista de proyectos de contenido (probablemente proyectos en los que esté trabajando). Cada elemento de la lista se referirá a una serie de recursos. Cuando selecciona un elemento haciendo clic o tocando, obtendrá acceso a una colección de paneles, cada uno de los cuales tendrá información sobre un recurso o dispositivo IoT en particular.

Cualquier número de los paneles entregados en respuesta a la consulta generada como resultado de la acción de la interfaz del usuario pueden ser aquellos paneles que interactúan con dispositivos vivos. Entonces, tan pronto como aparezca un panel, se espera que muestre actividad en tiempo real y pueda enviar un comando a un dispositivo.

Cómo se ven los paneles en la página es una decisión de diseño. Pueden ser ventanas flotantes o cuadros sobre un fondo desplazable. Independientemente de cómo se presente, los paneles marcarán el tiempo, la temperatura, la presión, la velocidad del viento o cualquier otra cosa que pueda imaginar. Esperamos que los paneles estén animados con respecto a varias escalas gráficas. La temperatura se puede presentar como un termómetro, la velocidad como un indicador de velocidad semicircular, el sonido como una forma de onda continua, etc.

El servidor web tiene el trabajo de entregar los paneles correctos al usuario correcto, dadas las consultas a una base de datos de paneles y dado que los dispositivos deben estar físicamente disponibles. Además, dado que habrá muchos tipos diferentes de dispositivos, es probable que los paneles para cada dispositivo sean diferentes. Por lo tanto, el servidor web debería poder entregar la información pictográfica necesaria para renderizar un panel. Sin embargo, la página HTML para el tablero no debería tener que cargarse con todos los paneles posibles. No hay idea de cuántos serán.

Aquí hay algunos parámetros que pueden guiar las opciones para nuestra página de tablero, cosas que debería hacer:

  1. Presentar una forma de seleccionar grupos de paneles de dispositivos relacionados;
  2. Hacer uso de mecanismos de comunicación de dispositivos simultáneos para una cierta cantidad de dispositivos;
  3. Activar paneles de dispositivos cuando el usuario los solicite;
  4. Incorpore gráficos cargados de forma diferida para diseños de paneles únicos;
  5. Hacer uso de tokens de seguridad y parámetros con respecto a cada panel;
  6. Mantenga la sincronía con todos los dispositivos bajo la inspección del usuario.
Una aplicación de una sola página que se comunica con múltiples MCU, de forma asincrónica e independiente del servidor de la página web.
Una aplicación de una sola página que se comunica con múltiples MCU, de forma asincrónica e independiente del servidor de la página web. (Vista previa grande)

Podemos comenzar a ver cómo cambia el juego, pero en el mundo del diseño de tableros, el juego ha estado cambiando un poco aquí y allá durante algún tiempo. Solo tenemos que limitarnos a algunas herramientas de desarrollo de páginas actualizadas y útiles para ponernos en marcha.

Comencemos con cómo podemos renderizar los paneles. Esto ya parece un gran trabajo. Estamos imaginando muchos tipos diferentes de paneles. Pero, si alguna vez usó un DAW de música, verá cómo han usado gráficos para hacer que los paneles se vean como los dispositivos analógicos que usaban las bandas de antaño. Todos los paneles en los DAW están dibujados por complementos que operan con sonido. De hecho, muchos de esos complementos de DAW pueden usar SVG para representar sus interfaces. Entonces, nos limitamos a manejar interfaces SVG, que a su vez pueden ser cualquier gráfico que podamos imaginar.

Elegir SVG para paneles

Por supuesto, me gustan los DAW y los usaría como ejemplo, pero SVG es un estándar de página web. SVG es un estándar W3C. Es para llevar dibujos lineales a las páginas web. SVG solía ser un ciudadano de segunda clase en la página web, requerido para vivir en iFrames. Pero, desde HTML5, ha sido un ciudadano de primera clase. Tal vez, cuando salga SVG2, podrá usar elementos de formulario. Por ahora, los elementos de formulario son objetos extraños en SVG. Pero eso no debería impedirnos hacer de SVG el sustrato para los paneles.

SVG se puede dibujar, almacenar para mostrar y se puede cargar de forma lenta. De hecho, a medida que exploramos el sistema de componentes, veremos que SVG se puede usar para plantillas de componentes. En esta discusión, usaremos Vue.js para crear componentes para los paneles.

Dibujar SVG no es difícil, porque hay muchos programas de dibujo lineal que son fáciles de conseguir. Si gasta el dinero, puede obtener Adobe Illustrator, que exporta SVG. Inkscape ha sido un goto para la creación de SVG durante algún tiempo. Es de código abierto y funciona bien en Linux, pero también se puede ejecutar en Mac y Windows. Luego, hay varios programas de edición SVG de páginas web que son de código abierto, y también algunas versiones SaaS.

He estado buscando un editor SVG basado en la web de código abierto. Después de mirar un poco, encontré SVG-Edit. Puede incluirlo en sus propias páginas web, tal vez si está creando un blog basado en SVG o algo así.

Diagrama eléctrico en SVG listo para animación.
Un diagrama eléctrico es bastante detallado, pero podemos obtenerlo fácilmente en SVG y animarlo con solo un poco de código. (Vista previa grande)

Cuando guarda su trabajo en un archivo, SVG-Edit lo descarga en su navegador y puede recoger el archivo de su directorio de descargas.

La imagen que dibujé muestra una puerta AND que controla un integrador. Eso no es lo que normalmente se esperaría ver en un panel para una MCU. El panel podría tener un botón para alimentar una de las entradas de la puerta AND, tal vez. Entonces podría tener una pantalla de un ADC que lea la salida del integrador. Quizás sea un gráfico de líneas en un eje de tiempo. La mayoría de los paneles tendrán gráficos que permitan al usuario relacionarse con lo que sucede dentro de la MCU. Y, si nuestro circuito va a vivir en algún lugar, estará dentro de la MCU.

De todos modos, nuestro diagrama electrónico se puede usar para discutir la animación. Lo que queremos hacer es echar un vistazo al SVG y ver dónde podemos obtener algunas de las etiquetas DOM que nos gustaría cambiar de alguna manera. Luego podemos animar el SVG usando un poco de JavaScript y un temporizador. Hagamos que la puerta AND parpadee en diferentes colores.

El SVG que estamos buscando está en el siguiente cuadro de código. No parece muy amigable para el programador, aunque el usuario estará bastante contento. Sin embargo, todavía hay algunas pistas para encontrar en qué elemento DOM deseamos operar. Primero, la mayoría de las herramientas de dibujo SVG tienen una forma de llegar a las propiedades del objeto, en particular, el atributo id . SVG-Edit también tiene una forma. En el editor, seleccione la puerta AND y observe la barra de herramientas. Verá un campo para la id y la class CSS también.

Una de las herramientas de dibujo SVG con una forma de capturar la identificación del objeto usando la interfaz provista.
Una de las herramientas de dibujo SVG con una forma de capturar la identificación del objeto usando la interfaz provista. (Vista previa grande)

Si no puede acceder a una herramienta de edición por algún motivo, puede abrir el SVG en un navegador e inspeccionar el DOM. En cualquier caso, hemos encontrado que nuestra puerta tení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>

Todo lo que necesitamos ahora es un poco de JavaScript. Primero tomamos nota de que el atributo de elemento "relleno" está presente. Luego está el programa simple que sigue:

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

Tenga en cuenta que lo que tenemos es una página HTML mínima. Puedes cortar y pegar el código en tu editor favorito. Y luego no olvides cortar y pegar el SVG para reemplazar el comentario. Mi versión de Chrome requiere que la página sea HTML para tener la sección de JavaScript. Entonces, ese es un navegador que todavía trata a SVG como algo separado. Pero, está muy lejos de los días de <iframe> .

Si corta y pega correctamente, puede abrir la página y ver la puerta AND pasar de rojo a verde una y otra vez.

Lectura recomendada : Descomposición de círculos SVG a caminos

Construcción de paneles a partir de componentes VUE

Ya estamos en camino de hacer que cualquier panel individual cobre vida, pero si queremos administrar grandes colecciones de paneles de manera sensata, tendríamos mucho trabajo por delante. Ese sería especialmente el caso si simplemente nos basamos en nuestro primer ejemplo.

Si bien el primer ejemplo nos muestra cómo podemos cambiar de forma asíncrona la vista de un objeto, no nos muestra cómo vincular la vista al estado de cualquier objeto de datos y mucho menos uno que administra una máquina. Ciertamente podemos entender cómo la demostración de setInterval puede ser reemplazada por un controlador de fetch , pero es posible que ni siquiera obtengamos el estado de una máquina del servidor web que sirve la página que contiene SVG. Además, cuando obtenemos los datos, ahora se requiere que nuestros programas conozcan la estructura DOM de la página dada.

Afortunadamente, los marcos como Vue se han vuelto populares y pueden ahorrarnos mucho trabajo.

Es fácil averiguar acerca de Vue. La documentación de Vue es muy accesible. Por lo tanto, si esta discusión avanza demasiado, entonces puede pasar algún tiempo aprendiendo sobre Vue en su propio sitio web. Pero, hay muy buenas discusiones dentro de las páginas de Smashing. Krutie Patel escribió un artículo impresionante sobre cómo hacer una infografía. Souvik Sarkar nos dice cómo construir un panel meteorológico con Vue.

Selección de grupo de paneles relacionados

Para el primer paso, debemos abordar la búsqueda de grupos de paneles. Una de las razones para hacer esto primero es que se encuentra en el marco de referencia de nuestras interacciones humanas.

El usuario busca algo que le interese. Tal vez le interesen todos los dispositivos en las ubicaciones de una ciudad. Tal vez tenga muchos lotes de productos líquidos y quiera limitarse a un tipo de producto con cada lote regido por una pequeña colección de dispositivos IoT. Entonces, el usuario primero buscará para obtener una pequeña lista.

Aquí está el proceso:

  1. Busque grupos de paneles por características/parámetros.
  2. Ver una lista de iconos que representan grupos.
  3. Seleccione un icono (haga clic/toque).
  4. Empiece a utilizar los paneles identificados con el icono cuando aparezcan.

Otra razón por la que este es un buen primer paso es que podemos usar Vue en su forma más simple. No se necesitan herramientas de construcción. Simplemente incluiremos vue.js con una etiqueta de secuencia de comandos en HTML. De hecho, ni siquiera tenemos que descargarlo. Hay un sitio donde se sirve una copia de trabajo de vue.js

Todo lo que necesitamos es la siguiente etiqueta:

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

Copié la etiqueta del script directamente de la documentación de Vue sobre la instalación.

Ahora, necesitamos una página web que pueda cargar íconos y convertirlos en algo que haga clic. Vue lo hace muy fácil. De hecho, acabo de escribir una pequeña aplicación para administrar una lista de Twitter usando Vue. Solo administra campos de texto. Como es un poco más simple que un SPWA que usa íconos, podemos echarle un vistazo y luego cambiarlo para que sea nuestro marco de aplicación de página única deseado.

Aquí hay parte de cómo se ve la página:

Una página basada en texto que se utiliza como punto de partida para crear una aplicación de gráficos.
Una página basada en texto que se utiliza como punto de partida para crear una aplicación de gráficos. (Vista previa grande)

Esto parece una página bastante simple. Cada entrada numérica exterior es un intervalo de tiempo con uno o dos tweets. El segundo tweet es opcional. Si edita un tweet, los mecanismos de Vue actualizan un objeto JavaScript. Esta página deja que el usuario haga clic en el botón "actualizar entradas" para decirle al servidor que algo ha cambiado, a través de su función de controlador de botón.

Para que el controlador de botones transmita datos al servidor, debe cambiar el objeto de datos de Vue a una cadena JSON. Ahora, puede preguntarse cuán difícil será traducir un objeto Vue a JSON. Resulta ser una línea de código. Puede encontrar la línea en el siguiente código fuente, pero si desea encontrarla más rápido, está resaltada en el párrafo después del código fuente.

La página parece simple. Las apariencias engañan. Por supuesto, la página parece simple, pero ¿es simple el código? ¡Sí, de hecho lo es! Usando Vue, la página administra el contenido de los campos casi mágicamente. Aquí está el 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>

Entonces, solo para resaltar las líneas asombrosas que hablan del poder del marco, repitamos aquí:

A. Esto es sacar los datos.

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

B. Esto es poner los datos en Vue y ver la actualización de la pantalla:

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

¿Cuánto trabajo es eso?

Parece que habrá una buena manera de expresar cómo los datos actualizarán los paneles para IoT.

Ahora, convirtamos los tweets en íconos en los que se puede hacer clic diseñados para obtener componentes del servidor web.

De tweets a iconos de obtención de paneles

A la gente le gusta usar SVG para íconos. Les gusta ese uso para SVG más que para otras cosas, por lo que puedo decir. Solo voy a la cantidad de sitios web que venden o regalan íconos hechos en SVG. El punto de venta es que los gráficos de líneas tienen menos bytes que las imágenes. Y, si fuera a pedir listas de imágenes con un comportamiento similar al de un botón, podría haber buscado PNG o JPEG en los días en que SVG estaba en 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. (Vista previa 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. (Vista previa 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. (Vista previa grande)

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

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

Aquí, svg1 es SVG tomado de un archivo. Por supuesto, un servidor correcto habría tomado la estructura de una base de datos, donde el SVG se almacenaría en la estructura.

Aquí hay un fragmento del código anterior. Este es el código que obtiene el JSON y coloca la matriz de estructuras en la aplicación Vue. Puede ver la estructura de promesa de fetch en uso. El texto se analiza y, en la siguiente línea, se decodifica el SVG codificado. Una línea más y Vue actualiza la página. La cantidad de botones en la barra de botones será igual a la longitud de la 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; }); });

Ahora, solo dos fragmentos más. La aplicación Vue. El lector notará que la directiva @click se ha incluido en los botones. El elemento de datos, iconEntry.name , se pasa a un método entre comillas.

El método se define dentro de la aplicación Vue:

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

Aquí está el fragmento para la definición de métodos. El objeto de methods se agrega justo después del objeto de data dentro del objeto de parámetro de la aplicación:

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

El lector debe encontrar la definición de goGetPanel , y se señaló su uso para el controlador @click . En nuestra aplicación final, la llamada de alert se puede reemplazar por una función que obtiene paneles del servidor.

Una biblioteca de componentes para paneles IoT

Podríamos decidir que los paneles que obtenemos del servidor pueden ser dibujos HMTL o SVG, pero si va a haber muchos tipos de paneles, esperamos que el trabajo de creación de paneles se simplifique al tener bibliotecas de componentes para escoge de. Podemos imaginar que los editores SVG podrían mejorarse para permitir que los componentes de la biblioteca se coloquen en las imágenes como parte de la edición. Luego, si el editor SVG pudiera generar una versión de la imagen con etiquetas de componentes, entonces el uso de Vue permitiría crear la imagen al tiempo que garantiza que la automatización y la animación de JavaScript se entrelacen perfectamente. Para nuestra discusión, un poco de edición manual puede ayudarnos a llegar allí.

Si queremos crear paneles a partir de componentes de Vue, será mejor que descubramos cómo hacer los componentes y luego los reunamos en algo útil. Tendremos que cambiar al uso de herramientas de línea de comandos proporcionadas por Vue y organizar nuestro flujo de trabajo.

Componentes

La documentación de Vue señala que la sección data del componente (subobjeto) de la definición del componente debe ser una función que devuelva datos. La razón de esto es que Vue necesita mantener los datos separados entre las instancias. Entonces, al pasar de la inicialización de una aplicación Vue a una definición de componente, hay otro pequeño cambio de código.

En este primer fragmento de código, se inicializa una aplicación Vue:

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

En este nuevo fragmento de código, se define y registra un componente. Primero, observe que en lugar de crear una new Vue , se está registrando un componente llamado iconic . Luego, el campo data devuelve datos personalizados para cualquier instancia iconic que crea la aplicación Vue. Finalmente, el campo de template está presente al final del registro del componente. Cualquier código HTML que se haya escrito en la página web para mostrar el componente puede formar parte de la 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>' });

Entonces, podemos imaginar un panel con termómetros. Entonces, si alguien proporcionara un componente de thermometer , esperaríamos una definición de componente en algún lugar de nuestro 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 tratando de crear algo que se vea así:

Aplicación de termómetro animado en Vue antes de explorar componentes.
Aplicación de termómetro animado en Vue antes de explorar componentes. (Vista previa grande)

El componente del termómetro es muy similar a los primeros componentes que encontrará en los tutoriales de Vue. Pero, es un poco complicado averiguar cómo actualizarlo. Hay una mejor manera de definir el componente para la reactividad usando propiedades. Y eso es lo siguiente:

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

Entonces, en lugar de representar la temperatura como un elemento de datos. Se representa como una propiedad bajo props . Luego, hay una nueva sección, computada , que proporciona variables que son funciones de la propiedad. Vemos que this.temperature se usa tanto para y como para height . Estas variables calculadas se utilizan en el SVG como atributos para un rectángulo.

En SVG, y crece de arriba hacia abajo. Entonces, cuando queremos que el rectángulo sea pequeño en la parte inferior del termómetro, la y del cuadro rojo debe ser más baja y la altura debe reducirse para que ( y + height ) permanezca en el cero del termómetro.

Observe el campo de template en la definición de los componentes. De hecho, es un ID de elemento de documento. El elemento al que se hace referencia es una sección de script con el tipo especial: type="text/x-template" . El elemento de script es donde está el SVG para los termómetros. Y, el SVG hace uso de variables Vue y términos de control para que se pueda definir la reactividad.

Aquí hay algunos de los 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"

El lector puede encontrar id="thermometer-template" en la parte superior, y mirando más abajo a los elementos rect , se pueden encontrar las variables calculadas.

Aquí se separan los usos variables. La sintaxis abreviada de Vue para v-bind está en uso, con :height="height" y lo mismo para y :

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

Cuando el padre de los elementos SVG establece variables que actúan como entrada para la temperature de la propiedad del termómetro, Vue vuelve a calcular la height y y . Como resultado, la posición y la altura del cuadro rojo cambian.

Es útil tener una lista de la aplicación Vue que utiliza el 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>

Eso es todo. Hay tres botones que llaman al método updateTemp de la aplicación thermoApp Vue. La sección de datos tiene dos variables de temperatura. Y, cada thermometer actualiza su temperatura cuando los valores cambian.

El código de los dos termómetros mencionados a continuación se puede encontrar en el código HTML asignado a la aplicación Vue.

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

Observe que la aplicación utiliza el formalismo de function para la definición del método. Definir updateTemp esta manera updateTemp: function (tval1,tval2) permite acceder a la variable de instancia this .

Además, definir updateTemp esta manera updateTemp: (tval1,tval2) => asigna this a una estructura de datos interna que no reacciona y actualiza la vista.

Montaje de un panel

Cada panel IoT puede ser un componente. Vue proporciona una forma de definir componentes con subcomponentes. Alternativamente, hay un mecanismo de ranura que se puede usar para producir un componente que puede envolver cualquier contenido HTML.

En los siguientes párrafos, veamos cómo hacer un panel a partir de subcomponentes. Hay dos formas que se siguen rápidamente de nuestros ejemplos. En un caso, los termómetros pueden ser subcomponentes llamados en JavaScript. En otro caso, los componentes se definen de forma independiente pero se mencionan en el HTML.

En ambos casos, se puede utilizar el mismo HTML para la plantilla. Aquí está nuestro panel como plantilla:

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

La única diferencia entre el primer detalle de la aplicación es que un elemento div rodea los dos termómetros. Vue arrojará un error si a la plantilla le falta un elemento DOM de nivel superior. El div pasa el requisito de Vue y los múltiples elementos pueden incluirse dentro de él.

Ahora, podemos ver los dos termómetros uno al lado del otro. Pasar las temperaturas desde la parte superior hasta el termómetro final tiene valores en cascada. En el nivel superior, el panel se une a la aplicación cuando se incluye una sola línea en el DOM de la aplicación.

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

La plantilla para el panel, aunque simple, parece indicar que los paneles se pueden diseñar fácilmente en términos de componentes. Es como si fuera posible un lenguaje solo para componentes de IoT.

Ahora, la definición de plantilla para el panel es bastante simple. Aquí está con los subcomponentes definidos de forma independiente:

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

Eso es todo lo que se requiere para que el panel funcione. Es cierto que esta versión se basa en una larga lista de propiedades para definir valores que se actualizarán a medida que ingresen mensajes a la página. Pero este es un buen comienzo. Actualizar el objeto de data en el nivel superior hace el trabajo de animar los termómetros. Sin embargo, a medida que los paneles se vuelven complicados, puede ser necesario otro método para mostrar el cambio.

Habiendo mencionado las otras formas de especificar subcomponentes, para el panel, deberíamos echarle un vistazo. Aquí lo tienes:

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

Ciertamente hay más código, pero eso se debe a que el JavaScript para el componente del thermometer está incluido en la lista de componentes del thermo-panel . Los dos enfoques hacen el mismo trabajo, pero ofrecen diferentes formas de empaquetar definiciones de componentes.

Por el momento, mi preferencia es por la primera forma. Debería ser considerablemente más fácil revisar los paneles y recuperarlos dinámicamente si solo se requiere cambiar la plantilla y las propiedades. Con este fin, los componentes definidos independientemente forman una biblioteca de componentes. Pero, aunque eso parece mejor, a continuación se vuelve más conveniente usar la segunda forma, aparentemente más detallada.

Dado que podemos crear paneles receptivos a partir de componentes de maneras claramente definidas, explicaré cómo podemos administrarlos como una base de datos que puede realizar consultas simples en la siguiente parte de mi artículo.