1

我在使用 D3 一个接一个地定位 css web-font 样式、svg 文本元素时遇到问题。当我第一次在加载时定位文本元素时,它们会重叠。

重叠词

但是,当我稍后使用延迟触发或通过按钮触发的相同功能定位元素时,它们不会重叠。

不重叠词

问题似乎在于,getBBox()并且getBoundingClientRect()最初都没有为元素返回正确的宽度。

关于如何首先获得正确宽度的任何想法?

JS 在下面,一个例子在这里: http ://bl.ocks.org/yanofsky/6618496 和完整的代码在这里: https ://gist.github.com/yanofsky/6618496

//helper function to grab transform coordinates 
function transformCoordOf(elem) {
    var separator = elem.attr("transform").indexOf(",") > -1 ? "," : " ";
    var trans = elem.attr("transform").split(separator);
    return { x: (trans[0] ? parseFloat(trans[0].split("(")[1]) : 0), y: (trans[1] ?         parseFloat(trans[1].split(")")[0] ): 0) };
}

//position the elements based on the one before it
function positionElements() {
    txts.filter(function(d,i){return i != 0}) //filter out the first element
        .attr("transform",function(d,i){
            var prev = d3.select(txts[0][i]), //use i b/c the list shifts on filter
            prevWidth = parseFloat(prev.node().getBoundingClientRect().width)
            prevCoords = transformCoordOf(prev);

            var cur = d3.select(this),
            curWidth = parseFloat(cur.node().getBoundingClientRect().width)
            curCoords = transformCoordOf(cur);

            var y = prevCoords.y,
                x = prevCoords.x + prevWidth + 10;

            return "translate("+x+","+y+")";
        })
}

var names = ["apples","oranges","bananas"]
var canvas = d3.select("#content")
    .append("svg")
    .attr("width","600px")
    .attr("height","100px");

var txts = canvas.selectAll("text").data(names)
    .enter()
    .append("text")
    .attr("transform","translate(10,50)")
    .text(function(d){return d});

positionElements()

d3.select("button").on("click",function(){positionElements()})
4

2 回答 2

2

我没有尝试过浏览器加载事件(我对网络字体几乎一无所知),但是当我们遇到这个问题时(尽管在 Chartbuilder 上进行了黑客攻击),我们通过使用WebFontLoader并等待活动事件来解决它。一个问题:文本必须出现在页面上才能被加载,所以你需要一个使用你的字体的隐藏跨度(或其他)。

这是我们的代码(我们从fonts.com加载字体:

WebFont.load({
    monotype: {
        projectId: '65980087-55e2-40ca-85ae-729fca359467',
    },
    active: function(name) {
        $(document).ready(function() {
            ChartBuilder.start();
        });
    }
});

附录:我不认为它真的有任何实际区别,但我们也切换到使用getComputedTextLength()而不是测量边界框,只是因为它看起来更正确。请参阅此处的代码

于 2013-09-19T12:50:33.610 回答
1

<text>在您首次渲染元素并测量其宽度时,您所引用的字体尚未下载。所以在这个时间点上,你会得到一个更小的宽度,在加载引用的字体之后你会得到一个更小的宽度。

等待浏览器的加载事件(正如Robert 建议的那样)是值得一试的,但我不确定这是否适用于所有浏览器。我之前读过一些内容,暗示某些浏览器实际上不会加载远程@font-face 字体,直到它们遇到第一次使用而不仅仅是 CSS 声明。但是我没有这方面的经验,所以我并不积极。

这是一个相关的 SO 问题,其中有几个很好的答案,其中包含有关 @font-face 和下载时间的链接。

于 2013-09-19T05:18:54.963 回答