2015-03-13 108 views
19

我想在其旁邊顯示一個rect,其標籤爲textrect的寬度應該拉伸到svg容器的寬度,小於文本的寬度,這是動態的,可以是任何可變長度。在繪製文本之前計算文本的寬度

JSFiddle

var text = 'Foobar'; 
var textWidth = 50; //how to calculate this? 
var plotWidth = 400; 
var barWidth = plotWidth-textWidth; 

var plot = d3.select(container) 
     .insert("svg") 
     .attr('width', plotWidth) 
     .attr('height', 50); 

plot.append("rect") 
    .style("fill", "steelblue") 
    .attr("x", 0) 
    .attr("width", barWidth) 
    .attr("y", 0) 
    .attr("height", 50); 

plot.append("text") 
    .attr("x", barWidth) 
    .attr("y", 28) 
    .text(text); 

如何計算使用D3文本的寬度,繪製之前呢?或者,如何確定取決於可變長度文本的維度的元素的位置和大小?

+3

見http://stackoverflow.com/questions/20224611/d3-position-text-element-dependent-on-length-of-element-before – 2015-03-13 12:07:49

回答

8

下面是基於使用getBBox().widthgetComputedTextLength()工作示例:

編輯:更新答案使用getComputedTextLength由於性能的關注(見註釋)

http://jsfiddle.net/henbox/jzkj29nv/27/

var text_element = plot.select("text"); 
var textWidth = text_element.node().getComputedTextLength() 

我也切換到使用text-anchor: end; CSS對於文本,所以你不需要計算文本的開始位置(只是在最後傳遞)

+1

值得一提的是getBBox()強制渲染過程在瀏覽器中,所以如果重複執行可能會導致可怕的性能問題。 – averydev 2017-04-04 03:45:33

+0

謝謝 - 好的電話!我已經更新了刪除getBBox()的答案,並建議使用getComputedTextLength – 2017-04-04 10:38:31

8

我知道你問了D3,但這可能是你的問題的本地解決方案。

HTML5 canvas 2D上下文具有一些內置功能來測量文本。您可能可以利用它來測量其他API(如SVG)的文本。如果它不是100%準確的,那肯定與正確的答案成正比。

function getTextWidth(text, fontSize, fontFace) { 
    var canvas = document.createElement('canvas'); 
    var context = canvas.getContext('2d'); 
    context.font = fontSize + 'px ' + fontFace; 
    return context.measureText(text).width; 
} 

// Then call it like this: 
console.log(getTextWidth('hello world', 22, 'Arial')); // 105.166015625 
console.log(getTextWidth('hello world', 22)); // 100.8154296875 
12

我與許多元素和文本之間的相互作用,這需要知道文本寬度之前顯示任何元素的複合圖表中也有類似的問題。

我採取了創建一個虛擬文本來獲取其寬度並立即刪除它。請注意0​​中函數的最後一行代碼。

var textData = ['a', 'b', 'c'] // your text here 

var textWidth = [] 

svg.append('g') 
    .selectAll('.dummyText') 
    .data(textData) 
    .enter() 
    .append("text") 
    .attr("font-family", "sans-serif") 
    .attr("font-size", "14px") 
    //.attr("opacity", 0.0)  // not really necessary 
    .text(function(d) { return d}) 
    .each(function(d,i) { 
     var thisWidth = this.getComputedTextLength() 
     textWidth.push(thisWidth) 
     this.remove() // remove them just after displaying them 
    }) 

console.log(textWidth) // this array contains the on-screen width of each text element