SVG получает ширину текстового элемента

Я работаю над некоторыми ECMAScript/JavaScript для SVG файла и должен получить width и height элемента text, чтобы изменить размер прямоугольника, который его окружает. В HTML я мог бы использовать атрибуты offsetWidth и offsetHeight для элемента, но кажется, что эти свойства недоступны.

Вот фрагмент, с которым мне нужно работать. Мне нужно изменить ширину прямоугольника всякий раз, когда я меняю текст, но я не знаю, как получить фактический width (в пикселях) элемента text.

<rect x="100" y="100" width="100" height="100" />
<text>Some Text</text>

Любые идеи?

Ответ 1

var bbox = textElement.getBBox();
var width = bbox.width;
var height = bbox.height;

а затем соответствующим образом установите соответствующие атрибуты.

Ссылка: getBBox() в стандарте SVG v1.1.

Ответ 2

Что касается длины текста, ссылка, по-видимому, указывает на то, что BBox и getComputedTextLength() могут возвращать несколько разные значения, но те, которые довольно близки друг к другу.

http://bl.ocks.org/MSCAU/58bba77cdcae42fc2f44

Ответ 3

Как насчет чего-то подобного для совместимости:

function svgElemWidth(elem) {
    var methods = [ // name of function and how to process its result
        { fn: 'getBBox', w: function(x) { return x.width; }, },
        { fn: 'getBoundingClientRect', w: function(x) { return x.width; }, },
        { fn: 'getComputedTextLength', w: function(x) { return x; }, }, // text elements only
    ];
    var widths = [];
    var width, i, method;
    for (i = 0; i < methods.length; i++) {
        method = methods[i];
        if (typeof elem[method.fn] === 'function') {
            width = method.w(elem[method.fn]());
            if (width !== 0) {
                widths.push(width);
            }
        }
    }
    var result;
    if (widths.length) {
        result = 0;
        for (i = 0; i < widths.length; i++) {
            result += widths[i];
        }
        result /= widths.length;
    }
    return result;
}

Это возвращает среднее значение любых действительных результатов трех методов. Вы можете улучшить его, чтобы изгнать outliers или одобрить getComputedTextLength, если элемент является текстовым элементом.

Предупреждение. Как говорится в комментарии, getBoundingClientRect сложно. Либо удалите его из методов, либо используйте его только в тех элементах, где getBoundingClientRect вернет хорошие результаты, поэтому нет вращения и, вероятно, нет масштабирования (?)

Ответ 4

Не уверен, почему, но ни один из вышеперечисленных методов не работает для меня. У меня был некоторый успех с методом canvas, но мне пришлось применять все виды масштабных факторов. Даже с учетом масштабных факторов у меня все еще были противоречивые результаты между Safari, Chrome и Firefox.

Итак, я попробовал следующее:

            var div = document.createElement('div');
            div.style.position = 'absolute';
            div.style.visibility = 'hidden';
            div.style.height = 'auto';
            div.style.width = 'auto';
            div.style.whiteSpace = 'nowrap';
            div.style.fontFamily = 'YOUR_FONT_GOES_HERE';
            div.style.fontSize = '100';
            div.style.border = "1px solid blue"; // for convenience when visible

            div.innerHTML = "YOUR STRING";
            document.body.appendChild(div);
            
            var offsetWidth = div.offsetWidth;
            var clientWidth = div.clientWidth;
            
            document.body.removeChild(div);
            
            return clientWidth;

Ответ 5

document.getElementById('yourTextId').getComputedTextLength();

работал у меня в

Ответ 6

function getSvgElementDims(selector) {
    var c = document.querySelector("#filtered");
    var matrix = c.getScreenCTM();
    var r = c.getBoundingClientRect()
    var pt_TopLeft = document.documentElement.createSVGPoint(r.x, r.y);
    var pt_BottomRight = document.documentElement.createSVGPoint(r.right, r.bottom);
    pt_TopLeft.x = r.x
    pt_TopLeft.y = r.y
    pt_BottomRight.x = r.right
    pt_BottomRight.y = r.bottom
    pt_TopLeft = pt_TopLeft.matrixTransform(matrix.inverse());
    pt_BottomRight = pt_BottomRight.matrixTransform(matrix.inverse());
    return {
        width: pt_BottomRight.x - pt_TopLeft.x,
        height: pt_BottomRight.y - pt_TopLeft.y
    }
}

Ответ 7

Спецификация SVG имеет специальный метод для возврата этой информации: getComputedTextLength()

var width = textElement.getComputedTextLength(); // returns a pixel number