Rendering Tooltips at Mouse Coordinates in SVG

Vector charting libraries achieve precise tooltip positioning by translating raw screen-space mouse events into the scalable coordinate system of an SVG canvas. Because an SVG can scale, stretch, and transform independently of the browser window’s pixel grid, libraries like D3.js, Highcharts, and Chart.js use native DOM transformation matrices, bounding box math, and spatial indexers to bridge the gap between viewport pixel coordinates and internal chart data coordinates.

The Coordinate Space Disconnect

When a user moves a mouse over an SVG, the browser’s pointermove or mousemove event reports position coordinates relative to the browser viewport (clientX, clientY) or the document (pageX, pageY).

However, SVG elements exist within a localized user space defined by the <svg> element’s viewBox attribute. If an SVG has a viewBox="0 0 1000 500" but is rendered inside a responsive CSS container measuring 400px by 200px, one unit in the SVG coordinate space does not equal one physical screen pixel. Placing a tooltip requires resolving this scale and offset mismatch.

Method 1: Transforming Coordinates via the Screen CTM

The most mathematically robust way to locate the mouse inside an SVG is using the SVG Current Transformation Matrix (CTM). Modern charting engines map screen pixels back to SVG coordinates using the following DOM methods:

  1. Create an SVG Point: The library initializes a reusable SVG point object via svg.createSVGPoint().

  2. Assign Screen Coordinates: The point’s x and y properties are set to event.clientX and event.clientY.

  3. Invert the Matrix: The library retrieves the screen transformation matrix using svg.getScreenCTM(), which accounts for all CSS transforms, scrolling, and aspect-ratio scaling applied to the SVG.

  4. Apply Inverse Transformation: The point is multiplied by the inverted matrix:

    const pt = svg.createSVGPoint();
    pt.x = event.clientX;
    pt.y = event.clientY;
    const svgCoords = pt.matrixTransform(svg.getScreenCTM().inverse());

This produces the exact x and y coordinates inside the SVG’s internal coordinate grid, allowing in-SVG tooltip elements (<g>, <rect>, <text>) to be positioned accurately.

Method 2: HTML Overlay via Bounding Rectangles

Many libraries render tooltips as standard HTML <div> elements layered over the chart rather than SVG elements. This avoids SVG z-index limitations and simplifies CSS styling.

For HTML-based tooltips, the coordinate transformation is reversed:

  1. The library queries the container’s position using svg.getBoundingClientRect().

  2. The tooltip position is calculated relative to the container:

    const rect = svg.getBoundingClientRect();
    const tooltipX = event.clientX - rect.left;
    const tooltipY = event.clientY - rect.top;
  3. The tooltip element is positioned using CSS transform: translate3d(x, y, 0) or top/left properties.

Hit Testing and Snapping to Data Points

Beyond raw mouse tracking, charts often snap tooltips to the nearest data point (such as a line node or bar segment) rather than floating freely under the cursor: