Componentes de páginas web SVG para IoT y creadores (Parte 2)

 

 

 

  • ¡Registro!
  • Clase magistral de CSS moderno avanzado, con Manuel Matuzović

  • Índice
    1. La aplicación perezosa
  • Conexión del panel al dispositivo IoT
  • Mantener el estado de la vista (Vue) sincronizado con los dispositivos
  • Conclusión
  • Al diseñar interfaces para una página web de IoT, siempre hay muchas opciones. En la parte anterior de este artículo, Richard Leddy arrojó luz sobre el significado de IoT y cómo se puede utilizar Vue.js para alojar grupos de interfaces hombre-máquina de IoT. Hoy, echemos un vistazo más de cerca a los paneles de carga diferida y cómo mantener el estado de Vue sincronizado con los dispositivos.

     

    Entonces, ya tenemos formas de cargar dinámicamente un menú de íconos SVG hechos para reaccionar cargando paneles si así lo deseamos, pero los íconos no eran componentes reales. Pudimos utilizar un truco simple para incorporar el SVG de cada ícono y pasarlo a la aplicación Vue. Fue bastante simple generar una lista de íconos, y cada ícono reaccionó de manera similar excepto por pequeñas diferencias en los datos. La diferencia de datos hizo posible vincular el nombre de un panel a cada ícono de tal manera que el controlador del clic del botón del ícono pudiera transmitirlo.

    Cuando un panel se carga en forma de componente Vue, se debe cargar todo lo relacionado con el panel y sus componentes, plantillas, JavaScript y más. Entonces, el trabajo de simplemente administrar la carga del panel es más grande que lo que hemos encontrado hasta ahora en esta discusión.

    Veamos la forma en que Vue proporciona un gancho para la carga asíncrona. El siguiente fragmento es de la guía de Vue .

    Vue.component('async-example', function (resolve, reject) { setTimeout(function () { // Pass the component definition to the resolve callback resolve({ template: 'divI am async!/div' }) }, 1000)})

    La guía nos dice que la función setTimeout es un ejemplo de cómo utilizar la sincronicidad con los componentes de Vue. Observe que donde antes había un objeto como segundo parámetro de Vue.component, ahora hay una función, a la que se hace referencia como función de fábrica. Dentro de la resolvedevolución de llamada hay una definición de componente, que habría sido el segundo parámetro Vue.componentanterior.

    Así que tuve que mirar este ejemplo un rato antes de que tuviera sentido para mí. Aquí hay otro ejemplo, que me conviene mejor:

    Vue.component('async-example', function (resolve, reject) { // Vue will call this function and promise itself to handle // it when it gets back with data. // this function can then call a promising object loader // here the 'loader' function is some abstract function. // Most likely the application will use 'fetch' // but it could be something else. loader('/my/resource/on/server.json'). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) = { handle it } );

    Parece que lo correcto es crear una función más general que evite este formulario.

    function componentLoader(c_name,resource_url) { Vue.component(c_name, function (resolve, reject) { loader(resource_url). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) = { handle it } );}

    Entonces, en general, para cargar un componente, solo necesitaríamos una línea como la siguiente:

    componentLoader('ThermoPanel','./JSON/thermo-panel.json');

    Entonces, ¿cuál es el JSON que se está cargando? Puede incluir todo lo relacionado con el componente. En este caso, como componente del panel, puede incluir termómetros, interruptores de máquina, controles deslizantes, medidores y más. Si bien parecía mejor mantener los componentes en la página web, en realidad puede funcionar mejor usar el campo de subcomponente que se encuentra en el ejemplo más largo para el "panel térmico" que hicimos antes y también para los otros paneles construidos de manera similar. El JSON contendrá una estructura de panel completa.

    Sin embargo, si el lector nota la inclusión de la llamada a la función transformJSONToJSObject, comprenderá que JSON podría estar codificado de alguna manera para facilitar el transporte y facilitarle al servidor el manejo de la definición. Después de todo, la definición incluirá plantillas SVG completas, definiciones de funciones y otras expresiones de JavaScript. Además, el objeto JSON puede contener algo más que la definición del panel porque cierta información puede simplemente ayudar en la contabilidad o la validación. Por lo tanto, se puede esperar que haya algún tratamiento del objeto al recibirlo.

    En cuanto a la codificación, los datos que llegan desde el servidor pueden codificarse de varias maneras. Quizás esté simplemente codificado en URL. O, de forma más segura, podría estar cifrado. Para esta discusión, podemos usar codificación URL.

    Algunas de las herramientas disponibles para crear aplicaciones Vue sin duda se encargan de la transformación JSON. Pero hasta ahora esta discusión ha evitado el uso de herramientas de línea de comandos. Esta omisión no es tan mala ya que también hemos usado Vue con el mínimo de recursos, usando solo una etiqueta de script para hacer referencia a la CDN. Sin embargo, ciertamente recomiendo buscar herramientas de línea de comandos, especialmente para organizar proyectos.

    Cuando el JSON llega a la página, dado que el componente está completamente ensamblado con subcomponentes, no es necesario realizar más trabajo para buscar las piezas. Podemos suponer que todos los componentes quedarán completamente definidos durante el resto de esta discusión. Sin embargo, ensamblar jerarquías completas de componentes requerirá herramientas de línea de comandos en algún momento.

     

    El proceso de edición de SVG también requerirá algo de trabajo. Los procesos de edición de SVG permiten a un diseñador dibujar un panel y todos los componentes que contiene. Pero cada subcomponente debe identificarse, nombrarse en un grupo o asignarse un lugar reservado. Cualquier enfoque para utilizar el dibujo requiere algún tratamiento del SVG para que las etiquetas de los componentes de Vue puedan reemplazar los grupos o elementos gráficos. De esta manera, cualquier representación de un artista puede convertirse en una plantilla. Y los subcomponentes dibujados deberán desmontarse en plantillas para los subcomponentes de Vue.

    Este tipo de parsimonia es contrario al flujo de trabajo de la mayoría de los marcos de JavaScript. Los marcos consisten en ensamblar páginas. Pero, editar o dibujar, da como resultado algo ya ensamblado por un artista. En la práctica, el resultado de la edición no proporciona un archivo de texto que corresponda directamente a la definición de un componente del marco.

    Es posible que se considere más sobre el proceso de edición en alguna otra discusión. Hay mucho que decir. Pero, por ahora, tenemos las herramientas que necesitamos para cargar componentes jerárquicos y darles vida.

    La aplicación perezosa

    Para la construcción de nuestros paneles IoT ya contamos con una barra de selección que responde a las búsquedas. Y tenemos una forma de cargar componentes cuando los necesitamos. Sólo necesitamos conectar estas partes. Y, por último, tenemos que asegurarnos de que los paneles aparezcan y de que empiecen a funcionar cuando lo hagan.

    La carga diferida de paneles realizada por el código asíncrono anterior proporciona un esbozo de una idea. Pero, afortunadamente, algunas personas han experimentado para encontrar formas de asegurarse de que se puedan cargar todo tipo de componentes. Hay una entrada de codepen que muestra cómo actualizar aplicaciones Vue con nuevos componentes de distintos tipos. Ese es el mecanismo necesario para actualizar una parte designada de la página con diferentes tipos de panel.

    Con la capacidad de agregar diferentes tipos de paneles y con un mecanismo simple para cargar sus definiciones, podemos, por fin, tener nuestra página de búsqueda de paneles.

    Aquí está el HTML que necesitamos en nuestra página para que la aplicación Vue pueda colocar componentes dinámicamente:

    template v-for="(panel, index) in panelList" component :is="panel" :key="panel.name"/component/template

    La componentetiqueta es una metaetiqueta de Vue. Consulte la referencia para componentes dinámicos . Las propiedades, atributos especiales, utilizados para la componentetiqueta en este caso son is y key . El isatributo existe para componentes dinámicos. Y keygarantiza que los nuevos niños tendrán identidades diferentes entre sí y ayuda a Vue a decidir qué dibujar.

    “Los hijos del mismo padre común deben tener claves únicas. Las claves duplicadas provocarán errores de representación ".

     

    La templateetiqueta recorrerá los componentes que se proporcionan en el panelListcampo de datos de la aplicación.

    Entonces, comenzando con la definición de Vue a nivel de aplicación para la aplicación de íconos, podemos realizar cambios para incluir panelList en los elementos de datos. (Ahora llamémoslo panelApp).

    var panelApp = new Vue({ el: '#PanelApp', data: { iconList: [ // Where is the data? Still on the server. ], panelList: [ ], queryToken : "Thermo Batches" // picked a name for demo }, methods : { goGetPanel: function (pname) { // var url = panelURL(pname); // this is custom to the site. fetch(url).then((response) = { // this is now browser native response.text().then((text) = { var newData = decodeURIComponent(text); eval(pHat); // widgdef = object def, must be assignment pHat = widgdef; var pnameHat = pname + pcount++; pHat.name = pnameHat; // this is needed for the key this.panelList.push(pHat); // now it’s there. }).catch( error = { /* handle it */ }); } } });

    Además de agregarse en el panel, goGetPanelahora está en un formulario necesario para obtener una definición de componente de una base de datos u otro almacén. El lado del servidor debe tener cuidado al entregar el código JavaScript en el formato correcto. En cuanto a cómo se ve el objeto proveniente del servidor, ya lo hemos visto. Es el tipo de objeto que se utiliza como parámetro Vue.component.

    Aquí está el cuerpo completo de la aplicación Vue que proporciona un menú como resultado de búsqueda y un lugar para colocar paneles obtenidos del servidor cuando el usuario hace clic en un ícono.

    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 buttonFind All/button buttonFind 5 Point/button buttonFind 6 Point/button /div !-- Here is a Vue loop for generating a lit -- div button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" div v-html="iconEntry.icon" /div /button /div div template v-for="(panel, index) in panelList" component :is="panel" :key="panel.name" :ref="panel.name" /component /template /div/div

    En el último div, la componentetiqueta ahora tiene un refparámetro vinculado al nombre del panel. El parámetro ref permite que la aplicación Vue identifique qué componente actualizar con datos y mantiene los componentes separados. Los refparámetros también permiten que nuestra aplicación acceda a los nuevos componentes cargados dinámicamente.

    En una versión de prueba de la aplicación del panel, tengo el siguiente controlador de intervalo:

    setInterval(() = { var refall = panelApp.$refs; // all named children that panels for ( var pname in refall ) { // in an object var pdata = refall[pname][0]; // off Vue translation, but it’s there. pdata.temp1 = Math.round(Math.random()*100); // make thermos jump around. pdata.temp2 = Math.round(Math.random()*100); }},2000)

    El código proporciona una pequeña animación, cambiando los termómetros al azar. Cada panel tiene dos termómetros y la aplicación permite al usuario seguir agregando paneles. (En la versión final, algunos paneles deben desecharse). Se accede a las referencias mediante panelApp.$refs, un campo que crea Vue dada la refsinformación de la componentetiqueta.

     

    Entonces, así es como se ven los termómetros que saltan aleatoriamente en una instantánea:

    Una colección de paneles animados para un tipo de panel (o componente). ( Vista previa grande )

    Conexión del panel al dispositivo IoT

    Entonces, el último fragmento de código es una setIntervalprueba que actualiza los termómetros con valores aleatorios cada dos segundos. Pero lo que queremos hacer es leer datos reales de máquinas reales. Para hacer eso, necesitaremos alguna forma de comunicación.

    Hay una variedad de formas. Pero usemos MQTT, que es un sistema de mensajes de publicación/subscripción. Nuestro SPWA puede suscribirse a mensajes de dispositivos en cualquier momento. Cuando recibe esos mensajes, el SPWA puede dirigir cada mensaje al controlador de datos apropiado para el panel asignado al dispositivo identificado en el mensaje. Todo sobre las islas canarias

    Entonces, básicamente lo que debemos hacer es reemplazar setIntervalcon un controlador de respuestas. Y eso será para un panel. Probablemente queramos asignar paneles a controladores a medida que se cargan. Y depende del servidor web asegurarse de que se entregue el mapeo correcto.

    Una vez que el servidor web y el SPWA tienen la página lista para funcionar, el servidor web ya no necesita encargarse de la mensajería entre la página y el dispositivo. el protocolo MQTT especifica un servidor de enrutamiento para manejar pub/sub. Se han creado varios servidores MQTT. Algunos de ellos son de código abierto. Uno muy popular es Mosquito , y hay algunos desarrollados sobre Node.js.

    El proceso de la página es simple. La SPWA se suscribe a un tema. Una buena versión de un tema es un identificador de una MCU, como una dirección MAC o un número de serie. O bien, el SPWA podría suscribirse a todas las lecturas de temperatura. Pero entonces la página tendría que hacer el trabajo de filtrar los mensajes de todos los dispositivos. La publicación en MQTT es esencialmente una transmisión o multidifusión.

    Echemos un vistazo a cómo interactuará SPWA con MQTT.

    Inicializando MQTT en el SPWA

    Hay varias bibliotecas cliente para elegir. Uno, por ejemplo, es MQTT.js. Otro es el eclipse paho . Hay más por supuesto. Usemos Eclipse Paho ya que tiene una versión almacenada en CDN. Sólo necesitamos agregar la siguiente línea a nuestra página:

    script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"/script

    El cliente MQTT debe conectarse a un servidor antes de poder enviar y recibir mensajes. Por lo tanto, las líneas que configuran la conexión también deben incluirse en JavaScript. Podemos agregar una función MQTTinitializeque configura el cliente y las respuestas para la gestión de la conexión y la recepción de mensajes.

     

    var messagesReady = false;var mqttClient = null;function MQTTinitialize() { mqttClient = new Paho.MQTT.Client(MQTTHostname, Number(MQTTPort), "clientId"); mqttClient.onMessageArrived = onMessageArrived; // connect the client mqttClient.connect({ onSuccess: () = { messagesReady = true; } }); // set callback handlers mqttClient.onConnectionLost = (response) = { // messagesReady = false; // if (response.errorCode !== 0) { console.log("onConnectionLost:"+response.errorMessage); } setTimeout(() = { MQTTinitialize() },1000); // try again in a second };}

    Configurar la suscripción

    Con la conexión lista, el cliente puede suscribirse a canales de mensajes, enviar mensajes a través de ellos, etc. Sólo unas pocas rutinas pueden hacer la mayor parte del trabajo necesario para conectar los paneles con las rutas MQTT.

    Para el panel SPWA, el momento de la suscripción se puede utilizar para establecer la asociación entre el panel y el tema, el identificador de MCU.

    function panelSubcription(topic,panel) { gTopicToPanel[topic] = panel; gPanelToTopic[panel] = topic; mqttClient.subscribe(topic);}

    Dado que una MCU está publicando sobre su tema, la SPWA recibirá un mensaje. Aquí se descomprime el mensaje de la OPS. Y luego el mensaje se transmite a la mecánica de la aplicación.

    function onMessageArrived(pmessage) { // var topic = pmessage.destinationName; var message = pmessage.payloadString; // var panel = gTopicToPanel[topic]; deliverToPanel(panel,message);}

    Entonces, ahora todo lo que tenemos que hacer es crear deliverToPanelel cual debería ser algo así como el controlador de intervalo que teníamos antes. Sin embargo, el panel está claramente identificado y sólo se pueden actualizar los datos clave enviados en el mensaje particular.

    function deliverToPanel(panel,message) { var refall = panelApp.$refs; // all named children that panels var pdata = refall[panel][0]; // off Vue translation, but it’s there. var MCU_updates = JSON.parse(message); for ( var ky in MCU_updates ) { pdata[ky] = MCU_updates[ky] }}

    Esta deliverToPanelfunción es lo suficientemente abstracta como para permitir cualquier definición de panel con cualquier número de puntos de datos para la animación.

    Enviando mensajes

    Para completar el bucle de aplicación entre la MCU y la SPWA, definimos una función para enviar un mensaje.

    function sendPanelMessage(panel,message) { var topic = gPanelToTopic[panel]; var pmessage = new Paho.MQTT.Message(message); pmessage.destinationName = topic; mqttClient.send(pmessage);}

    La sendPanelMessagefunción no hace más que enviar el mensaje en la misma ruta temática a la que se suscribe la SPWA.

    Como planeamos hacer que los botones de íconos sean responsables de incorporar una cierta cantidad de paneles para un solo grupo de MCU, habrá más de un panel del que ocuparse. Pero tenemos en cuenta que cada panel corresponde a una única MCU, por lo que tenemos un mapeo uno a uno, para lo cual podemos usar dos mapas de JavaScript para el mapa y a la inversa.

    Entonces, ¿cuándo enviamos mensajes? Normalmente, la aplicación del panel enviará un mensaje cuando quiera cambiar el estado de la MCU.

     

    Mantener el estado de la vista (Vue) sincronizado con los dispositivos

    Una de las mejores cosas de Vue es que es muy fácil mantener el modelo de datos sincronizado con la actividad del usuario, quien puede editar campos, hacer clic en botones, usar controles deslizantes, etc. Uno puede estar seguro de que los cambios de botones y campos se realizarán. se reflejará inmediatamente en los campos de datos de los componentes.

    Pero queremos que los cambios envíen mensajes a la MCU tan pronto como se produzcan. Por lo tanto, buscamos hacer uso de los eventos de interfaz que Vue puede regir. Buscamos responder a tal evento, pero solo después de que el modelo de datos de Vue esté listo con el valor actual.

    Creé otro tipo de panel, este con un botón de aspecto bastante artístico (quizás inspirado en Jackson Pollock). Y comencé a convertirlo en algo cuyo clic informa el estado al panel que lo contiene. Ese no fue un proceso tan simple.

    Una cosa que me desconcertó es que había olvidado algunas de las rarezas en la gestión de SVG. Primero intenté cambiar la cadena de estilo para que el displaycampo del estilo CSS fuera "Ninguno" o "algo". Pero el navegador nunca reescribió la cadena de estilos. Pero como eso era engorroso, intenté cambiar la clase CSS. Eso tampoco tuvo ningún efecto. Pero ahí está el visibilityatributo, que la mayoría de nosotros recordamos del antiguo HTML (quizás la versión 1.0), pero que está muy actualizado en SVG. Y eso funciona bien. Todo lo que tenía que hacer era hacer que el evento de clic en el botón se propagara.

    Vue ha diseñado propiedades para propagarse en una dirección, de padre a hijo. Entonces, para cambiar datos en la aplicación o en el panel, debe enviar un evento de cambio al padre. Luego, puedes cambiar los datos. El cambio del elemento de datos que controla el botón hace que Vue actualice la propiedad afectando la visibilidad del elemento SVG que hemos elegido para indicar el estado. Aquí hay un ejemplo:

    Finalmente, una colección de diferentes tipos de paneles, cada uno con instancias asignadas a MCU independientes. ( Vista previa grande )

    Cada instancia del panel de botones ondulado es independiente. Entonces, algunos están ENCENDIDOS y otros APAGADOS.

    Este fragmento de SVG contiene el indicador amarillo de aspecto extraño:

    path :visibility="stateView" d="m -36.544616,12.266886 c 19.953088,17.062165 5.07961,-19.8251069 5.317463,8.531597 0.237853,28.356704 13.440044,-8.847959 -3.230451,10.779678 -16.670496,19.627638 14.254699,-2.017715 -11.652451,3.586456 -25.90715,5.60417 10.847826,19.889979 -8.095928,-1.546575 -18.943754,-21.436555 -1.177383,14.210702 -4.176821,-12.416207 -2.999438,-26.6269084 -17.110198,8.030902 2.14399,-8.927709 19.254188,-16.9586105 -19.075538,-8.0837048 9.448721,-5.4384245 28.52426,2.6452804 -9.707612,-11.6309807 10.245477,5.4311845 z" transform="translate(78.340803,6.1372042)" /

    La visibilidad se completa con stateView, una variable calculada que asigna el estado booleano a una cadena para SVG.

    Aquí está la plantilla de definición de componentes del panel:

    script type="text/x-template" div control-switch :state="bstate" v-on:changed="saveChanges" /control-switch gauge :level="fluidLevel" /gauge /div/script

    Y esta es la definición de JavaScript del panel Vue con sus hijos como subcomponentes:

     

    var widgdef = { data: function () { var currentPanel = { // at the top level, values controlling children bstate : true, fluidLevel : Math.round(Math.random()*100) } // return currentPanel }, template: '#mcu-control-panel-template', methods: { saveChanges: function() { // in real life, there is more specificity this.bstate = !this.bstate relayToMCU(this.name,"button",this.bstate) // to be defined } }, components: { 'control-switch' : { // the odd looking button props: [’state'], template: '#control-switch-template', // for demo it is in the page. computed: { // you saw this in the SVG above. stateView : function() { return ( this.state ) ? "visible" : "hidden" } }, methods : { // the button handler is in the SVG template at the top. stateChange : function () { // can send this.$emit('changed'); // tell the parent. See on the template instance } } }, 'gauge' : { // some other nice bit of SVG props: ['level'], template: '#gauge-template' } }}

    Así pues, ahora se ha presentado el mecanismo para un único botón incrustado en un panel. Y tiene que haber un gancho para decirle al MCU que algo ha sucedido. Debe llamarse inmediatamente después de que se haya actualizado el estado de los datos del componente del panel. Definámoslo aquí:

    function relayToMCU(panel,switchName,bstate) { var message = switchName + ':' + bstate // a on element parameter string. sendPanelMessage(panel,message)}

    Está el cambio de estado en camino al hardware en solo dos líneas de código.

    Pero este es un caso bastante simple. Cualquier interruptor puede verse como una llamada de función a una pieza de hardware en el mundo. Por lo tanto, la cadena puede contener el nombre del conmutador y varios otros elementos de datos. Por lo tanto, el método del componente que registra el cambio tendrá que tener algún manejo personalizado para que pueda reunir todos los datos establecidos en el panel y enviarlos en una cadena de comando. Incluso la cadena de comando es un poco simple. Si la MCU es bastante pequeña, es posible que la cadena de comando deba traducirse a un código. Si la MCU tiene mucha capacidad, la cadena de comando podría ser en realidad una estructura JSON o quizás todos los datos que aloja el panel.

    En esta discusión, los botones en el panel de íconos contienen el nombre del panel a buscar. Esto también puede simplificarse bastante. Parece tener sentido que ese parámetro pueda representar cualquier panel que pueda estar almacenado en la base de datos de una empresa. Pero quizás sea alguna fórmula. Quizás, la información sobre el panel debería incluirse en la definición del panel que recibimos del servidor. En cualquier caso, los conceptos básicos se pueden ampliar fácilmente una vez que se eliminen ciertos dolores de cabeza, como hacer que el SVG responda correctamente a los clics.

    Conclusión

    Esta discusión ha establecido algunos pasos y decisiones básicos que conducen a la realización de una aplicación web de página única (SPWA) que puede interactuar con dispositivos IoT. Ahora sabemos cómo obtener paneles de un servidor web y convertirlos en una interfaz MCU.

    Hay mucho más en esta discusión y muchas otras discusiones pueden seguir. Comenzar con Vue es algo en lo que pensar. Pero luego está toda la historia del MCU, que sólo hemos mencionado brevemente.

    En particular, al seleccionar MQTT como sustrato de comunicación, asumimos que MQTT puede controlar de alguna manera los dispositivos IoT en el otro extremo. Pero puede que ese no sea siempre el caso. A veces se necesitan puertas de enlace para que MQTT obtenga acceso a un dispositivo con enlaces serie o Bluetooth. O quizás todo lo que uno necesita en la página web son WebSockets. Sin embargo, utilizamos MQTT como ejemplo para mostrar cómo Vue podría recibir y enviar datos mientras mantiene su estado sincronizado con los dispositivos.

    Una vez más sólo tenemos una parte de la historia. Esta vez es para sincronización porque la página debería poder manejar alertas y molestar al usuario si sucede algo crítico. A veces los mensajes pueden perderse. Entonces, tenemos que tener un mecanismo para los agradecimientos.

    Finalmente, en mi opinión, Vue hace que la actualización de los datos al recibirlos sea bastante elegante. Pero enviar los cambios de estado no es tan sencillo. No parece hacer el trabajo mucho más simple de lo que se puede hacer con JavaScript básico. Pero hay una manera y tiene sentido.

    Quizás se pueda construir una biblioteca limpia para crear un conjunto universal de componentes para todos los paneles. Se han mencionado brevemente los elementos para crear dichas bibliotecas y almacenarlas en una base de datos. Es posible que sea necesario desarrollar herramientas que vayan más allá de la simple creación de imágenes SVG. En cualquier caso, es probable que se puedan hacer muchas cosas para los próximos pasos.

    (dm, yk, il)Explora más en

    • javascript
    • vista
    • SVG





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Componentes de páginas web SVG para IoT y creadores (Parte 2)

    Componentes de páginas web SVG para IoT y creadores (Parte 2)

    ¡Registro! Clase magistral de CSS moderno avanzado, con Manuel Matuzović Índice La aplicación perezosa

    programar

    es

    https://aprendeprogramando.es/static/images/programar-componentes-de-paginas-web-svg-para-iot-y-creadores-parte-2-983-0.jpg

    2024-05-20

     

    Componentes de páginas web SVG para IoT y creadores (Parte 2)
    Componentes de páginas web SVG para IoT y creadores (Parte 2)

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20