23

我在 D3 上经常遇到这个问题。很多时候我喜欢在我的 SVG 上覆盖 HTML 对象。

我当前的策略是在名为 .html-overlay 的 SVG 元素旁边创建一个空 DIV。我根据我在 SVG 中为主图形设置的内部填充来定位它(例如:20px)。然后我使用以下函数(使用 jQuery)来确定 HTML 元素的位置:

//element is the object returned by D3 .append()
var getOffset: function(element) {
        var $element = $(element[0][0]);
        return {
            left: $element.offset().left - $('.html-overlay').offset().left,
            top: $element.offset().top - $('.html-overlay').offset().top
        };
    }

我想知道,必须有一些内部(不依赖于 jQuery)的方法来快速获取元素的偏移量。它非常有用(尤其是在元素经过多次平移、旋转、缩放等之后)

具有计算元素“中心”的偏移量、元素的最高点、最底部、最左边、最右边等的函数也很棒。

笔记:

getBoundingClientRect() 由于某种原因没有给出正确的数字:

var $element = $(element[0][0]);

            console.log($element.offset(), element[0][0].getBoundingClientRect())
Object
left: 328
top: 248.8333282470703
__proto__: Object

ClientRect
bottom: 376.83331298828125
height: 139.99998474121094
left: 328
right: 478
top: 236.8333282470703
width: 150
4

3 回答 3

17

你试过了吗

var xywh =element[0][0].getBoundingClientRect();

似乎拥有一切?(原始解决方案在这篇文章中)

于 2012-10-24T01:14:06.083 回答
11

问题在于getBoundingClientRect,它不考虑滚动位置或元素相对于文档的容器位置。它只会报告项目相对于文档顶部和左侧坐标的确切位置。

我创建了一个 d3 方法,它将报告元素的位置。它的工作原理是遍历父元素,直到找到容器 SVG,然后考虑该项目在计算中的位置。它返回您通常会从getBoundingClientRect.

这是方法:

d3.selection.prototype.position = function() {

    var el = this.node();
    var elPos = el.getBoundingClientRect();
    var vpPos = getVpPos(el);

    function getVpPos(el) {
        if(el.parentElement.tagName === 'svg') {
            return el.parentElement.getBoundingClientRect();
        }
        return getVpPos(el.parentElement);
    }

    return {
        top: elPos.top - vpPos.top,
        left: elPos.left - vpPos.left,
        width: elPos.width,
        bottom: elPos.bottom - vpPos.top,
        height: elPos.height,
        right: elPos.right - vpPos.left
    };

};

你可以像这样使用它:

d3.select(element).position()

请注意,我实际上并没有在此处添加代码来考虑滚动位置。

于 2013-12-05T18:02:08.750 回答
0

扩展 James Lai 的答案以支持现代版本的 IE:

function getVpPos(el) {
    if(el.parentNode.nodeName === 'svg') {
        return el.parentNode.getBoundingClientRect();
    }
    return getVpPos(el.parentNode);
}

注意:parentElement更改为parentNodetagName更改为nodeName

于 2015-02-25T19:06:18.733 回答