javascript SVG获取文本元素宽度

qyswt5oh  于 2022-12-21  发布在  Java
关注(0)|答案(7)|浏览(214)

我正在为一个SVG文件编写一些ECMAScript/JavaScript,需要获取text元素的widthheight,这样我就可以调整围绕它的矩形的大小。在HTML中,我可以使用元素的offsetWidthoffsetHeight属性,但这些属性似乎不可用。
这是我需要处理的一个片段,每当我改变文本时,我需要改变矩形的宽度,但是我不知道如何获得text元素的实际width(以像素为单位)。

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

有什么想法吗?

rpppsulh

rpppsulh1#

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

然后相应地设置rect的属性。
链接:SVG v1.1标准中的getBBox()

s1ag04yj

s1ag04yj2#

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

为我工作过

h4cxqtbf

h4cxqtbf3#

关于文本的长度,链接似乎指示BBox和getComputedTextLength()可能返回略有不同的值,但彼此相当接近。
http://bl.ocks.org/MSCAU/58bba77cdcae42fc2f44

jtw3ybtb

jtw3ybtb4#

这样的兼容性如何:

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将返回良好结果的元素上使用它,因此没有旋转,可能也没有缩放(?)

fykwrbwg

fykwrbwg5#

不知道为什么,但是上面的方法对我都不起作用。我在画布方法上取得了一些成功,但是我不得不应用各种各样的比例因子。即使使用了比例因子,我在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;

工作起来很棒,超级精确,但只在Firefox中。比例因子拯救了Chrome和Safari,但没有喜悦。原来Safari和Chrome错误与字符串长度或字体大小都不是线性的。
那么,第二种方法。我不太喜欢暴力破解的方法,但是在断断续续地挣扎了几年之后,我决定给予一下。我决定为每个可打印字符生成常量值。通常这会有点乏味,但幸运的是Firefox碰巧超级精确。下面是我的两部分暴力破解解决方案:

<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);
            var space_string_width = div.clientWidth;
            document.body.removeChild(div);
            var no_space_string = "!!";
            div.innerHTML = no_space_string;
            document.body.appendChild(div);
            var no_space_string_width = div.clientWidth;
            console.log("space width: " + (space_string_width - no_space_string_width));
            document.body.removeChild(div);


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

注意:上面的代码片段必须在Firefox中执行才能生成一个精确的数组值。另外,您必须在控制台日志中用空格宽度值替换数组项32。

我只需要复制Firefox屏幕上的文本,并将其粘贴到我的JavaScript代码中。现在我已经有了可打印字符长度的数组,我可以实现一个get width函数。

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

嗯,就是这样。蛮力,但它在所有三个浏览器中都非常准确,我的挫折感已经降到了零。不知道随着浏览器的发展,它会持续多久,但它应该足够长,我可以为我的SVG文本开发一个健壮的字体度量技术。

ua4mk5z4

ua4mk5z46#

SVG规范具有返回此信息的特定方法:第一个月

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

mitkmikd7#

如果你正在使用NodeJS并且希望保持你的应用程序轻便(例如不使用无头浏览器),一个可以使用的解决方案是预先计算字体大小。
1.使用:https://github.com/nicktaras/getFontCharWidth可以确定字体中每个字符的宽度。
1.然后在一个节点js应用程序中,例如,您可以迭代每个字符来计算实际宽度。

相关问题