A D3 és a React kezdete

Az adatközpontú dokumentumok (D3.js) egy JavaScript-könyvtár, amelyet HTML, CSS és SVG használatával hoznak létre az adatok vizualizálásához. Ezt úgy teszi, hogy az adatokat a DOM-hoz (Document Object Model) és annak elemeihez köti, és lehetővé teszi számukra, hogy átalakuljanak, amikor az adatok megváltoznak.

Tegyük fel például, hogy szeretnénk létrehozni egy kördiagramot a könyvtár minden műfajában szereplő könyvek mennyiségéről. Van néhány adatunk, amelyet minden alkalommal frissítünk, amikor egy könyvtáros új könyvbe lép. Tároljuk az alkalmazás állapotában, a „könyvek” nevű változóban.

const [books, setBooks] = useState(initialBooks) const initialBooks = [ { name: "Harry Potter and the Philosophers Stone", author: "J. K. Rowling", genre: "fantasy" },{ name: "The Pedagogy of Freedom", author: "Bell hooks", genre: "non-fiction" },{ name: "Harry Potter and the Chamber of Secrets", author: "J. K. Rowling", genre: "fantasy" },{ name: "Gilgamesh", author: "Derrek Hines", genre: "poetry" } ]

Most létrehozhatnánk egy táblázatot, amely a fantázia 50% -át, a szépirodalom 25% -át és a költészet 25% -át tartalmazza. Amikor a könyvtáros új könyvet vesz fel az adatbázisba, az adatok megváltoznak, és a graft elmozdul. Tegyük fel, hogy hozzáadunk „50 vegán ételt”.

setBooks(books.concat( { name: "50 vegan dishes", author: "Antti Leppänen", genre: "non-fiction" } ))

Amikor ezek az adatok megváltoznak, a D3 grafikonunk frissíti a DOM-ot az új adatokkal. Most 40% fantázia, 40% nem szépirodalom és 20% vers. A D3 megkönnyíti a DOM weboldal manipulálását. Ez azt jelenti, hogy felhasználhatja elemek létrehozására, frissítésére és törlésére az oldalszerkezetben.

Ha követni szeretné ezt a példát, akkor a React alkalmazás létrehozása segítségével létrehozhat egy egyszerű React webalkalmazást. Ha a React még mindig ismeretlen az Ön számára, megnézheti ezt az oktatóanyagot a React dokumentációjában.

  1. Hozzon létre egy új alkalmazást, a my-d4-app nevet npx create-react-app my-d3-app. Változtassa a könyvtárat a létrehozott mappába a használatával cd my-d3-app.
  2. Telepítse a D3-at futtatással npm install d3 --save.
  3. A D3 fájlt hozzáadással importálja az App.js fájlba import * as d3 from d3. Az import * -ot kell használnia („importál mindent”), mivel a D3-nak nincs alapértelmezett exportált modulja.

DOM elemek kiválasztása

A D3 megkönnyíti a DOM manipulálását. Például próbáljunk meg mindent megváltoztatnit;

Original text


-elements to have an inline style setting the color to blue.

d3.selectAll("p").style("color", "blue")

The .selectAll()-method allows us to select all elements of a specific type. We can also use .select() to select individual nodes.

The React library also manipulates the DOM. This means we have to make a little extra effort to get it to work together with D3. Luckily React already has a solution for allowing targeting and updating DOM elements. To do this, React uses references.

Let’s create a -element and add a reference to it, and then use the reference to pick it up with D3.

d3.select(this.refs.myDiv).style(“background-color”, “blue”) render( )

Appending elements to the DOM

Once you have selected the element you want to manipulate, you can start appending more elements to it. For example, imagine we have a

    . We can use D3 to append a new list item element, containing the text “bananas”.

    d3.select(this.refs.myList) .append("li") .text("bananas")

    Using data to create

    You can make D3 aware of your data by selecting DOM elements and attaching the data to them using .data(). D3 has a method called .enter(), which is often used for working with data. It signifies that these data elements need to be added to the DOM. Enters counterpart, .exit() , is used to signify those elements that no longer exist in the data but do exist in the DOM. We can use it to remove those elements together with remove, as in .exit().remove().

    Let’s take a look at an example.

    import React, { component } from 'react' import * as d3 from 'd3' class App extends Component { const temperatureData = [ 8, 5, 13, 9, 12 ] d3.select(this.refs.temperatures) .selectAll("h2") .data(temperatureData) .enter() .append("h2") .text("New Temperature") render( ) } export default App

    This reads “D3, select the element with reference ‘temperatures’. Then, attach temperatureData to it’s

    -elements. For the parts of data which aren’t represented in the DOM yet, append new

    -element with the text “New Temperature”.

    Wait, now it says “New temperature” over and over again! What if we want to display the actual datapoint value?

    Properties as functions

    In D3, styles, attributes and other element properties can be set using functions. Let’s refactor the code above to use a function that sets the texts of the <h2>-elements to the datapoint value they represent.

    d3.select(this.refs.temperatures) .selectAll("h2") .data(temperatureData) .enter() .append("h2") .text((datapoint) => datapoint + " degrees")

    We can use an arrow function to take the datapoint value and return the value added to “ degrees”. Functions in properties allow us to get creative with the elements. In this example from the D3 documentation, a paragraph is given a random color using a function to set the elements style property.

    d3.selectAll("p") .style("color", function() { return "hsl(" + Math.random() * 360 + ",100%,50%)"; } );

    You can also use conditionals, just as in any function. Let’s say we want to set the style of an element of our temperature list based on the data.

    d3.select(this.refs.temperatures) .selectAll("h2") .data(temperatureData) .enter() .append("h2") .text((datapoint) => `${datapoint} degrees`) .style((datapoint) => { if (datapoint > 10) { return "red" } else { return "blue" } }) 

    However, adding inline styles is a tedious job, and we would like to use classes and ids instead so that we could set the styles in our CSS. To set attributes like classes and ids, we use .attr(). The code above could be refactored to .attr("class", (datapoint) => { datapoint > 10 ? "highTemperature" : "lowTemperature" }.

    Animating with transitions

    Finally, D3 makes animating transitions easy. We could change text color to red.

    d3.select(this.ref.descr) .transition() .style("background-color", "red"); render()

    We can modify the animation to happen after 1 second using .duration(1000). We can also use functions together with transitions. For example, we can make our elements to appear in a staggered transition. The following example from the D3 documentation makes circles appear one at a time, using a delay() function that takes dataPoint and iteration as parameters, and returns the iteration multiplied by 10. Iteration refers to the position of the datapoint in the list of data.

    d3.selectAll("circle").transition() .duration(750) .delay(function(dataPoint, iteration) => iteration * 10) .attr("r", (dataPoint) => Math.sqrt(d * scale))

    Our first chart

    Let’s create a new component. Create a new file, called BarChart.js. Modify App.js to look like this.

    import React from React import BarChart from './BarChart' const App = () => { return (  ) }

    Paste the following boilerplate into BarChart.js. Call npm start to start the app.

    import React, { Component } from 'react' import * as d3 from 'd3' class BarChart extends Component { componentDidMount() { const data = [ 2, 4, 2, 6, 8 ] this.drawBarChart(data) } drawBarChart(data) {} render() { return } } export default BarChart

    We have a set of dummy data, which we pass to the drawing function as a parameter. From now on, we’ll be working inside drawBarChart(). First, select the div with the reference canvas. Inside drawBarChart(), we append a svg element inside the div we referenced. We set the svg to have a with of 600, a height of 400 and a black border. You should see this empty box appear on the page.

    const svgCanvas = d3.select(this.refs.canvas) .append(“svg”) .attr(“width”, 600) .attr(“height”, 400) .style(“border”, “1px solid black”)

    Next, we need some bars on our bar chart. We select all rect elements, or rectangles, of the svg. Then we append the data to the rectangles and use enter to step into the data. For each data in the element, we append a rectangle with a width of 40 and the height of the datapoint value multiplied by 20.

    svgCanvas.selectAll(“rect”) .data(data).enter() .append(“rect”) .attr(“width”, 40) .attr(“height”, (datapoint) => datapoint * 20) .attr(“fill”, “orange”)

    Wait, why does it look like we only have one rectangle? Since we didn’t specify where on the svg the rectangle should appear, they all piled up at 0, 0. Let’s add the x and y positions to them. Let’s also refactor the code to keep the canvas width, height and the scale of the bars in variables.

    drawBarChart(data) { const canvasHeight = 400 const canvasWidth = 600 const scale = 20 const svgCanvas = d3.select(this.refs.canvas) .append(“svg”) .attr(“width”, canvasWidth) .attr(“height”, canvasHeight) .style(“border”, “1px solid black”) svgCanvas.selectAll(“rect”) .data(data).enter() .append(“rect”) .attr(“width”, 40) .attr(“height”, (datapoint) => datapoint * scale) .attr(“fill”, “orange”) .attr(“x”, (datapoint, iteration) => iteration * 45) .attr(“y”, (datapoint) => canvasHeight — datapoint * scale) }

    Now we set the position x to the iteration multiplied by 45, which is 5 wider than the column width, leaving a small gap between the columns. The y position is a bit trickier. We set it to the canvas height minus the height of the bar, which is the datapoint value multiplied by 20. Now our chart looks like this.

    To give our bars a final touch, let’s add the data point values to the bars. We append some text elements to the svg and set their x-attribute 10 units greater than each bars starting point. We set the y-attribute to be 10 units less than the starting point of the bar.

    svgCanvas.selectAll(“text”) .data(data).enter() .append(“text”) .attr(“x”, (dataPoint, i) => i * 45 + 10) .attr(“y”, (dataPoint, i) => canvasHeight - dataPoint * scale - 10) .text(dataPoint => dataPoint)

    Now the texts sit just above the bars. You can continue working with the chart, adding styles (using .attr("class", "bar") ) and adding a CSS file. You can also add an axis to the chart and add a tooltip when mousing over the bar.

    Get creative and enjoy!

    Working with D3 can seem difficult in the beginning. Once you get the basics down it becomes a powerful tool to express and visualize data. I recommend using D3 over picking a ready-made chart library, since it allows for more personal and modifiable pieces.

    Finally, learning D3 is also a good way of getting fluent at traversing and manipulating the DOM. Understanding the DOM is often a quality interviewers look for in front end developers.

    Resources:

    D3 Tutorials suggested by D3

    React tutorial from the React documentation