de-transform — CSS transform coordinate correction
Canvas and charting libraries report wrong mouse event coordinates when CSS transforms are on parent elements. Built a JavaScript module that mathematically inverts the full transform stack to give correct coordinates.
github.com/siddharthapaul001/de-transform · Solves IE9+ cross-browser
The problem
JavaScript canvas and SVG charting libraries — including FusionCharts — rely on mouse event coordinates to detect which element a user clicked or hovered over. The browser provides these as clientX/clientY relative to the viewport.
When a CSS transform (rotate, scale, perspective, matrix3d) is applied to the chart container or any of its parent elements, the coordinates the library receives are in the transformed space, not the element's own space. The result: click detection is wrong. Hovering over a data point selects a different one. Drag operations move in the wrong direction. The further the transform, the more broken the interaction.
This is a fundamental issue with how the browser's coordinate system interacts with CSS transforms — no charting library could handle it without external help.
What I built
Built a standalone JavaScript module — de-transform — with three APIs:
getOriCoordinate(element, event, useOffset) — the core function. Takes an HTML element and a MouseEvent and returns the correct coordinates relative to that element, after mathematically cancelling all CSS transforms on it and its parents. Two approaches depending on browser support (see architecture).
applyTransformAtPoint(point, matrix, origin) — the raw math primitive. Applies a CSS matrix() or matrix3d() transform to any {x, y} or {x, y, z} point at a given transform-origin. Handles both 2D (6-value matrix) and 3D (16-value matrix3d). Used internally by getOriCoordinate.
getOriDragDistance(element, event, state, useOffset) — wraps getOriCoordinate across a drag sequence (start → move → end) to return correct dx/dy deltas even when the element is inside a rotated or scaled container.
Approaches considered
Architecture
getOriCoordinate (matrix-inverse path): traverse DOM from element → BODY → collect elements with non-identity CSS transforms → read their computed matrix() / matrix3d() and transform-origin → build inverse transform stack → apply inverse chain to clientX/clientY top-down → return coordinate in element's own space.
applyTransformAtPoint: parse CSS matrix string → translate point by subtracting origin → apply 2×2 (2D) or 4×4 (3D) matrix multiplication → translate back by adding origin → return transformed point.
getOriDragDistance: on 'start', store getOriCoordinate result; on 'move', subtract stored start from current getOriCoordinate result; on 'end', clear state.
Result
Published as an open source library at github.com/siddharthapaul001/de-transform. Built specifically to solve a real production problem encountered at FusionCharts when charts are embedded inside transformed containers. Supports IE9+. Handles nested 2D transforms on any number of parent elements, and single CSS 3D transforms (perspective + rotateX/Y/Z combinations).