【问题标题】:SVG: why does getBoundingClientRect return 190 when y attribute is 200?SVG:当 y 属性为 200 时,为什么 getBoundingClientRect 返回 190?
【发布时间】:2018-12-20 03:41:07
【问题描述】:

以下代码将 textBox1 置于 200 的 y 位置,但 getBoundingClientRect 返回的值为 190。

为什么?

https://codepen.io/anon/pen/REKayR?editors=1011

<svg id="rootBox" width="500" height="800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">

    <rect x="0%" y="0%" width="100%" height="100%" fill="beige" />

    <svg id="textBox1" x="0%" y="200" width="100%" height="25%">
      <rect class="background" x="0%" y="0%" width="100%" height="100%" fill="gray" fill-opacity="0.5" />
      <text class="textGroup" x="0" y="0"><tspan x="50%" dy="-0.25em" text-anchor="middle">tspan line 0</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 1</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 2</tspan></text>
    </svg>

</svg>


var textBox = $("#textBox1");
var textBBox = textBox[0].getBoundingClientRect();
console.log("The y-pos is: " + textBBox.y);

【问题讨论】:

    标签: javascript html svg


    【解决方案1】:

    .getBoundingClientRect() 是通用Element 接口的一部分,用于计算与屏幕视口相关的矩形。 SVG 提供一些more specific methods:

    • SVGGraphicsElement.getBBox() 在绘制元素的局部坐标系中计算边界框。
    • SVGGraphicsElement.getCTM() 计算局部坐标系和最近 SVG 视口(例如&lt;svg&gt; 元素)之间的变换矩阵。
    • SVGGraphicsElement.getScreenCTM() 计算局部坐标系和屏幕视口之间的变换矩阵。

    此外,DOMMatrix 接口有一个.inverse() 方法,因此您可以轻松计算相反方向的位置。 (例如,如果您使用 element.getScreenCTM().inverse() 的结果转换鼠标事件 screenx/screenY 位置,您将获得相对于该元素的鼠标位置。)

    有点尴尬的是,您必须构造一个 SVGPoint 对象,这只能通过 &lt;svg&gt; 元素上的 SVGSVGElement.createSVGPoint() 方法来实现,才能将矩阵应用到。

    至于您的问题,请考虑内部&lt;svg&gt; 内部矩形的三个坐标系的不同返回值:

    var textBox = document.querySelector('#textBox1 rect');
    var svg = document.querySelector('#rootBox');
    var point = svg.createSVGPoint();
    
    var local = textBox.getBBox();
    point.x = local.x, point.y = local.y;
    console.log("local: ", local.x, local.y);
    
    var nearest = textBox.getCTM();
    var point2 = point.matrixTransform(nearest);
    console.log("nearest viewport: ", point2.x, point2.y);
    
    var screen = textBox.getScreenCTM();
    var point3 = point.matrixTransform(screen);
    console.log("screen viewport: ", point3.x, point3.y);
    <svg id="rootBox" width="500" height="800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    
        <rect x="0%" y="0%" width="100%" height="100%" fill="beige" />
    
        <svg id="textBox1" x="0%" y="200" width="100%" height="25%">
          <rect class="background" x="0%" y="0%" width="100%" height="100%" fill="gray" fill-opacity="0.5" />
          <text class="textGroup" x="0" y="0"><tspan x="50%" dy="-0.25em" text-anchor="middle">tspan line 0</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 1</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 2</tspan></text>
        </svg>
    </svg>

    【讨论】:

    • 处理这个问题真是令人沮丧,浪费了这么多时间。你在几分钟内解决了它。谢谢。
    【解决方案2】:

    getBoundingClientRect 会考虑滚动位置等因素。 HTML 正文上的任何边距或填充也会考虑在内,但会添加到结果中而不是减去。

    如果您确保没有向下滚动,并且不考虑边距,您将获得 200:

    function log() {
      var textBox = $("#textBox1");
      var textBBox = textBox[0].getBoundingClientRect();
      console.log("The y-pos is: " + textBBox.y);
    }
    log();
    setInterval(log, 1000);
    html,
    body {
      margin: 0;
      padding: 0;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <svg id="rootBox" width="500" height="800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    
        <rect x="0%" y="0%" width="100%" height="100%" fill="beige" />
    
        <svg id="textBox1" x="0%" y="200" width="100%" height="25%">
          <rect class="background" x="0%" y="0%" width="100%" height="100%" fill="gray" fill-opacity="0.5" />
          <text class="textGroup" x="0" y="0"><tspan x="50%" dy="-0.25em" text-anchor="middle">tspan line 0</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 1</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 2</tspan></text>
        </svg>
    
    </svg>

    【讨论】:

    • 是否有考虑滚动、边距和填充的等效函数?还是您必须手动计算?感谢您的帮助!
    • @Crashalot 我认为这取决于您要获得的 Y 值相对于什么。如果你知道这一点,你可以得到那个元素的 Y 值,然后减去另一个元素的 Y 值,你就会得到答案。
    • 例如,即使使用 jQuery 的偏移功能,尝试这个 Codepen 仍然会产生错误的值:codepen.io/anon/pen/REKayR?editors=1111
    • @Crashalot jQuery 故意不完全支持 SVG,它主要是一个 DOM 库,所以它可能与此有关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 2019-11-11
    • 2021-03-21
    • 1970-01-01
    相关资源
    最近更新 更多