2015-03-13 4 views
19

Я хочу показать rect с ярлыком text рядом с ним. Ширина rect должна растягиваться до ширины контейнера 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 –

ответ

8

Вот рабочий пример, основанный на использовании getBBox().widthgetComputedTextLength():

Edit: Обновление ответа использовать getComputedTextLength из-за проблем производительности (см комментарий)

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

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

Я также переключился на использование text-anchor: end; CSS fo r текст, поэтому вам не нужно рассчитать начальную позицию текста (просто пройдите в конце)

+1

Стоит отметить, что getBBox() заставляет рендер проход в браузере, и, если это сделано, это может привести к серьезным проблемам с производительностью. – averydev

+0

Спасибо, хороший звонок! Я обновил ответ, чтобы удалить getBBox() и рекомендовать getComputedTextLength –

8

Я знаю, что вы спросили о D3, но это может быть родным решением вашей проблемы.

В двухмерном контексте холста HTML5 есть встроенная функциональность для измерения текста. Вы могли бы использовать это для измерения текста для других 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

У меня была аналогичная проблема в сложном графике с большим количеством взаимодействий между элементами и текста, которые требуется знание текста ширину перед тем отображения какой-либо элемент.

Я прибегал к созданию фиктивного текста, чтобы захватить его ширину и немедленно удалить его. Обратите внимание на последнюю строку кода функции в each.

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 
Смежные вопросы