6.2 KiB
D3.js
Basics
Selection
d3.select('#some-id') //like document.querySelector()
d3.selectAll('.some-class') //like document.querySelectorAll()
d3.select('main').selectAll('span'); //can chain to select ancestors
.style()
d3.select('div').style('color', 'orange'); //sets the style for an element
d3.select('div').style('color', 'orange').style('font-size': '20px'); //will return the selection for chaining
.attr()
d3.select('div').attr('anExampleAttribute', 'someValue'); //adds/changes an attribute on an selection
.classed()
d3.selectAll('.house').classed('house'); // returns true if all elements in selection contain the chosen class
d3.selectAll('div').classed('frog', true); //adds the class and returns the selection
d3.selectAll('div').classed('frog', false); //removes the class and returns the selection
.append()
d3.selectAll('div').append('span'); //append html to a selection and return appended element
.html()
d3.selectAll('div').html('<span>hi</span>'); //change the inner html of an element
.text()
d3.selectAll('div').text('hi'); //set the content of the selection to the exact text (escapes html)
AJAX
Named based off of what kind of data they accept
d3.json('path', function(error, data){});
d3.csv('path', function(error, data){});
d3.tsv('path', function(error, data){});
d3.xml('path', function(error, data){});
d3.html('path', function(error, data){});
d3.text('path', function(error, data){});
Data binding
d3.selectAll('circle')//make a "ghost call" to all circles, even if there are none already
.data(dataArray) //joins each element in dataArray to an element in the selection
.enter() //returns the sub section of dataArray that has not been matched with DOM elements
.append('circle'); //creates a DOM element for each of the remaining dataArray elements
once data has been bound to elements, you can call something like:
d3.selectAll('circle').attr('r', function(d,i){ //d is data for the current element, i is the index of that element in the array
//callback will be executed for each DOM element
//return value is how each value will be set
return d.value * 2 //takes value property of d (data), multiplies it by two and sets the radius to that
})
Can remove elements:
d3.selectAll('circle')//make a "ghost call" to all circles, even if there are none already
.data(dataArray) //joins each element in dataArray to an element in the selection
.exit() //returns the sub section of DOM elements that has not been matched with dataArray elements
.remove(); //removes those elements
Linear Scale
A scale will map a data value to a visual value.
-
Create a scale. There are many types. Here we'll use a linear scale
var yScale = d3.scaleLinear(); -
Set up a visual range
yScale.range([height,0]); -
Add the domain
yScale.domain(yDomain); -
Can check range and domain after initialization
yScale.range(); yScale.domain(); -
Can now pass a data value into the scale to get a visual value
yScale(361); //returns the visual value that maps to this data value -
Can go the opposite way
yScale.invert(800); //returns the data value that maps to this visual value -
If data min/max of a data set (called the "domain") are not found, you can find them:
var yMax = d3.max(data, function(element){ return parseInt(element.TMAX); }) var yMin = d3.min(data, function(element){ return parseInt(element.TMAX); }) var yDomain = [yMin, yMax];- Can combine this into one call if max/min come from same element:
var yDomain = d3.extent(data, function(element){ return parseInt(element.TMAX); });
Time Scale
-
Create the scale
var xScale = d3.scaleTime(); -
Set up the visual range
xScale.range([0, width]); -
Set up the time range
xScale.domain([new Date('2016-1-1'), new Date('2017-1-1')]);
Dealing with alternate date formats
Date formatting options: https://github.com/d3/d3-time-format#locale_format
To parse an alternate format into a date object
var parseTime = d3.timeParse("%Y%m%d");
parseTime('20160101') //returns a date object
To create an alternately formated string from a date object
var formatTime = d3.timeFormat("%Y%m%d");
formatTime(new Date()); //returns a string in the above format
Axes
var leftAxis = d3.axisLeft(yScale); //create a left axis based on the yScale
d3.select('svg')
.append('g') //append a group element
.call(leftAxis); //apply the axis to it
Different types of axes: https://github.com/d3/d3-axis#axisTop
Events
select.on('mouseenter', function(data, index){
d3.select(this); //select just element that was hovered
console.log(d3.event); //the event object
})
click, mouseenter and mouseleave are common
use d3.event.stopPropagation(); when events conflict
Behaviors
Dragging
var drag = d3.behavior.drag()
.on('dragstart', dragStart)
.on('drag', drag)
.on('dragend', dragEnd);
//....
dotsGroup.call(drag);
//....
function dragStart(d){ //d is the data for the dragged object
d3.select(this); //the visual object
d3.event.x; //x position of cursor
d3.event.y; //y position of cursor
}
Zooming
//generator for a behavior
//scale from 1 - 10
//.on function says, when there's an event of type 'zoom', call the 'zoomed' function. Could be any event
var zoom = d3.behavior.zoom().scaleExtent([1,10]).on('zoom', zoomed);
var svg = d3.select('#viz-wrapper').append('svg').call(zoom);
function zoomed(){
console.log(d3.event.translate);//get mouse position
console.log(d3.event.scale);//bounded by 1,10 as set up above
viz.attr('transform', 'translate(' + d3.event.translate + ')' + 'scale(' + d3.event.scale + ')');
}
You can use the xScale.invert and yScale.invert to get data from d3.event.x and d3.event.y