Координаты HTML-элементов foreignObject в пространстве SVG - PullRequest
2 голосов
/ 07 ноября 2011

У меня есть файл SVG с таблицей XHTML. Я хочу соединить части таблицы с рисунком SVG (через JavaScript). Например, в следующем файле я хочу разместить каждый из желтых кругов по центру с правого края красной границы:

<?xml version="1.0"?>
<svg viewBox="0 0 1000 650" version="1.1" baseProfile="full"
     xmlns="http://www.w3.org/2000/svg">
  <title>Connect</title>
  <style type="text/css"><![CDATA[
    table { border-collapse:collapse; margin:0 auto; }
    table td { padding:0; border-bottom:1px solid #c00;}
    circle.dot { fill:blue }
  ]]></style>
  <foreignObject x="100" width="800" height="600" y="400"><body xmlns="http://www.w3.org/1999/xhtml"><table><thead><tr>
    <th>Space</th>
  </tr></thead><tbody>
    <tr><td><input name="name" type="text" value="One"/></td></tr>
    <tr><td><input name="name" type="text" value="Two"/></td></tr>
  </tbody></table></body></foreignObject>
  <circle class="dot" id="dot1" cx="100" cy="100" r="5" />
  <circle class="dot" id="dot2" cx="200" cy="100" r="5" />
</svg>

Как лучше всего найти местоположение произвольного элемента HTML в глобальном координатном пространстве SVG?

Для простоты не стесняйтесь игнорировать изменение размера браузера и любые стеки преобразования, которые могут обернуть <foreignObject>.

1 Ответ

2 голосов
/ 08 ноября 2011

Вот то, что я придумал, в действии: Расположение элемента HTML в SVG (v2)

// 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.
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;
  body.style.margin = body.style.padding = 0;
  wrap.setAttribute('x',100);
  var broken = body.getBoundingClientRect().left != 0;
  svg.removeChild(wrap);
  var pt = svg.createSVGPoint();
  return function svgCoordsForHTMLElement(htmlEl,svgEl){
    if (!svgEl) svgEl = htmlEl.ownerDocument.documentElement;
    for (var o=htmlEl;o&&o.tagName!='foreignObject';o=o.parentNode){}
    var xform = o.getTransformToElement(svgEl);
    if (broken) xform = o.getScreenCTM().inverse().multiply(xform);

    var coords = {};
    var rect = htmlEl.getBoundingClientRect();
    pt.x = rect.left; pt.y = rect.top;
    coords.nw = pt.matrixTransform(xform);
    pt.y = rect.bottom; coords.sw = pt.matrixTransform(xform);
    pt.x = rect.right;  coords.se = pt.matrixTransform(xform);
    pt.y = rect.top;    coords.ne = pt.matrixTransform(xform);

    return coords;
  };
})(document.documentElement);

А вот как вы его используете:

// Setting SVG group origin to bottom right of HTML element
var pts = svgCoordsForHTMLElement( htmlEl );
var x = pts.sw.x, y = pts.sw.y;
svgGroup.setAttribute( 'transform', 'translate('+x+','+y+')' );

Предостережения:

  • Отлично работает в Firefox v7
  • Работает для Chrome v16 и Safari v5, за исключением:
    • Не работает, еслизум браузера был отрегулирован.
    • Не работает, если <foreignObject> был повернут или перекошен, из-за этой ошибки Webkit .
  • Он не работает для IE9 (XHTML не отображается, а getTransformToElement не работает).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...