You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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.

  1. Create a scale. There are many types. Here we'll use a linear scale

    var yScale = d3.scaleLinear();
    
  2. Set up a visual range

    yScale.range([height,0]);
    
  3. Add the domain

    yScale.domain(yDomain);
    
  4. Can check range and domain after initialization

    yScale.range();
    yScale.domain();
    
  5. 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
    
  6. Can go the opposite way

    yScale.invert(800); //returns the data value that maps to this visual value
    
  7. 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

  1. Create the scale

    var xScale = d3.scaleTime();
    
  2. Set up the visual range

    xScale.range([0, width]);
    
  3. 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.sourceEvent.stopPropagation(); when events conflict

Behaviors

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 + ')');
}

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
}

You can use the xScale.invert and yScale.invert to get data from d3.event.x and d3.event.y

Basic Layouts