Efficient tooltip positioning in D3.js chart

8th August, 2017 - 2 min. read - in Tutorials - Go to Index

I was just scribbling on paper without a specific goal. Suddenly, a little ah-ha moment brought me in a little exploration.


The proof-of-concept

Apparently, I’m all about Proof-Of-Concept these days.

This time is about positioning a graphic element (let’s say, a tooltip) next to the mouse but using the most efficient area in a given canvas in order to avoid the element to be cut by the boundary of the canvas.


I didn’t make any research on the topic, I bet I wouldn’t be astonished if there were, at least, a couple of Ph.D. out there on efficient tooltips positioning algorithms.
I don’t know whether this technique has been already used somewhere. In this case, I would love to hear more about them.

The rules

They are simple and can be outlined as the following:

A very efficient way to show how it works and what’s going on behind the scene might be this progressive visualization:


Here the relevant javascript code that uses a couple of essential native functions to accomplish this feature. It was extrapolated by a D3.js script but it can be adapted to other contexts quite easily. This script requires to be within a mousemove listener:

// finding the longest line
var maxL
var maxV = 0
lines.each(function (d, i) {
  if (d.l >= maxV) {
    maxL = this
    maxV = d.l

// get the final point
var l = maxL.getTotalLength()
var p = maxL.getPointAtLength(l - 60)

// position the element
legend.attr('transform', `translate(${p.x}, ${p.y})`)

Here the interactive version (click to toggle the chart visibility and… desktop only):


I don’t know whether I’m going to use this technique in the future. Nevertheless, it’s always good to figure out what’s going on behind the curtain, it can’t hurt.

PS: I’ve also learned something on SVG 2; the getTotalLength() function will be deprecated on some SVG element (i.e. line, text), this is why my implementation uses path instead line elements.

Source code here.

Want to ask something? Drop me a line!

Not ready to talk? Follow me on Twitter.

Spotted a typo or (likely) a grammar error? Send a pull request.