How do you convert screen coordinates to document space in a scaled SVG?
If you call the function getScreenCTM()
on the SVG element, it will return the transform matrix used to convert document coordinates to screen coordinates. You want the transform matrix for the other direction, so call inverse()
on the matrix object.
var transform = svg.getScreenCTM().inverse();
Now you can transform a point object to do the final conversion:
pt = pt.matrixTransform(transform);
Working demo here
var x = document.getElementById("x"),
y = document.getElementById("y"),
svg = document.querySelector("svg");
svg.addEventListener("mousemove", function(evt) {
var pt = svg.createSVGPoint();
pt.x = evt.pageX;
pt.y = evt.pageY;
pt = pt.matrixTransform(svg.getScreenCTM().inverse());
x.innerHTML = pt.x;
y.innerHTML = pt.y;
}, false);
#container {
width: 200px;
height: 200px;
}
div {
float: left;
margin-left: 1em;
}
<div id="container">
<svg version="1.0" viewbox="0 0 100 100">
<rect x="0" y="0" width="100" height="100" fill="blue"/>
</svg>
</div>
<div>
x = <span id="x"></span><br/>
y = <span id="y"></span>
</div>
If the above version (using pageX/Y) doesn't work for you, try this version instead.
var x = document.getElementById("x"),
y = document.getElementById("y"),
svg = document.querySelector("svg");
svg.addEventListener("mousemove", function(evt) {
var pt = svg.createSVGPoint();
pt.x = evt.clientX;
pt.y = evt.clientY;
pt = pt.matrixTransform(evt.target.getScreenCTM().inverse());
x.innerHTML = pt.x;
y.innerHTML = pt.y;
}, false);
#container {
width: 200px;
height: 200px;
}
div {
float: left;
margin-left: 1em;
}
<div id="container">
<svg version="1.0" viewbox="0 0 100 100">
<rect x="0" y="0" width="100" height="100" fill="blue"/>
</svg>
</div>
<div>
x = <span id="x"></span><br/>
y = <span id="y"></span>
</div>
See http://msdn.microsoft.com/en-us/library/hh535760%28v=vs.85%29.aspx It's my sample code. For this usage, getScreenCTM method is very useful.
<svg viewBox="0 0 300 300" onload="
var c = document.getElementById('c');
var cx = c.cx.baseVal;
var cy = c.cy.baseVal;
var svg = this;
var point = svg.createSVGPoint();
svg.onmousemove = function(e){
point.x = e.clientX;
point.y = e.clientY;
var ctm = c.getScreenCTM();
var inverse = ctm.inverse();
var p = point.matrixTransform(inverse);
cx.value = p.x;
cy.value = p.y;
};
">
<rect width="100%" height="100%" fill="yellow"/>
<circle id="c" r="10" fill="blue"/>
</svg>