SVG获取文本元素宽度

时间:2009-10-28 12:04:53

标签: javascript dom text svg

我正在为SVG文件制作一些ECMAScript / JavaScript,需要获取width元素的heighttext,以便我可以调整围绕它的矩形。在HTML中,我可以使用元素上的offsetWidthoffsetHeight属性,但看起来这些属性不可用。

这是我需要使用的片段。每当我更改文本时,我都需要更改矩形的宽度,但我不知道如何获得width元素的实际text(以像素为单位)。

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

有什么想法吗?

7 个答案:

答案 0 :(得分:139)

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

然后相应地设置rect的属性。

链接:SVG v1.1标准中的getBBox()

答案 1 :(得分:7)

关于文本的长度,链接似乎表明BBox和getComputedTextLength()可能会返回稍微不同的值,但是它们彼此非常接近。

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

答案 2 :(得分:2)

兼容性如何:

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;
}

这将返回三种方法的任何有效结果的平均值。如果元素是文本元素,您可以改进它以抛弃异常值或支持getComputedTextLength

警告:正如评论所说,getBoundingClientRect很棘手。从方法中删除它或仅在getBoundingClientRect将返回良好结果的元素上使用它,因此没有旋转,可能没有缩放(?)

答案 3 :(得分:2)

不确定原因,但上述方法都不适合我。我在canvas方法上取得了一些成功,但我不得不应用各种比例因子。即使使用比例因子,我仍然在Safari,Chrome和Firefox之间产生不一致的结果。

所以,我尝试了以下内容:

&#13;
&#13;
            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;
&#13;
&#13;
&#13;

工作得非常棒且非常精确,但仅限于Firefox。缩放因素来拯救Chrome和Safari,但没有任何乐趣。事实证明,Safari和Chrome错误与字符串长度或字体大小不一致。

所以,接近第二。我不太关心蛮力的做法,但经过多年的挣扎,我决定尝试一下。我决定为每个可打印字符生成常量值。通常这会很乏味,但幸运的是Firefox恰好是超级准确的。这是我的两部分蛮力解决方案:

&#13;
&#13;
    <body>
        <script>
            
            var div = document.createElement('div');
            div.style.position = 'absolute';
            div.style.height = 'auto';
            div.style.width = 'auto';
            div.style.whiteSpace = 'nowrap';
            div.style.fontFamily = 'YOUR_FONT';
            div.style.fontSize = '100';          // large enough for good resolution
            div.style.border = "1px solid blue"; // for visible convenience
            
            var character = "";
            var string = "array = [";
            for(var i=0; i<127; i++) {
                character = String.fromCharCode(i);
                div.innerHTML = character;
                document.body.appendChild(div);
                
                var offsetWidth = div.offsetWidth;
                var clientWidth = div.clientWidth;
                console.log("ASCII: " + i + ", " + character + ", client width: " + div.clientWidth);
                
                string = string + div.clientWidth;
                if(i<126) {
                    string = string + ", ";
                }

                document.body.removeChild(div);
                
            }
        
            var space_string = "! !";
            div.innerHTML = space_string;
            document.body.appendChild(div);
            console.log("space width: " + div.clientWidth - space_string.charCodeAt(0)*2);
            document.body.removeChild(div);

            string = string + "]";
            div.innerHTML = string;
            document.body.appendChild(div);
            </script>
    </body>
&#13;
&#13;
&#13;

注意:上述代码段必须在Firefox中执行才能生成准确的值数组。此外,您必须使用控制台日志中的空间宽度值替换数组项目32。

我只是在屏幕文本上复制Firefox,然后将其粘贴到我的javascript代码中。现在我有可打印字符长度数组,我可以实现一个get width函数。这是代码:

&#13;
&#13;
const LCARS_CHAR_SIZE_ARRAY = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 26, 46, 63, 42, 105, 45, 20, 25, 25, 47, 39, 21, 34, 26, 36, 36, 28, 36, 36, 36, 36, 36, 36, 36, 36, 27, 27, 36, 35, 36, 35, 65, 42, 43, 42, 44, 35, 34, 43, 46, 25, 39, 40, 31, 59, 47, 43, 41, 43, 44, 39, 28, 44, 43, 65, 37, 39, 34, 37, 42, 37, 50, 37, 32, 43, 43, 39, 43, 40, 30, 42, 45, 23, 25, 39, 23, 67, 45, 41, 43, 42, 30, 40, 28, 45, 33, 52, 33, 36, 31, 39, 26, 39, 55];


    static getTextWidth3(text, fontSize) {
        let width = 0;
        let scaleFactor = fontSize/100;
        
        for(let i=0; i<text.length; i++) {
            width = width + LCARS_CHAR_SIZE_ARRAY[text.charCodeAt(i)];
        }
        
        return width * scaleFactor;
    }
&#13;
&#13;
&#13;

嗯,就是这样。蛮力,但它在所有三种浏览器中都非常准确,我的挫折程度已降至零。不确定浏览器的发展会持续多长时间,但是我应该为我的SVG文本开发一个强大的字体度量技术。

答案 4 :(得分:2)

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

为我工作

答案 5 :(得分:0)

如果您正在使用 NodeJS 并希望使您的应用程序保持轻便(例如,不使用无头浏览器)。可以使用的解决方案是预先计算字体大小。

  1. 使用:https://github.com/nicktaras/getFontCharWidth,您可以确定字体中每个字符的宽度。

  2. 然后例如在 node js 应用程序中,您可以遍历每个字符以计算实际宽度。

答案 6 :(得分:-1)

SVG规范有一个特定的方法来返回此信息:getComputedTextLength()

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