Para el tutorial de hoy vamos a empezar a diseñar y crear gráficos de bars usando D3.js, sigue leyendo para que sepas cómo hacerlo
First of all, what is D3.js?
D3.js es una biblioteca de JavaScript basada en datos para manipular elementos DOM.
“D3 te ayuda a dar vida a los datos mediante HTML, SVG y CSS. El énfasis de D3 en los estándares Web le brinda todas las capacidades de los browsers modernos sin atarse a un marco propietario, combinando poderosos componentes de visualización y un enfoque basado en datos para la manipulación de DOM «. – d3js.org
Why should you create charts with D3.js? Why not just show an image?
Well, the charts are based on information from third party resources that require dynamic display during processing time. Also, SVG is a very powerful tool that is well suited to this application case.
Let's take a detour to see what benefits we can get from using SVG.
The benefits of SVG
SVG significa gráficos vectoriales escalables, que técnicamente es un lenguaje de marcado basado en XML.
It is commonly used to draw vector graphics, specify lines and shapes, or modify existing images.
Pros:
- Compatible with all major browsers
- Has DOM interface, does not require third party lib
- Scalable, can maintain high resolution
- Reduced size compared to other image formats.
Cons:
- It can only display two-dimensional images;
- Long learning curve
- Rendering can be time consuming with compute intensive operations.
- Despite its drawbacks, SVG is a great tool for displaying icons, logos, illustrations, or in this case graphics.
Starting with D3.js
I chose the bar chart to start with because it represents a low complexity visual while teaching the basic D3.js application itself. This shouldn't fool you, D3 provides a great set of tools for visualizing data.
A bar chart can be horizontal or vertical depending on its orientation. I'll go with the column chart aka vertical.
En este diagrama, voy a mostrar los 10 lenguajes de programming más populares según el resultado de la Encuesta de Desarrolladores 2018 de Stack Overflow .
Time to draw!
SVG has a coordinate system that starts from the upper left corner (0; 0). The positive x-axis goes to the right, while the positive y-axis goes to the bottom. Therefore, the height of the SVG must be taken into account when calculating the y coordinate of an element.
I want to create a graphic that is 1000 pixels wide and 600 pixels high.
<body> <svg /> </body> <script> const margin = 60; const width = 1000 - 2 * margin; const height = 600 - 2 * margin; const svg = d3.select('svg'); </script>
In the above code snippet, I select the created element in the HTML file with D3 select. This selection method accepts all types of selection strings and returns the first matching element. Use selectAll if you want to get all of them.
También defino un valor de margen que le da un poco de relleno adicional al gráfico. El relleno se puede aplicar con un elemento <g> traducido por el valor deseado. De ahora en adelante, recurro a este grupo para mantener una buena distancia de cualquier otro contents of the page.
const chart = svg.append ('g') .attr ('transform', `translate ($ {margin}, $ {margin})`);
Agregar atributos a un elemento es tan fácil como llamar al método attr. El primer parámetro del método toma un attribute que quiero aplicar al elemento DOM seleccionado. El segundo parámetro es el valor o una función de devolución de llamada que devuelve su valor. El código anterior simplemente mueve el inicio del gráfico a la posición (60; 60) del SVG.
D3.js input formats supported
To start drawing, I need to define the data source that I am working from. For this tutorial I use a simple JavaScript array that contains objects with the name of the languages and their percentages, but it is important to mention that D3.js supports various data formats.
The library has built-in functionality to load from XMLHttpRequest, .csv files, text files, etc. Each of these sources can contain data that D3.js can use, the only important thing is to build an array from it. Note that as of version 5.0, the library uses promises instead of callbacks to load data, which is not a backward-compatible change.
Scaling and axes
Let's continue with the axes of the graph. To draw the axis and, I need to set the lowest and highest value limit, which in this case are 0 and 100.
I'm working with percentages in this tutorial, but there are utility functions for data types other than numbers that I'll explain later.
I have to divide the height of the graph between these two values in equal parts. For this, I create something called a scaling function.
const yScale = d3.scaleLinear () .range ([height, 0]) .domain ([0, 100]);
La escala lineal es el tipo de escala más conocido. Convierte un domain de entrada continuo en un rango de salida continuo. Observa el método rangey domain. El primero toma la longitud que debe dividirse entre los límites de los valores del dominio.
Remember, the SVG coordinate system starts from the upper left corner, so the range takes the height as the first parameter and not zero.
Creating a left axis is as simple as adding another group and calling D3's axisLeft method with the scale function as a parameter.
chart.append ('g') .call (d3.axisLeft (yScale));
Now, continue with the x-axis.
const xScale = d3.scaleBand () .range ([0, width]) .domain (sample.map ((s) => s.language)) .padding (0.2) chart.append ('g') .attr ( 'transform', `translate (0, $ {height})`) .call (d3.axisBottom (xScale)); d3-js-tutorial-bar-chart-labels
Note that I use scaleBand for the x-axis, which helps to divide the range into bands and calculate the coordinates and widths of the bars with additional padding.
D3.js is also capable of handling the date type among many others. scaleTime is really similar to scaleLinear, except the domain here is a set of dates.
Drawing bars in D3.js
Think about what kind of input we need to draw the bars. Each represents a value that is illustrated with simple shapes, specifically rectangles. In the following code snippet, I attach them to the created group item.
chart.selectAll () .data (goals) .enter () .append ('rect') .attr ('x', (s) => xScale (s.language)) .attr ('y', (s) => yScale (s.value)) .attr ('height', (s) => height - yScale (s.value)) .attr ('width', xScale.bandwidth ())
First, you use selectAll to select the elements in the chart that returns with an empty result set. Then the data function that indicates how many elements the DOM should be updated based on the length of the array. enter identifies missing items if the data entry is longer than the selection. This returns a new selection representing the items to be added. Usually this is followed by an append element that adds elements to the DOM.
Basically I tell D3.js to add a rectangle for each member of the array.
Now this just adds rectangles on top of each other that have neither height nor width. These two attributes have to be calculated and that is where scaling functions come in handy again.
Look, I add the coordinates of the rectangles with the attr called. The second parameter can be a callback that takes 3 parameters: the actual member of the input data, its index, and the entire input.
.attr ('x', (actual, index, array) => xScale (actual.value))
The scale function returns the coordinate for a given domain value. Calculating the coordinates is a piece of cake, the trick is with the height of the bar. The calculated y-coordinate must be subtracted from the height of the graph to get the correct representation of the value as a column.
I define the width of the rectangles with the scaling function also scaleBand has a bandwidth function that returns the calculated width for an element based on the padding set.
d3-js-tutorial-bar-chart-drawn-out-with-javascript
Nice work, but not so fancy, right?
To prevent our audience from getting bored, let's add information and enhance the images to make your graphic look much better!