- From: Gavin Kistner <phrogz@me.com>
- Date: Wed, 09 Nov 2011 17:18:59 +0000 (GMT)
- To: Gavin Kistner <phrogz@me.com>
- Cc: www-svg@w3.org
- Message-id: <9018756d-cba8-6f4a-fc3f-ffe1c175cc2f@me.com>
On Nov 07, 2011, at 09:03 PM, Gavin Kistner <phrogz@me.com> wrote:
My question: is there a better way to accomplish my goal of getting SVG elements coordinated with embedded HTML elements?
While writing a workaround for the Webkit bug[1] (transforming points from screen to foreignObject space) I realized that there's no point in round-tripping through screen space for compliant browsers. It's easier to just use foreignObject.getTransformToElement( otherSVGElement ).
I now have a solution and test page[2] that works in Firefox and mostly works in Webkit (with the caveat that rotated/skewed foreignObjects don't give the right results, since getBoundingClientRect() gives the screen-space bounding box that no longer touches the corners of the objects).
[1] https://bugs.webkit.org/show_bug.cgi?id=71819
[2] http://phrogz.net/SVG/html_location_in_svg_2.svg
For archival posterity, here's my code (including Webkit workaround):
// Find the four corners (nw/ne/sw/se) of any HTML element embedded in
// an SVG document, transformed into the coordinates of an arbitrary SVG
// element in the document.
//
// Usage:
// var coords = svgCoordsForHTMLElement( htmlEl, svgEl );
// svgEl may be null to use the root SVG documentElement
var svgCoordsForHTMLElement = (function(svg){
var svgNS= svg.namespaceURI, xhtmlNS = "http://www.w3.org/1999/xhtml";
var doc = svg.ownerDocument;
var wrap = svg.appendChild(doc.createElementNS(svgNS,'foreignObject'));
var body = wrap.appendChild(doc.createElementNS(xhtmlNS,'body'));
if (typeof body.getBoundingClientRect != 'function') return;
wrap.setAttribute('x',100);
var rectIsInForeignObject = body.getBoundingClientRect().left == 0;
svg.removeChild(wrap);
var pt = svg.createSVGPoint();
return function svgCoordsForHTMLElement(htmlEl,svgEl){
if (!svgEl) svgEl = htmlEl.ownerDocument.documentElement;
var coords = {};
for (var o=htmlEl;o&&o.tagName!='foreignObject';o=o.parentNode){}
var transform = wrap.getTransformToElement(svgEl);
if (!rectIsInForeignObject){
// Workaround https://bugs.webkit.org/show_bug.cgi?id=71819
transform = wrap.getScreenCTM().inverse().multiply(transform);
}
var rect = htmlEl.getBoundingClientRect();
pt.x = rect.left; pt.y = rect.top;
coords.nw = pt.matrixTransform(transform);
pt.y = rect.bottom;
coords.sw = pt.matrixTransform(transform);
pt.x = rect.right;
coords.se = pt.matrixTransform(transform);
pt.y = rect.top;
coords.ne = pt.matrixTransform(transform);
return coords;
};
})(document.documentElement);
Received on Wednesday, 9 November 2011 17:20:27 UTC