使用SVG将文本居中在圆形中。

84

我想使用SVG将文本居中在圆形中。文本的大小会是动态的。

我的代码在Plunker上:

<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     xml:space="preserve"
     style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
     viewBox="0 0 500 500">

  <g id="UrTavla">
      <circle style="fill:url(#toning);stroke:#010101;stroke-width:1.6871;stroke-miterlimit:10;" cx="250" cy="250" r="245">
      
      </circle>
      <text x="50%" y="50%" stroke="#51c5cf" stroke-width="2px" dy=".3em"> Look, I’m centered!Look, I’m centered! </text>
  </g>
</svg>
6个回答

104

text 元素中添加 text-anchor="middle"

Plunker

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 500 500">
  <g id="UrTavla">
    <circle style="fill:url(#toning);stroke:#010101;stroke-width:1.6871;stroke-miterlimit:10;" cx="250" cy="250" r="245">
    </circle>
    <text x="50%" y="50%" text-anchor="middle" stroke="#51c5cf" stroke-width="2px" dy=".3em">Look, I’m centered!Look, I’m centered!</text>
  </g>
</svg>


11
如果他们的圆不在整个 SVG 中心,那么如何将文本居中在圆中?例如:http://plnkr.co/edit/bFeiKl5B67rjwhM028os?p=preview - Michael
2
@Michael 在这种情况下,我会使用JavaScript来居中文本。 - Weafs.py
7
做得很好!但为什么dy的魔术数字是0.3em而不是其他值? - Leo Gao
1
@Michael 使用圆的半径和当前位置。即:当前cx + 半径 = 文本的x值 - Kevin Cohen
16
这不应该被视为接受的答案,因为它取决于圆本身居中,并且使用取决于字体大小的y偏移量使文本垂直居中。相反,'text'元素的'x'和'y'属性应该等于'circle'元素的'cx'和'cy'属性,而且应该向'text'元素添加属性'textAnchor='middle''和'alignmentBaseline='central''。有关详细信息,请参见下面的备选答案。 - Nikolaj
1
下降投票原因:答案错误且无法运行。 它将文本居中于整个容器而不是圆圈上。 - NickG

53
所提出并接受的解决方案在您想要绘制不居中容器的圆形时是无效的!
只有当SVG元素包含居中于视口的圆时,使用x="50%" y="50%"text标记上才有效。
如果要绘制3个圆,则还必须更改(x,y)文本坐标,使它们等于如下示例中所做的(cx,cy)圆坐标。
正如random所建议的那样,我仅为代码片段中的第一个圆添加了alignment-baseline="middle",这样您就可以看到对于Label文本现在垂直对齐(完美)。

<svg height="350" width="350">
    <circle cx="110" cy="110" r="100"
            stroke="red"
            stroke-width="3"
            fill="none"
            />
    <text x="110" y="110" 
          text-anchor="middle"
          stroke="red"
          stroke-width="1px"
          alignment-baseline="middle"
          > Label
    </text>
    <circle cx="240" cy="110" r="100" 
            stroke="blue" 
            stroke-width="3"
            fill="none"
            />
    <text x="240" y="110" 
          text-anchor="middle" 
          stroke="blue" 
          stroke-width="1px"
          > Ticket
    </text>
    <circle cx="170" cy="240" r="100" 
            stroke="green" 
            stroke-width="3" 
            fill="none"
            />
    <text x="170" y="240" 
          text-anchor="middle" 
          stroke="green" 
          stroke-width="1px"
          > Vecto
    </text>
</svg>

为了好玩,我加入了带有3个圆圈的代码,可以选择每个部分。只需单击即可!

->

为了好玩,我在代码中加入了3个圆圈来选择每个部分,只需点击即可!

    function setReadableCode()
        {
        var circLabel = document.getElementById('circLabel');
        var circTicket = document.getElementById('circTicket');
        var circVecto = document.getElementById('circVecto');
        var interLabelTicket = document.getElementById('interLabelTicket');
        var interTicketVecto = document.getElementById('interTicketVecto');
        var interVectoLabel = document.getElementById('interVectoLabel');
        var interLabelTicketVecto = document.getElementById('interLabelTicketVecto');
        }

    function clickCircle(sCircle, sInter2a, sInter2b, sInter3)
        {
        var circ = document.getElementById(sCircle);
        var inter2a = document.getElementById(sInter2a);
        var inter2b = document.getElementById(sInter2b);
        var inter3 = document.getElementById(sInter3);

        var sColor = '';

        if (circ.style.fill == '' || circ.style.fill == 'white')
            {
            sColor = 'yellow';
            }
        else
            {
            sColor = 'white';
            }

        circ.style.fill = sColor;
        inter2a.style.fill = sColor;
        inter2b.style.fill = sColor;
        inter3.style.fill = sColor;

        setReadableCode();
        }

                    function clickCircLabel() {
                        clickCircle('circLabel', 'interLabelTicket', 'interVectoLabel', 'interLabelTicketVecto');
                    }

                    function clickCircTicket() {
                        clickCircle('circTicket', 'interLabelTicket', 'interTicketVecto', 'interLabelTicketVecto');
                    }

                    function clickCircVecto() {
                        clickCircle('circVecto', 'interVectoLabel', 'interTicketVecto', 'interLabelTicketVecto');
                    }

                    function clickIntersection2(sInter2, sInter3) {
                        var inter2 = document.getElementById(sInter2);
                        var inter3 = document.getElementById(sInter3);
                        var sColor = '';

                        if (inter2.style.fill == '' || inter2.style.fill == 'white') {
                            sColor = 'yellow';
                        }
                        else {
                            sColor = 'white';
                        }

                        inter2.style.fill = sColor;
                        inter3.style.fill = sColor;

                        setReadableCode();
                    }

                    function clickInterLabelTicket() {
                        clickIntersection2('interLabelTicket', 'interLabelTicketVecto');
                    }

                    function clickInterTicketVecto() {
                        clickIntersection2('interTicketVecto', 'interLabelTicketVecto');
                    }

                    function clickInterVectoLabel() {
                        clickIntersection2('interVectoLabel', 'interLabelTicketVecto');
                    }

                    function clickInterLabelTicketVecto() {
                        var inter = document.getElementById('interLabelTicketVecto');
                        var sColor = '';

                        if (inter.style.fill == '' || inter.style.fill == 'white') {
                            sColor = 'yellow';
                        }
                        else {
                            sColor = 'white';
                        }

                        inter.style.fill = sColor;
                        setReadableCode();
                    }
text 
    {
    font-family:Arial;
    }
<svg height="350" width="350">
<circle id="circLabel" cx="110" cy="110" r="100" stroke="red" stroke-width="0" fill="white" onclick="clickCircLabel();"/>
<text x="60" y="110" text-anchor="middle" stroke="red" stroke-width="1px" onclick="clickCircLabel();">Label</text>
<circle id="circTicket" cx="210" cy="110" r="100" stroke="blue" stroke-width="0" fill="yellow" onclick="clickCircTicket();"/>
<text x="260" y="110" text-anchor="middle" stroke="blue" stroke-width="1px" onclick="clickCircTicket();">Ticket</text>
<circle id="circVecto" cx="160" cy="196.602541" r="100" stroke="green" stroke-width="0" fill="white" onclick="clickCircVecto();" />
<text x="160" y="240" text-anchor="middle" stroke="green" stroke-width="1px" onclick="clickCircVecto();">Vecto</text>
<path id="interLabelTicket"
      d="M 160 23.397460 a100,100 0 0,0 0,173.205081 a100,100 0 0,0 0,-173.205081 z"
      fill="white"
      stroke-width="3"
      onclick="clickInterLabelTicket();"
      />

<path id="interVectoLabel"
      d="M 60 196.602541 a100,100 0 0,0 150,-86.602540 a100,100 0 0,0 -150,86.602540 z"
      fill="white"
      stroke-width="3"
      onclick="clickInterVectoLabel();"
      />

<path id="interTicketVecto"
      d="M 260 196.602541 a100,100 0 0,0 -150,-86.602540 a100,100 0 0,0 150,86.602540 z"
      fill="white"
      stroke-width="3"
      onclick="clickInterTicketVecto();"
      />

<path id="interLabelTicketVecto"
      d="M 110 110 a100,100 0 0,1 100,0 a100,100 0 0,1 -50,86.602540 a100,100 0 0,1 -50,-86.602540 z"
      fill="none"
      stroke-width="3"
      onclick="clickInterLabelTicketVecto();"
      />

<circle cx="110" cy="110" r="100" stroke="red" stroke-width="3" fill="none" />
<circle cx="210" cy="110" r="100" stroke="blue" stroke-width="3" fill="none" />
<circle cx="160" cy="196.602541" r="100" stroke="green" stroke-width="3" fill="none"/>

</svg>


3
它适用于大圆,但我们看不到的是文本垂直居中不好。你必须添加 alignment-baseline="middle"dominant-baseline="middle",就像其他答案所说的那样。 - Random
1
@random:谢谢。我已经在第一轮的代码片段中加入了你的建议,并在答案中添加了一些注释。 - schlebe

21

或许,alignment-baseline="middle"text-anchor="middle" 也会有用:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" viewBox="0 0 500 500">

  <g id="UrTavla">
      <circle style="fill:url(#toning);stroke:#010101;stroke-width:1.6871;stroke-miterlimit:10;" cx="250" cy="250" r="245" /> <!--self-closing tag-->

      <text x="50%" y="50%" stroke="#51c5cf" stroke-width="2px" dy=".3em" text-anchor="middle" alignment-baseline="middle"> Look, I’m centered!Look, I’m centered! </text>
  </g>
</svg>

这是一个很好的资源: http://apike.ca/prog_svg_text_style.html

11
如果你使用alignment-baseline="central",就不需要使用dy属性。 - 4thex
7
如果您使用 dominant-baseline="central" 而不是 alignment-baseline,它在 Firefox 中也可以工作。(https://dev59.com/jWIk5IYBdhLWcg3wguX-#21373135) - user3389196

14
一个适用于非居中圆的更简单的解决方案是将圆和文本放在翻译的组内。
这样,您无需在文本上重复坐标。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Centered texts</title>
  </head>

  <body ng-controller="MainCtrl">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
      <g transform="translate(300, 300)" >
        <circle fill="none" stroke="black" stroke-width="1px" r="120"/>
        <text stroke="blue" stroke-width="1px" text-anchor="middle" alignment-baseline="central">Look, I’m centered!</text>
      </g>
      
      <g transform="translate(150, 150)" >
        <circle fill="none" stroke="black" stroke-width="1px" r="120"/>
        <text stroke="blue" stroke-width="1px" text-anchor="middle" alignment-baseline="central">Look, I’m also centered!</text>
      </g>
    </svg>
  </body>
</html>


10

使用alignment-baseline="central"时,不同浏览器的行为不一致。特别是,Chrome会正确定位,但Firefox则不会。如果使用dominant-baseline="central",两者都将正确显示。

FireFox:

Chrome:

svg { height:140px }
<h4>alignment-baseline AND dominant-baseline settings:</h4>
<svg viewBox="0 0 48 48">
    <circle stroke="darkgray" stroke-width="1px" 
            fill="lightgray"  cx="50%" cy="50%" r="48%"/>
    <line x1="0" y1="50%" x2="100%" y2="50%" stroke="blue" stroke-width="1"/>
    <text text-anchor="middle" alignment-baseline="central" x="50%" y="50%">central</text> 
</svg>
<svg viewBox="0 0 48 48">
    <circle stroke="darkgray" stroke-width="1px" 
            fill="lightgray"  cx="50%" cy="50%" r="48%"/>
    <line x1="0" y1="50%" x2="100%" y2="50%" stroke="blue" stroke-width="1"/>
    <text text-anchor="middle" alignment-baseline="middle" x="50%" y="50%">middle</text> 
</svg>
<svg viewBox="0 0 48 48">
    <circle stroke="darkgray" stroke-width="1px" 
            fill="lightgray"  cx="50%" cy="50%" r="48%"/>
    <line x1="0" y1="50%" x2="100%" y2="50%" stroke="blue" stroke-width="1"/>
    <text text-anchor="middle" dominant-baseline="central" x="50%" y="50%">central</text> 
</svg>
<svg viewBox="0 0 48 48">
    <circle stroke="darkgray" stroke-width="1px" 
            fill="lightgray"  cx="50%" cy="50%" r="48%"/>
    <line x1="0" y1="50%" x2="100%" y2="50%" stroke="blue" stroke-width="1"/>
    <text text-anchor="middle" dominant-baseline="middle" x="50%" y="50%">middle</text> 
</svg>


-1

在SVG圆形中使文本居中非常容易。

<svg height="300" width="300">
      <circle cx="120" cy="120" r="30%" fill="#117da9" />
      <text x="50" y="120" fill="white">Center Text in SVG Circle</text>
</svg>

你所需要做的就是改变

不对。文本没有居中。试着只用一个单词。你做了一个巨大的假设,即文本永远不会改变,因此你可以硬编码x和y坐标。 - NickG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接