Подтвердить что ты не робот

Вычислить ширину текста перед рисованием текста

Я хочу показать 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, до его рисования? Или как я могу позиционировать и размер элементов, которые зависят от размеров текста переменной длины?

4b9b3361

Ответ 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; для текста, поэтому вам не нужно вычислять начальную позицию текста (просто передайте в конце)