Exercise 3 - Single Line-Chart with Tooltip
Step 1: Create a single line chart
After completing excercise 1, you should be able to create a single line chart in the presented way:
- Create index.html
- Create index.js and import into index.html
- Create a function for plotting the line chart
- Prepare the chart canvas and load data
- Data preparation
- Add axis to the chart
- Add the line to the chart
Step 2: Prepare the tooltip
To display a tooltip (as shown in the chart to the left), we need a circle and a text that states the value.
- Like adding a path or grouping seen so far in the code, you can add a circle to the svg element:
var focus = svg .append('g') .append('circle') .attr("stroke", "black") .attr('r', 8.5) - in the same way, a text can be added:
var focusText = svg .append('g') .append('text') .attr("text-anchor", "left") .attr("alignment-baseline", "middle")
Step 3: Prepare mouse-tracking
To be able to track the position of the mouse on the chart, we need a separate element that catches the mousemovements. We add a rectangle and add a listener to mouse movements.
svg.append("rect") .style("fill", "none") .style("pointer-events", "all") .attr("width", width) .attr("height", height) //here the function mousemove is called when the mouse is moved on the rect element .on("mousemove", function(event){ mousemove(event)})
Step 4: Track the mouse and place the tooltip
To place the tooltip at the right place on the line, we need the coordinates of mouse pointer. To be more precise, we need a value for the x-axis that is present in the data (time) and is
closest to where the mouse pointer is.
- First, we need a little helper function, that will give us the closest existing x-value based on the mouse pointer's position. Thankfully, D3 has a built-in function for that:
var bisect = d3.bisector(function(d) {return d.time}).left; - With the help of this function and the function 'd3.pointer' (relates to the coordinates of the mouse) we can define a function to place the tooltip:
function mousemove(event) { //get the current mouse position -> returns an array [x,y] var mouse_position = d3.pointer(event, svg.node()); var x0 = xScale.invert(mouse_position[0]); //get the nearest x-value with our help function var i = bisect(data['datapoints'], x0, 1); //with the existing x-value, we can select the correct datapoint var selectedData = data['datapoints'][i]; //place the circle on the chart line focus .attr("cx", xScale(selectedData.time)) .attr("cy", yScale(selectedData.actPressure)); //place the text 15 pixels to the right of the circle focusText .html("y:" + selectedData.actPressure) .attr("x", xScale(selectedData.time)+15) .attr("y", yScale(selectedData.actPressure)) }
Step 5: Now it is your turn!
After you have followed the steps so far, the chart does not look exactly the same as shown at the left side. Try to achieve the same look, especially try to:
- Style the circle in a way, that it has no fill
- The circle (and text) of the tooltip is visible from the beginning, change it so they are invisible in the binning
- After you have done 2., you will need two functions that will set the tooltip visible by entering the area and invisble by leaving.
You also need to bind these functions to the corresponding events on the rect element - similar to what we have done for the move event.