Вычислить ширину текста перед рисованием текста
Я хочу показать 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, до его рисования? Или как я могу позиционировать и размер элементов, которые зависят от размеров текста переменной длины?
Ответы
Ответ 1
У меня была аналогичная проблема в сложной диаграмме с большим количеством взаимодействий между элементами и текстом, что требовало знания ширины текста до отображения любого элемента.
Я прибегал к созданию фиктивного текста, чтобы захватить его ширину и немедленно удалить его. Обратите внимание на последнюю строку кода функции в 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
Ответ 2
Я знаю, что вы спрашивали о D3, но это может быть нативным решением вашей проблемы.
2D-контекст HTML5 canvas имеет некоторые встроенные функции для измерения текста. Вы можете использовать это для измерения текста для других API, таких как SVG. Если он не на 100% точен, то он обязательно пропорционален правильному ответу.
var BrowserText = (function () {
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d');
/**
* Measures the rendered width of arbitrary text given the font size and font face
* @param {string} text The text to measure
* @param {number} fontSize The font size in pixels
* @param {string} fontFace The font face ("Arial", "Helvetica", etc.)
* @returns {number} The width of the text
**/
function getWidth(text, fontSize, fontFace) {
context.font = fontSize + 'px ' + fontFace;
return context.measureText(text).width;
}
return {
getWidth: getWidth
};
})();
// Then call it like this:
console.log(BrowserText.getWidth('hello world', 22, 'Arial')); // 105.166015625
console.log(BrowserText.getWidth('hello world', 22)); // 100.8154296875
Ответ 3
Вот рабочий пример, основанный на использовании getBBox().width
getComputedTextLength()
:
Изменить: обновление ответа для использования getComputedTextLength
из-за проблем с производительностью (см. комментарий)
http://jsfiddle.net/henbox/jzkj29nv/27/
var text_element = plot.select("text");
var textWidth = text_element.node().getComputedTextLength()
Я также переключился на использование CSS text-anchor: end;
для текста, поэтому вам не нужно вычислять начальную позицию текста (просто передайте в конце)