Dibujar con SVG los gráficos de datos de sensores conectados a la Internet de las cosas (IoT)

Dibujar con SVG los gráficos de datos de sensores conectados a la Internet de las cosas (IoT)

Dibujar con SVG los gráficos de datos de sensores conectados a la Internet de las cosas (IoT)

En este artículo de la serie sobre la representación de gráficos de datos en la IoT explico cómo trazar las gráficas usando el lenguaje SVG. Como en las otras ocasiones, el artículo también sirve como una pequeña introducción al lenguaje.

Tabla de contenidos

    Gráficos de datos de los sensores conectados a la Internet de las cosas (IoT) contenedor en HTMLGráficos de datos de los sensores conectados a la Internet de las cosas (IoT) definición del aspecto en CSSGráficos de datos de los sensores conectados a la Internet de las cosas (IoT) dibujo con SVGGráficos de datos de los sensores conectados a la Internet de las cosas (IoT) Generación y modificación con JavaScript

    El formato SVG

    SVG corresponde con las siglas de Scalable Vector Graphics (gráficos vectoriales escalables, en inglés). Es un lenguaje de marcado que se basa en XML y que permite, principalmente, describir un dibujo por la geometría que lo define; en contraposición al método matricial, que se utiliza por ejemplo para una fotografía, que usaría una cuadrícula de píxeles de color para codificarla.

    Dentro de un dibujo SVG puede incluirse también una imagen (una matriz de píxeles) ya sea haciendo referencia a un documento externo o incrustada dentro del propio dibujo SVG.

    La versión del lenguaje que está vigente en el momento de escribir este artículo es la SVG 1.1 aunque ya se está elaborando la definición de la versión SVG 2. En lo posible, intentaré que lo que se explica en la introducción, aunque se refiera a SVG 1.1 sirva también para SVG 2.

    Si el dibujo SVG se incluye en un documento separado y no dentro del código HTML (mi propuesta en esta solución para representar datos de la IoT lo embebe en el código HTML) debe estar encabezado por una referencia XML y una definición de tipo de documento (DTD).

    En la primera línea del código anterior se avisa de la versión XML usada (la 1.0) la codificación de caracteres (UTF-8) y se indica si necesita definiciones externas (standalone="no") o es un documento independiente (standalone="yes"). La segunda línea expresa la definición de tipo de documento (DTD), que no será necesaria en la próxima versión de SVG.

    El código con el que se define el dibujo va encerrado entre las etiquetas <sgv> y </sgv> que además indican, como ya se adelantó al hablar del código HTML que hace de contenedor a las gráficas de datos en la IoT, las medidas, la parte del total representada, la proporción y también el tipo y la versión.

    El ejemplo anterior define un dibujo de 500 píxeles de ancho por 250 píxeles de alto (viewport de 500×250) que se recortará con un rectángulo de 460×80 (viewbox de 460×80) que empieza en las coordenadas 20,10 utilizando todo el espacio disponible en el contenedor (un elemento en una página web, en nuestro caso) sin respetar la proporción original por usar preserveAspectRatio="none". Además ya puede verse el primer contenido del documento, los comentarios que se incluyen entre <!-- y --> como en otros formatos basados en XML.

    El sistema de coordenadas elegido por SVG está orientado según la horizontal (eje X) y la vertical (eje Y) y el sentido positivo es el de la escritura occidental, es decir, los valores del eje X crecen hacia la derecha y los valores positivos del eje Y crecen hacia abajo.

    Definir la gráfica con SVG

    Para definir los gráficos de la información almacenada por nuestros sensores conectados a IoT necesitaremos especificar el tipo de objeto que se dibuja, su geometría (coordenadas, dimensiones…) y su aspecto (grosor, color…) En el ejemplo de este artículo se utiliza un gráfico de líneas que puede hacerse uniendo segmentos de líneas con el objeto line, más útil para trazar elementos independientes, o con una línea de múltiples segmentos, un objeto path, más práctico para series de líneas conectadas.

    Con el elemento path se busca hacer un dibujo como el de la imagen de abajo, que está formada por un trazado cerrado y relleno de color más claro rematado en la parte superior por un trazado abierto, sin relleno y dibujado con una línea gruesa.

    Para describir una línea se usa una expresión del tipo:

    En la que X1,Y1 son las coordenadas del primer punto de la línea y X2,Y2 las del segundo. Se ha utilizado un atributo stroke-width para definir el grosor. Hay varias formas de definir el aspecto de los objetos SVG, con sus propiedades individuales, como la anterior, o con la propiedad style que las reúne a todas y que es el método que se va a usar en la propuesta del artículo.

    El código anterior une en la propiedad style los valores de stroke (el color del trazo), stroke-width (el grosor de la línea) y stroke-opacity (la opacidad del objeto)

    La descripción de un objeto path tiene la forma

    El código anterior usa las operaciones SVG M, L y Z dentro de la propiedad d, que significan, respectivamente, «moveto» (mover a), «lineto» (línea hasta) y «closepath» (cerrar trayecto). Pueden expresarse en mayúsculas o minúsculas para indicar un valor absoluto o relativo cuando proceda (en el caso de Z, por ejemplo, es irrelevante). Existen muchas otras operaciones con las que, por ejemplo, trazar curvas circulares, curvas elípticas, curvas Bézier… que en este ejemplo no necesitaremos.

    Aunque en esta propuesta se trazan gráficos de líneas que pueden encerrar un área, puede ser útil dibujar otros elementos sencillos para marcar puntos o para resaltar zonas. De entre los disponibles en SVG pueden ser interesantes los polígonos (con los que también se puede dibujar el relleno), los rectángulos (más cómodos para el caso concreto), las elipses y los círculos (como un caso particular de las elipses). La sintaxis de estos elementos puede verse en el siguiente código de ejemplo.

    El aspecto del código anterior sería como el de la siguiente imagen (con algún truco para poder reutilizar los puntos del ejemplo de más arriba)

    Las puntos del polígono (polygon) se indican en la propiedad points como pares de coordenadas x,y separados por espacios entre ellos. Para definir las elipses (ellipse) se usan las propiedades cx (coordenada x del centro), cy (coordenada y del centro), rx (ancho) y ry (alto). En lugar de dos valores de radio (radio horizontal y vertical, rx y ry) el círculo (circle) se define por un radio con la propiedad r y las coordenadas del centro con cx y cy. Para definir el rectángulo (rectangle) se indican las coordenadas de la esquina superior izquierda (x e y) el ancho (width) y el alto (height)

    Por último, para incluir un texto se utiliza el objeto text de la siguiente forma:

    La posición del texto se indica con las coordenadas x e y, el tipo de letra corresponde con la propiedad font-family, el tamaño con font-size y el color con la propiedad fill.

    HTML permite integrar dibujos SVG como un elemento más de la página. Como otros objetos, se puede usar la propiedad ID para asignarles un identificador único con el que luego se podrán referir desde JavaScript para manipularlos. Desde el punto de vista de HTML, un objeto SVG tendría la forma siguiente:

    Con lo visto hasta ahora ya sería posible trazar el tipo de gráfico básico que se busca en esta propuesta pero, para dar flexibilidad al aspecto del contenedor (la página web) la proporción del gráfico se va a ver afectada (por preserveAspectRatio="none") al modificar su tamaño para adaptarlo a la distribución en la ventana del navegador de los elementos HTML.

    En líneas generales, existen dos alternativas al de comportamiento al modificar el tamaño de la ventana del navegador que muestra el la página web contenedor del gráfico: (1) mantener el tamaño del gráfico SVG dejando espacios en blanco si sobra o añadiendo barras de desplazamiento si falta o (2) modificar el tamaño del gráfico SVG de manera acompasada a cambio de tamaño de la ventana del navegador que muestra la web. Si se opta por la primera fórmula se pueden predecir las magnitudes y dibujar con medidas absolutas, aunque corregidas en función del tamaño elegido y de los valores del gráfico. Si se opta por la segunda forma, que es la que propongo, las magnitudes son siempre porcentajes de los valores representados. La ventaja del segundo método es su adaptabilidad a la web y el inconveniente el dibujo de los elementos que acompañan a la gráfica, como puntos o textos.

    Para corregir la deformación que podría producirse en el grosor de las líneas se utiliza el efecto vector-effect="non-scaling-stroke" en los trazados que sea necesario (los que tengan un valor de stroke que no sea none). Para los objetos text no hay un efecto equiparable, por lo que es necesario deformarlos (junto con los que estén asociados a ellos) en el sentido contrario al producido por el cambio de tamaño del contenedor.

    Las transformaciones en SVG se pueden aplicar a grupos de objetos de manera que se pueden integrar varios textos y otros objetos de un gráfico en un único grupo y realizar, más cómodamente, una transformación para todos ellos.

    Los elementos que forman parte de un grupo se incluyen entre las etiquetas <g> y </g>, para asignarle una transformación se utiliza la propiedad transform y una serie de operaciones de las que, para nuestro caso, es relevante scale, a la que se le indica un factor de ampliación en horizontal y vertical. Si el valor de scale es mayor que uno amplia en el eje correspondiente y si es menor que uno se produce una reducción de tamaño de los objetos a lo largo de ese eje.

    En el ejemplo anterior, el primer y segundo texto se modifican reduciendo a la mitad su medida horizontal y ampliando al doble el vertical por los valores 0.5 y 2.0 usados en scale(0.5,2.0)

    El próximo artículo de la serie sobre representación de gráficos de datos de sensores conectados a la IoT explica cómo generar o modificar en tiempo real los gráficos utilizando JavaScript lo que permitirá ir viendo una animación del gráfico al representar los últimos valores cargados del servidor.

    El siguiente es un ejemplo de cómo quedarían los gráficos generados utilizando esta propuesta.

    Puede que te hayas perdido