如何对齐单独的 svg 文本元素,如 word 中的字符对齐

How to align separate svg text elements like character alignment in word

我正在使用 svg text 元素,我需要为特定单词的每个字符创建单独的 <text></text> 元素,在本例中为 Lorem

例如,

const svg = document.querySelector("svg");

const svgns = "http://www.w3.org/2000/svg"

//vboxDim

var vboxW = 200;
var vboxH = 200;

//assigning svg element attribute 
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', `0 0 ${vboxW} ${vboxH}`);

//make background
var fill1 = '#F1C40F';

let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute("width", `${vboxW}`);
bg.setAttribute("height", `${vboxH}`);
bg.setAttribute("fill", fill1);
svg.appendChild(bg);

var txtArray1 = ['L', 'o', 'r', 'e', 'm'];


var textX = svg.viewBox.baseVal.width / 2;
var textY = svg.viewBox.baseVal.height / 2;


for (var i = 0; i < txtArray1.length; i++) {
    let text1 = document.createElementNS(svgns, "text")
    text1.setAttribute('class', 't0' + i)
    text1.setAttribute('id', 't0' + i);
    text1.setAttribute('x', textX);
    text1.setAttribute('y', textY);
    text1.setAttribute('fill','green');
    text1.setAttribute('dominant-baseline', 'middle'); //positions text in the middle
    text1.setAttribute('text-anchor', 'middle'); //positions text in the middle
    text1.textContent = txtArray1[i];
    svg.appendChild(text1);
    var el = document.getElementById(`t0${i}`);
    var width = el.getBBox().width;
    textX = textX + width;

}

let text2 = document.createElementNS(svgns, "text")
text2.setAttribute('class', 'word')
text2.setAttribute('id', 'word');
text2.setAttribute('x', (svg.viewBox.baseVal.width / 2));
text2.setAttribute('y', (svg.viewBox.baseVal.height / 2) - 50);
text2.setAttribute('fill','brown');
text2.setAttribute('dominant-baseline', 'middle'); //positions text in the middle
text2.setAttribute('text-anchor', 'middle'); //positions text in the middle
text2.textContent = 'Lorem';
svg.appendChild(text2);
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style></style>

</head>

<body>

    <svg>
        <script href="index.js"></script>
    </svg>
</body>

</html>

如果这些单独的字符被创建为单词,我希望它们对齐

class="word"

在设计时,我最初的想法是获取立即创建的角色的BBox().width并将下一个元素的x增加相同的值。但是最后一个元素与 class="word".

中的元素相距甚远

创建单个文本元素并将它们对齐(绿色)的最佳策略是什么,因为它们将出现在一个句子(棕色)中?

Update 我已经尝试了@Robert Longson 的建议。不知道是不是做错了,但是不准确

const svg = document.querySelector("svg");

const svgns = "http://www.w3.org/2000/svg"

//vboxDim
var vboxW = 200;
var vboxH = 200;

//assigning svg element attribute 
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', `0 0 ${vboxW} ${vboxH}`);

//make background
var fill1 = '#F1C40F';

let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute("width", `${vboxW}`);
bg.setAttribute("height", `${vboxH}`);
bg.setAttribute("fill", fill1);

// append the new rectangle to the svg
svg.appendChild(bg);

var txtArray1 = ['L', 'o', 'r', 'e', 'm'];


var textX = svg.viewBox.baseVal.width / 2;
var textY = svg.viewBox.baseVal.height / 2;



let text2 = document.createElementNS(svgns, "text")
text2.setAttribute('class', 'word')
text2.setAttribute('id', 'word');
text2.setAttribute('x', (svg.viewBox.baseVal.width / 2));
text2.setAttribute('y', (svg.viewBox.baseVal.height / 2) - 50);
text2.setAttribute('fill','brown');
text2.setAttribute('dominant-baseline', 'middle'); //positions text in the middle
text2.setAttribute('text-anchor', 'middle'); //positions text in the middle
text2.textContent = 'Lorem';
svg.appendChild(text2);



for (var i = 0; i < txtArray1.length; i++) {
    var x = document.getElementById('word');
    let text1 = document.createElementNS(svgns, "text")
    text1.setAttribute('class', 't0' + i)
    text1.setAttribute('id', 't0' + i);
    text1.setAttribute('x', x.getStartPositionOfChar(i).x);
    text1.setAttribute('y', x.getStartPositionOfChar(i).y);
    text1.setAttribute('fill','green');
    text1.setAttribute('dominant-baseline', 'middle'); //positions text in the middle
    text1.setAttribute('text-anchor', 'middle'); //positions text in the middle
    text1.textContent = txtArray1[i];
    svg.appendChild(text1);


}

text2.setAttribute('y', 75);
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style></style>

</head>

<body>
    <link rel="stylesheet" href="style.css">
    </link>
    <svg>
        <script href="index.js"></script>
    </svg>
</body>

</html>

  • 调用 getStartPositionOfChar 找出每个字符的位置。

  • 制作副本时不需要设置text-anchor或dominant-baseline,因为原始字符位置已经包含了。

const svg = document.querySelector("svg");

const svgns = "http://www.w3.org/2000/svg"

//vboxDim
var vboxW = 200;
var vboxH = 200;

//assigning svg element attribute 
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', `0 0 ${vboxW} ${vboxH}`);

//make background
var fill1 = '#F1C40F';

let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute("width", `${vboxW}`);
bg.setAttribute("height", `${vboxH}`);
bg.setAttribute("fill", fill1);

// append the new rectangle to the svg
svg.appendChild(bg);

var txtArray1 = ['L', 'o', 'r', 'e', 'm'];


var textX = svg.viewBox.baseVal.width / 2;
var textY = svg.viewBox.baseVal.height / 2;



let text2 = document.createElementNS(svgns, "text")
text2.setAttribute('class', 'word')
text2.setAttribute('id', 'word');
text2.setAttribute('x', (svg.viewBox.baseVal.width / 2));
text2.setAttribute('y', (svg.viewBox.baseVal.height / 2) - 50);
text2.setAttribute('fill','brown');
text2.setAttribute('dominant-baseline', 'middle'); //positions text in the middle
text2.setAttribute('text-anchor', 'middle'); //positions text in the middle
text2.textContent = 'Lorem';
svg.appendChild(text2);



for (var i = 0; i < txtArray1.length; i++) {
    var x = document.getElementById('word');
    let text1 = document.createElementNS(svgns, "text")
    text1.setAttribute('class', 't0' + i)
    text1.setAttribute('id', 't0' + i);
    text1.setAttribute('x', x.getStartPositionOfChar(i).x);
    text1.setAttribute('y', x.getStartPositionOfChar(i).y);
    text1.setAttribute('fill','green');
    text1.textContent = txtArray1[i];
    svg.appendChild(text1);


}

text2.setAttribute('y', 75);
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style></style>

</head>

<body>
    <link rel="stylesheet" href="style.css">
    </link>
    <svg>
        <script href="index.js"></script>
    </svg>
</body>

</html>