d3 - kylecoberly/knowledge GitHub Wiki
Notes
- D3 just does the math and gives you a declarative DOM API. You have to use something like HTML or SVG to actually draw the visualization
- Much like jQuery, you start d3 chains with a selection. The methods chain together, each step returning a modified version of the selection
- You can set attributes and style properties with constant values, or with computed properties by passing in functions
- You can save selections part way through a chain to fork them or make things more clear
- Binding data has 3 phases
-
Enter, which is when there is new elements being created because there are more data points than there are elements
-
Update, which is done to elements that already exist
-
Exit, which is when there are more elements than data points
-
- You can make linear, ordinal and other scales to transform a data point to whatever scale it's being presented at. You set the domain (data input) and range (chart output) of the scale, and then use the resulting function to scale data to your chart size.
- You can animate transitions with
transition(),delay(), andduration() - You set the style of nodes with
.style(), and the attributes of nodes with.attr() - All SVGs are absolutely positioned from the top left
Flow
- Start by selecting DOM elements. You will likely be selecting DOM elements that don't exist yet.
- Then bind data to your selected elements. It will attempt to make a 1:1 correspondance with every DOM element that's been selected.
- A data binding returns a selector with all of the elements it was able to match to data points, plus it allows the
.enter()and.exit()methods
- When there are more data points than matching elements, the
.enter()method allows you to create them by giving you placeholder DOM nodes. - When there are more matching elements than data points, the
.exit()method allows you to work with the excess DOM nodes.
Selections
- Use
.select()or.selectAll() - Subsequent selections happen inside previous ones
- Can filter a selection with
.filter() - Merge multiple collections with
old.merge(new) - Can create a new element that's not already in the DOM with
.create()
Data Binding
- Bind data to a selection with
.data() - Match data items to a key by giving it a second argument:
.data(data, d => d[0]) - Instead of separate
.enter()and.exit(), you can use.join():
d3.selectAll("circle")
.data(data)
.join(
enter => enter.append("circle"),
update => update.append("circle"),
exit => exit.append("circle"),
)
You can also use it to replace .enter().append():
d3.selectAll("circle")
.data(data)
.join("circle")
DOM Nodes
- Append with
.append(item) - Prepend with
.insert(item, itemToPrepend) - Remove with
.remove() - Set and get attributes with
.attr()- Setter will also take a function, called with
d,index, andnodes
- Setter will also take a function, called with
- Set and get styles with
.style() - Set and get non-attribute properties (like
checked) with.property() - Selectively add classes with
.classed(classNames, addOrRemoveBoolean) - Set text with
.text() - Set
.innerHTMLwith.html() - Set the data with
.datum() - Sort with
.sort(comparator) - Apply a function to every element with
.call(someFunction, arguments)
Scales
const scaleX = d3.scaleLinear()
.domain(d3.extent(data, d => d.x)) // Range of data
.range(0, height) // Range of display
.nice()
d3.extent()takes an array and returns an array with the highest and lowest value..nice()rounds the values
Lines
const line = d3.line()
.x(d => scaleX(d.x))
.y(d => scaleY(d.y))
d3.select("#some-svg-g")
.append("path")
.attr("fill", "none")
.attr("stroke", "red")
.attr("d", linemaker(data))
Curves
const line = d3.line()
.curve(d3.curveNatural)
.x()
.y()
Axes
svg.append("g")
.call(d3.axisBottom(scaleX))
.attr("transform", `translate(${width},0)`)
svg.append("g")
.call(d3.axisLeft(scaleY))
.attr("transform", `translate(${width},0)`)
Events
d3.selectAll("li")
.data(data)
.enter()
.append("li")
.text(d => d)
.on("click", (d, index) => {
// Whatever
})
- In the handler,
eventis the DOM event,dis the data,thisis the DOM element.thisbinding isn't magicked over, you can used3.event.targetin an arrow function. .on("click.someLabel", whatever)can be used to attach multiple listeners for the same event.on("click.someLabel focus", whatever)can be used to attach multiple listeners for different eventsd3.mouse(someElement)returns the[x, y]relative tosomeElement- Add built-in event handlers (like drag/drop) with behavior components:
drag(d3.selectAll("some-selector"))
.call(
d3.drag()
.on("start", whatever)
.on("drag", whatever)
.on("end", whatever)
)
Animations
d3.select(this)
.transition()
.duration(2000)
.style("color", "blue")
.transition()tweens the values.delay().ease()applies an easing function- Transitions can be chained