D3
D3.js, short for Data-Driven Documents, is a JS Package for manipulating documents based on data and is well suited to interactive graphics.
In an HTML file, we should add the link to D3 in the <head>
element. And then write JavaScript in the <body>
.
<head>
<script src="https://d3js.org/d3.v7.js"></script>
</head>
<body>
<svg width="500" height="300"> <!-- some SVG -->
<rect x="20" y="20" width="460" height="260" fill="lightblue"></rect>
<circle cx="200" cy="75" r="20" fill="blue"></circle>
<ellipse cx="175" cy="100" rx="45" ry="30" fill="green"></ellipse>
<text x="150" y="200">(150, 200)</text>
<line x1="250" y1="150" x2="300" y2="200" stroke="red" stroke-width="5"></line>
</svg>
<script>
// JavaScript / D3 will go here
</script>
</body>
D3 helps us conveniently interact with the DOM. Some basic commands (try them in the console of Developer Tools):
d3.select("circle").attr("cx", "200");
d3.select("circle").attr("r", "30");
d3.select("circle").attr("fill", "red");
- Effects of commands executed in the console will be gone after a refresh of the page.
As we can see, a basic D3 statement is a combination chain of D3 methods. Another example:
d3.select("svg").select("circle").transition().duration(2000).attr("r", "50");
What the above example does is
- select the first element targeted by CSS Selector
svg circle
- change the value of attribute
r
of the selected element to"50"
- add a transition of 2000ms to the change
Select Elements
Selecting elements in DOM is the same as targeting elements using CSS Selector.
.select(selector)
selects the first element targeted byselector
.selectAll(selector)
selects all elements targeted byselector
For a composite selector, for example, svg#id1 circle.container
, we can use
- one
.select()
:.select("svg#id1 circle.container")
; or chaining.select()
s:.select("svg").select("#id1").select("circle").select(".container")
- The above line is wrong: chaining selects select inside the previous selected element. So
.select("svg").select("#id1")
returns empty.
We can store the selected elements in a variable/constant for future reference:
const selection = d3.selectAll("circle")
- Note that once a selection is stored to a variable, even if the elements in the selection are removed from the DOM, the selection contains those elements.
{ #qahtei}
Change Attributes, Style, and Content
-
.attr(attrName, attrValue)
changes or sets the attributeattr
of the element toattrValue
-
.style(styleName, styleValue)
changes or sets the stylestyleName
of the element tostyleValue
style
is just a special attribute; thus.style(styleName, value)
is just shorthand for.attr("style", "styleName: value;")
- if there is a style rule and an attribute having the same name, the style rule takes precedence
-
.text("new content")
changes or sets the tag text content -
to see the value of an attribute/style rule/text content, just leave the argument empty
With JS Functions, especially JS Arrow Functions, we can easily modify the values of attributes/styles/content based on the original values.
- It is actually not easy to get original values! One way is to use
this.getAttribute()
. However,this
is different in a JS Arrow Function and a normal function. To make this work, we should use a normal function.
Add and Remove Elements
-
.append(element)
adds an element inside the selected element, as the last child- We can directly give the newly added element attributes, styles, and content using methods in #Change Attributes, Style, and Content
d3.select('svg').append('circle').attr('cx', '100').attr('r','30')
- We can directly give the newly added element attributes, styles, and content using methods in #Change Attributes, Style, and Content
-
.insert(type[, before])
adds an element inside the selected element, before the childbefore
- If
before
is not specified,.insert()
=.append()
- Use CSS Selector#Adjacent Sibling Selector
before + *
, the element is inserted after the childbefore
- If
-
After
.append()
or.insert()
, the selection will be the new element. -
.remove()
removes the selected element- If the selector targets multiple elements,
.select(selector).remove()
will only remove the first element - Use
.selectAll(selector).remove()
to remove all the elements targeted byselector
- If the selector targets multiple elements,
D3 Bind Data
Data Function
D3 is powerful for manipulating documents based on data. Now we've learned how to bind data to elements; then we can manipulate these elements based on their data.
All the DOM manipulation methods introduced in previous sections, such as .attr()
, .style()
, .text()
, .append()
, etc., not only can take in a constant value, but also accepts a function as a parameter. This function is a function of data. The method will call the function using the bound data. To be exact, these parameters will be passed to the function
- first argument
d
: data bound to the element - second argument
i
: index of the element
- Note that the selection will also be passed to the function as
this
Then we can easily manipulate the elements based on their data using JS Arrow Functions as the functions of data. For example, to set the x-position of a circle to its data value:
d3.select("circle").attr("cx", d => d)
// This is short for
d3.select("circle").attr("cx", function(d) {return d})