Scatter plot
We add a tooltip to our scatter plot. Along the way, we learn about d3.timeFormat and learn a great trick for making our tooltips feel smoother, using voronoi.
Let's level up and add tooltips to a scatter plot.

We want a tooltip to give us more information when we hover over a point in our chart.
At the bottom of the file, we'll select all of our <circle/>
elements and add a mousenter
and a mouseleave
event.
bounds.selectAll("circle")
.on("mouseenter", onMouseEnter)
.on("mouseleave", onMouseLeave)
We know that we'll need to modify our #tooltip
element, so let's assign that to a variable. Let's also define our onMouseEnter()
and onMouseLeave()
functions.
const tooltip = d3.select("#tooltip")
function onMouseEnter(event, d) {
}
function onMouseLeave() {
}
Let's first fill out our onMouseEnter()
function. We want to display two values:
the metric on our x axis (dew point), and
the metric on our y axis (humidity).
For both metrics, we'll want to define a string formatter using d3.format()
. Then we'll use that formatter to set the text value of the relevant <span/>
in our tooltip.
function onMouseEnter(event, d) {
const formatHumidity = d3.format(".2f")
tooltip.select("#humidity")
.text(formatHumidity(yAccessor(d)))
const formatDewPoint = d3.format(".2f")
tooltip.select("#dew-point")
.text(formatDewPoint(xAccessor(d)))
}
Let's add an extra bit of information at the bottom of this function — users will probably want to know the date of the hovered point. Our data point's date is formatted as a string, but not in a very human-readable format (for example, "2019-01-01"). Let's use d3.timeParse
to turn that string into a date that we can re-format.
const dateParser = d3.timeParse("%Y-%m-%d")
console.log(dateParser(d.date))
Now we need to turn our date object into a friendlier string. The d3-time-format module can help us out here! d3.timeFormat()
will take a date formatter string and return a formatter function.
The date formatter string uses the same syntax as d3.timeParse
— it follows four rules:
it will return the string verbatim, other than specific directives,
these directives contain a percent sign and a letter,
usually the letter in a directive has two formats: lowercase (abbreviated) and uppercase (full), and
a dash (
-
) between the percent sign and the letter prevents padding of numbers.
For example, d3.timeFormat("%Y")(new Date())
will return the current year.
Let's learn a few handy directives:
%Y
: the full year%y
: the last two digits of the year%m
: the padded month (eg. "01")%-m
: the non-padded month (eg. "1")%B
: the full month name%b
: the abbreviated month name%A
: the full weekday name%a
: the abbreviated weekday name%d
: the day of the month
See the full list of directives at https://github.com/d3/d3-time-format.
Now, let's create a formatter string that prints out a friendly date.
const dateParser = d3.timeParse("%Y-%m-%d")
const formatDate = d3.timeFormat("%B %A %-d, %Y")
console.log(formatDate(dateParser(d.date)))
Much better! Let's plug that in to our tooltip.
const dateParser = d3.timeParse("%Y-%m-%d")
const formatDate = d3.timeFormat("%B %A %-d, %Y")
tooltip.select("#date")
.text(formatDate(dateParser(d.date)))
Next, we'll grab the x
and y
value of our dot , offset by the top and left margins.
const x = xScale(xAccessor(d))
+ dimensions.margin.left
const y = yScale(yAccessor(d))
+ dimensions.margin.top
Just like with our bars, we'll use calc()
to add these values to the percentage offsets needed to shift the tooltip. Remember, this is necessary so that we're positioning its arrow, not the top left corner.
tooltip.style("transform", `translate(`
+ `calc( -50% + ${x}px),`
+ `calc(-100% + ${y}px)`
+ `)`)
Lastly, we'll make our tooltip visible and hide it when we mouse out of our dot.
tooltip.style("opacity", 1)
}
function onMouseLeave() {
tooltip.style("opacity", 0)
}
Nice! Adding a tooltip was much faster the second time around, wasn't it?
This page is a preview of Fullstack D3 Masterclass