如何在SVG矩形中放置和居中放置文本


177

我有以下矩形...

<rect x="0px" y="0px" width="60px" height="20px"/>

我想将“小说”一词放在其中。对于其他矩形,svg换行是否保留在其中?我似乎找不到关于在水平和垂直居中以及自动换行的形状中插入文本的任何具体信息。此外,文本不能离开矩形。

查看http://www.w3.org/TR/SVG/text.html#TextElement示例没有帮助,因为文本元素的x和y与矩形的x和y不同。文本元素似乎没有宽度和高度。我不确定这里的数学。

(我的html表只是无法使用。)


1
您能否使用文本锚和优势基准切换到答案?谢谢!
neaumusic

1
神经音乐,完成。8)
阿列那夫人

Answers:


304

在SVG中将文本水平和垂直居中的简单解决方案:

  1. 将文本的位置设置为要在其中居中的元素的绝对中心

    • 如果是父母,您可以这样做x="50%" y ="50%"
    • 如果它是另一个元素,x将是x该元素+一半的宽度(以及类似的y,但与高度)。
  2. 使用该text-anchor属性可以使文本水平居中,并具有以下值middle

    中间

    对齐渲染的字符,以使生成的渲染文本的几何中间位置位于初始当前文本位置。

  3. 使用dominant-baseline属性将文本与值垂直居中middle(或取决于您想要的样子,您可能想要这样做central

这是一个简单的演示:

<svg width="200" height="100">
  <rect x="0" y="0" width="200" height="100" stroke="red" stroke-width="3px" fill="white"/>
  <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle">TEXT</text>    
</svg>


1
我一直在到处寻找这种简单的解决方案-没有其他东西对我有用,我用它在径向进度栏中将数字居中
anthonytherockjohnson

7
就我而言,是工作的dominant-baseline财产,而不是alignment-baseline
pintoch

1
如果您要定期执行此操作,则还可以添加以下内容:<style type="text/css"><![CDATA[ text { alignment-baseline: middle; text-anchor:middle; } ]]></style>。感谢您的解决方案。
曼戈

1
运行您自己的代码段。没用 看看:它甚至在stackoverflow本身提供的预览中也不起作用。如前所述,dominant-baseline确实需要使用该评论。抱歉,这个答案有点令人误解。由于它似乎无法在Firefox或Chromium中运行,此外,您还必须研究注释以自行找到正确的解决方案,因此我自由地添加了另一个可以按预期工作的代码答案。(记录:在FF和Chromium上在Ubuntu Linux上进行了测试。)
里吉斯(Regis

2
@RegisMay感谢您指出。我在Chrome Mac和它工作得很好用alignment-baseline,但似乎它可能是一个古怪的事,因为审查的规格,它应该是dominant-baselinetext,和alignment-baselinetspantrefaltGlyph,和textPath。我相应地更新了答案。
阿尔瓦罗·蒙托罗

38

SVG 1.2 Tiny添加了文本换行,但是在浏览器中可以找到的大多数SVG实现(Opera除外)都没有实现此功能。开发人员通常要手动确定文本的位置。

SVG 1.1规范很好地概述了此限制以及克服该限制的可能解决方案:

每个“文本”元素都会导致呈现单个文本字符串。SVG不执行自动换行或自动换行。要获得多行文本的效果,请使用以下方法之一:

  • 作者或创作包需要预先计算换行符,并使用多个“文本”元素(每行文本一个)。
  • 作者或创作包需要预先计算换行符,并使用单个“ text”元素和一个或多个“ tspan”子元素,并为属性“ x”,“ y”,“ dx”和“ dy”使用适当的值为那些开始换行的字符设置新的开始位置。(此方法允许跨多行文本选择用户文本-请参阅文本选择和剪贴板操作。)
  • 表示要在另一个XML名称空间中呈现的文本,例如XHTML [XHTML]内嵌在'foreignObject'元素中。(注意:此方法的确切语义目前尚未完全定义。)

http://www.w3.org/TR/SVG11/text.html#Introduction

作为原始语言,可以使用dy属性和tspan元素来模拟文本换行,并且如规范中所述,某些工具可以实现此功能。例如,在Inkscape中,选择所需的形状和所需的文本,然后使用“文本”->“流入框架”。这样,您就可以使用换行符来编写文本,换行符将根据形状的边界进行换行。另外,请确保遵循以下指示,以告诉Inkscape保持与SVG 1.1的兼容性:http : //wiki.inkscape.org/wiki/index.php/FAQ#What_about_flowed_text.3F

此外,还有一些JavaScript库可用于动态自动执行文本换行:http : //www.carto.net/papers/svg/textFlow/

有趣的是,注意到CSVG将形状包装到文本元素的解决方案(例如,请参见其“按钮”示例),尽管重要的是要提到它们的实现在浏览器中不可用:http : //www.csse.monash.edu .au /〜clm / csvg / about.html

我之所以这样说是因为我已经开发了一个CSVG风格的库,尽管我尚未发布它,但它允许您做类似的事情并且可以在Web浏览器中工作。


感谢您的答复。看来我那时将不得不转储svg。开发人员应该想到的第一件事就是将文本(按用户期望的格式)附加到形状上!我将等到他们团结一致,然后再采取行动。我将尝试在Windows Paint中重绘它,看看是否能做到。(如果只有我可以让浏览器正确显示该表。)
Lady Aleena

关于svg中的可编辑文本,Opera支持SVG 1.2 Tiny中的editable属性,只需将属性添加editable="true"到text或textArea元素即可获得可编辑文本。
ErikDahlström

2
@ Erik,Opera再次领先。
jbeard4 2011年

@Lale Aleena,为什么不只使用我指导过的Inkscape解决方案?如果只是静态图像(例如,没有动态行为,没有动态更新文本内容),那么这应该可以正常工作。另外,它可以扩展,而Paint则不能,因为Paint可以生成光栅图形。最后,我不相信Paint支持任何级别的文本换行。
jbeard4 2011年

@ echo-flow很久以前,因为我使用(然后转储了)Microsoft Front Page生成html,所以我对代码生成程序失去了所有信任。我总是对程序添加自己的专有代码到我正在编写的程序中保持警惕。头版真的弄乱了我的html。如果您是Inkscape用户,能否告诉我Inkscape是否将自己的专有代码放在svg创建后必须进入并剥离的svg中?
Lady Aleena

22

使用圆角或stroke-width大于1 时,先前的答案给出的结果不佳。例如,您希望以下代码生成一个圆角矩形,但是拐角被父svg组件剪切:

<svg width="200" height="100">
  <!--this rect should have rounded corners-->
  <rect x="0" y="0" rx="5" ry="5" width="200" height="100" stroke="red" stroke-width="10px" fill="white"/>
  <text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">CLIPPED BORDER</text>    
</svg>

相反,我建议将包裹在textsvg,然后将new svg和the rect一起嵌套在一个g元素中,如以下示例所示:

<!--the outer svg here-->
<svg width="400px" height="300px">

  <!--the rect/text group-->
  <g transform="translate(50,50)">
    <rect rx="5" ry="5" width="200" height="100" stroke="green" fill="none" stroke-width="10"/>
    <svg width="200px" height="100px">
      <text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">CORRECT BORDER</text>      
    </svg>
  </g>

  <!--rest of the image's code-->
</svg>

这样可以解决上述答案中出现的削波问题。我还使用该transform="translate(x,y)"属性翻译了rect / text组,以证明这为在屏幕上定位rect / text提供了一种更直观的方法。


15

如果您以编程方式创建SVG,则可以对其进行简化并执行以下操作:

  <g>
      <rect x={x} y={y} width={width} height={height} />
      <text
          x={x + width / 2}
          y={y + height / 2}
          dominant-baseline="middle"
          text-anchor="middle"
      >
          {label}
      </text>
  </g>

3
Shouldsn't它是dominant-baselinetext-anchor,不dominantBaselinetextAnchor
纳撒尼尔·比弗

1
@ NathanielM.Beaver是的,应该。接得好。上面的代码来自React,不幸的是,需要使用camelCase重命名属性。
布伦南·张

12

您可以直接使用text-anchor = "middle"属性。我建议在矩形和文本上创建一个包装器svg元素。这样,您可以使用一个CSS选择器来使用整个元素。确保将文本的“ x”和“ y”属性放置为50%。

    <svg class="svg-rect" width="50" height="40">
        <rect x="0" y="0" rx="3" ry="3" width="50" height="40" fill="#e7e7e7"></rect>
        <text x="50%" y="50%" text-anchor="middle" stroke="black" stroke-width="1px" dy=".3em">N/A</text>
    </svg>


7

完整细节博客:http : //blog.techhysahil.com/svg/how-to-center-text-in-svg-shapes/

<svg width="600" height="600">
  <!--   Circle -->
  <g transform="translate(50,40)">
    <circle cx="0" cy="0" r="35" stroke="#aaa" stroke-width="2" fill="#fff"></circle>
    <text x="0" y="0" alignment-baseline="middle" font-size="12" stroke-width="0" stroke="#000" text-anchor="middle">HueLink</text>
  </g>
  
  <!--   In Rectangle text position needs to be given half of width and height of rectangle respectively -->
  <!--   Rectangle -->
  <g transform="translate(150,20)">
    <rect width="150" height="40" stroke="#aaa" stroke-width="2" fill="#fff"></rect>
    <text x="75" y="20" alignment-baseline="middle" font-size="12" stroke-width="0" stroke="#000" text-anchor="middle">HueLink</text>
  </g>
  
  <!--   Rectangle -->
  <g transform="translate(120,140)">
    <ellipse cx="0" cy="0" rx="100" ry="50" stroke="#aaa" stroke-width="2" fill="#fff"></ellipse>
    <text x="0" y="0" alignment-baseline="middle" font-size="12" stroke-width="0" stroke="#000" text-anchor="middle">HueLink</text>
  </g>
  
  
</svg>


其他解决方案不在Firefox中。 codepen.io/anon/pen/oEByYr
tgf

我在Firefox 58.0.1(64位)上进行了测试,可以正常工作。您能提到它无法为您解决的版本吗?
萨希尔·古普塔

Firefox 58.0.2 64位。文本比应有的略高。刚开始时可能不太容易注意到它,但是如果您的包装盒非常合适,则更加明显。尝试降低高度。
tgf

6

alignment-baseline不是在此处使用的正确属性。正确的答案是使用组合dominant-baseline="central"text-anchor="middle"

<svg width="200" height="100">
    <g>
        <rect x="0" y="0" width="200" height="100" style="stroke:red; stroke-width:3px; fill:white;"/>
        <text x="50%" y="50%" style="dominant-baseline:central; text-anchor:middle; font-size:40px;">TEXT</text>
    </g>
</svg>


2

在矩形内插入文本的一种方法是在rect对象内插入异物,这是DIV。

这样,文本将显示DIV的限制。

var g = d3.select("svg");
					
g.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width","100%")
.attr("height","100%")
.attr("fill","#000");


var fo = g.append("foreignObject")
 .attr("width","100%");

fo.append("xhtml:div")
  .attr("style","width:80%;color:#FFF;margin-right: auto;margin-left: auto;margin-top:40px")
  .text("Mussum Ipsum, cacilds vidis litro abertis Mussum Ipsum, cacilds vidis litro abertis Mussum Ipsum, cacilds vidis litro abertis");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.js"></script>
<svg width="200" height="200"></svg>


1

我有时会花时间在SVG上获取任何东西,所以我推出了自己的小功能。希望它能对您有所帮助。请注意,它仅适用于SVG元素。

function centerinparent(element) { //only works for SVG elements
    var bbox = element.getBBox();
    var parentwidth = element.parentNode.width.baseVal.value;
    var parentheight = element.parentNode.height.baseVal.value;
    var newwidth = ((parentwidth / 2) - (bbox.width / 2)) - 2; //i start everything off by 2 to account for line thickness
    var newheight = ((parentheight / 2) - (bbox.height / 2)) - 2;
    //need to adjust for line thickness??

    if (element.classList.contains("textclass")) { //text is origined from bottom left, whereas everything else origin is top left
        newheight += bbox.height; //move it down by its height
    }

    element.setAttributeNS(null, "transform", "translate(" + newwidth + "," + newheight + ")");
    // console.log("centering BOXES:  between width:"+element.parentNode.width.baseVal.value + "   height:"+parentheight);
    // console.log(bbox);
}

1

为了使图形中的文本水平和垂直对齐,您可能需要使用以下CSS样式。特别要注意,这dominant-baseline:middle可能是错误的,因为(通常)这是在顶部和基线之间的一半,而不是在顶部和底部之间的一半。另外,某些来源(例如Mozilla)使用dominant-baseline:hanging代替 dominant-baseline:text-before-edge。这也可能是错误的,因为 hanging它是为印度脚本设计的。当然,如果您混合使用拉丁文,印度文,表意文字或其他任何文字,则可能需要阅读文档

/* Horizontal alignment */
text.goesleft{text-anchor:end}
text.equalleftright{text-anchor:middle}
text.goesright{text-anchor:start}
/* Vertical alignment */
text.goesup{dominant-baseline:text-after-edge}
text.equalupdown{dominant-baseline:central}
text.goesdown{dominant-baseline:text-before-edge}
text.ruledpaper{dominant-baseline:alphabetic}

编辑:我刚刚注意到Mozilla也使用了dominant-baseline:baseline这绝对是错误的:它甚至不是公认的价值!我认为它是默认的字体默认值,即alphabetic,所以他们很幸运。

更多编辑:Safari(11.1.2)可以,text-before-edge但不能text-after-edge。它也会失败ideographic。很棒的东西,苹果。因此,您可能最终被迫使用alphabetic并允许使用后代。抱歉。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.