确定使用@ font-face设置样式的svg文本宽度的可靠方法

时间:2013-09-19 03:02:19

标签: javascript css svg d3.js font-face

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

overlaping words

然而,当我稍后使用在延迟或按钮上触发的相同功能定位元素时,它们不会重叠。

not overlapping words

该问题似乎与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()})

2 个答案:

答案 0 :(得分:2)

我还没有尝试过浏览器加载事件(我几乎也不了解网络字体),但是当我们遇到这个问题时(尽管仍在使用Chartbuilder),我们使用WebFontLoader解决了这个问题并等待对于active event。这有一个问题:文本必须出现在页面上才能加载,所以你需要一个使用你的字体的隐藏跨度(或其他)。

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

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

附录:我认为它确实没有任何实际意义,但我们也转而使用getComputedTextLength()而不是测量边界框,只是因为它似乎更正确。请参阅the code here

答案 1 :(得分:1)

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

等待浏览器的加载事件(如Robert suggests)是值得尝试的,但我不确定它是否适用于所有浏览器。我之前读到的一些内容暗示某些浏览器实际上并没有加载远程@ font-face字体,直到遇到第一个用法而不仅仅是CSS声明。但我没有任何经验,所以我不肯定。

这是一个related SO question,它有很多关于@ font-face和下载时间的完整答案。