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

时间:2011-04-05 02:00:26

标签: text svg

我有以下矩形...

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

我想把“小说”这个词放在其中。对于其他矩形,svg自动换行保留在其中吗?我似乎无法找到任何具体的关于在水平和垂直居中以及自动换行的形状中插入文本的内容。此外,文本不能离开矩形。

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

(我的html表格不起作用。)

10 个答案:

答案 0 :(得分:168)

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

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

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

      

    <强>中间

         

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

  3. 使用dominant-baseline属性将文本垂直居中,并带有值middle(或者根据您希望的样子,您可能希望central

  4. 这是一个简单的演示:

    <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 :(得分:37)

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

SVG 1.1规范提供了对此限制的良好概述,以及克服它的可能解决方案:

  

每个'text'元素都会导致单个元素   要呈现的文本字符串。 SVG   不执行自动换行或   自动换行。达到效果   多行文本,使用其中之一   以下方法:

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

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

作为原语,可以使用dy属性和tspan元素模拟文本换行,并且如规范中所述,某些工具可以自动执行此操作。例如,在Inkscape中,选择所需的形状和所需的文本,然后使用文本 - &gt;流入框架。这将允许您使用包装来编写文本,这将根据形状的边界进行换行。此外,请确保按照这些说明告诉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启发的库,允许你做类似的事情,并且可以在网络浏览器中工作,虽然我还没有发布它。

答案 2 :(得分:18)

以前的答案在使用圆角或stroke-width使用&gt; 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>

相反,我建议将text包裹在svg中,然后将新svgrect嵌套在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。

答案 3 :(得分:9)

您可以直接使用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>

答案 4 :(得分:6)

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

# partially disable webrtc
preferences = {
    "webrtc.ip_handling_policy" : "disable_non_proxied_udp",
    "webrtc.multiple_routes_enabled": False,
    "webrtc.nonproxied_udp_enabled" : False
}
chrome_options.add_experimental_option("prefs", preferences)

答案 5 :(得分:5)

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

&#13;
&#13;
{{1}}
&#13;
&#13;
&#13;

答案 6 :(得分:2)

在矩形内插入文本的一种方法是在rect对象中插入一个外来对象,它是一个DIV。

这样,文本将取代DIV的限制。

&#13;
&#13;
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");
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.js"></script>
<svg width="200" height="200"></svg>
&#13;
&#13;
&#13;

答案 7 :(得分:2)

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>

答案 8 :(得分:1)

我有一个时间使用SVG集中任务的bugger,所以我推出了自己的小功能。希望它能帮助你。请注意,它仅适用于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);
}

答案 9 :(得分:0)

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

/* 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并毕竟允许后代。抱歉。