For the fourth technical progress check-in, you'll be using the D3 framework to create an interactive multi-series line chart. In doing so, you'll demonstrate a strong familiarity with the following skills:
- Advanced knowledge of the data-join
- Ability to use functions to compute
path
elements for lines - Assigning
mouseover
andmouseout
events to add interactivity to your chart
Complete example of visualization.
This assignment uses a dataset from UN Data that shows carbon dioxide emissions between 1990 and 2014 for multiple countries (data here).
(From UN Data): the carbon dioxide emissions are given as units of:
Carbon Dioxide (CO2) Emissions without Land Use, Land-Use Change and Forestry (LULUCF), in kilotonne CO2 equivalent)
Instructions are included below, as well as in-line in your js/script.js
file. In order to focus on the data-join and hover events, much of the code has already been written for you.
- Use the
d3.line()
function to create a functionline
for drawing yourpath
elements. You'll need to leverage the.x
and.y
methods to describe how to compute the path from your data
In this section, you'll carefully perform a data-join. As demonstrated in class, you'll want to create the following effect:
- Entering lines transition in from left to right
- Updating elements update their position in a smooth motion
- Exiting elements transition out from right to left
To accomplish this, I suggest you set attributes separately for entering/updating/exiting elements (i.e., no merge
). However, I suggest you first get your path
elements on the screen (entering), move on to the hover section, then come back an put your finishing touches on the transitions.
- Perform a data-join between a selection of
path
elements in yourg
and your data that you pass into thedraw
function - For each new (entering) element, append a
path
element to yourg
- Use your
line
function to set thed
property of your path. This will describe how to draw it on the screen - Set your
fill
tonone
and stroke-width to1.5
(these are path attributes) - To create your transition, you'll need to set your
stroke-dasharray
toLENGTH LENGTH
(with a space in-between), whereLENGTH
is the length of each path. To get each path's length (in pixels), you can use the following syntax inside a function:d3.select(this).node().getTotalLength()
- Set your
stroke-dashoffset
to the total length of each path (see last step). This essentially creates a dashed line whose dash length (stroke-dasharray
) is the length of your line. Then, you shift it (stroke-dashoffset
) by the length of your path so that you begin with an empty dash.
- Set your
stroke-dasharray
tonone
- Transition your
d
attribute using yourline
function to update the position appropriately - Update the
stroke
of each path
- To transition right to left, transition your
stroke-dashoffset
to-LENGTH
(negative value of the length of each path) - Reset your
stroke-dasharray
toLENGTH LENGTH
Your drawHover
function will take in a year
as a parameter, and then leverage a data-join to place circles and text over the appropriate locations on the graph. This requires that you filter down your data to the closest year to the hover (using d3.bisect
), then add/remove circles from the screen.
- Use
d3.bisector
to define a function (bisector
) that can find the closest datapoint to your year:var bisector = d3.bisector(function(d, x) { return +d.year - x; }).left;
- Get hover data by using the
bisector
function to find the nearest data-point to your hover event. You'll need to:- Iterate through your
selectedData
array - Sort the
values
of each country by+year
- Return the element closest to your
year
variable. Hint:dat.values[bisector(dat.values, year)]
- Iterate through your
Once you have your data, you can simply do the following to add hover:
- Do a data-join (enter, update, exit) to draw
circle
elements over your lines - Do a data-join (enter, update, exit) to draw
text
elements over your lines
You'll need to assign event listeners to your overlay
element to listen to your hovers:
- On mousemove, detect the mouse location (
d3.mouse(this)
)and usexScale.invert
to get the data value that corresponds to the pixel value - On mouseout, remove all
circle
andtext
elements from theg
element