我有如下矩形:

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

我想把"虚构"这个词放在中间。对于其他矩形,SVG换行是否保持在其中?我似乎找不到任何关于在水平和垂直居中的形状和换行中插入文本的具体内容。此外,文本不能离开矩形。

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

(我的HTML表就是不能工作。)


当前回答

SVG 1.2 Tiny添加了文本换行,但是您在浏览器中看到的大多数SVG实现(Opera除外)都没有实现这个特性。这通常取决于您(开发人员)手动定位文本。

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

Each ‘text’ element causes a single string of text to be rendered. SVG performs no automatic line breaking or word wrapping. To achieve the effect of multiple lines of text, use one of the following methods: The author or authoring package needs to pre-compute the line breaks and use multiple ‘text’ elements (one for each line of text). The author or authoring package needs to pre-compute the line breaks and use a single ‘text’ element with one or more ‘tspan’ child elements with appropriate values for attributes ‘x’, ‘y’, ‘dx’ and ‘dy’ to set new start positions for those characters who start new lines. (This approach allows user text selection across multiple lines of text -- see Text selection and clipboard operations.) Express the text to be rendered in another XML namespace such as XHTML [XHTML] embedded inline within a ‘foreignObject’ element. (Note: the exact semantics of this approach are not completely defined at this time.)

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

As a primitive, text wrapping can be simulated by using the dy attribute and tspan elements, and as mentioned in the spec, some tools can automate this. For example, in Inkscape, select the shape you want, and the text you want, and use Text -> Flow into Frame. This will allow you to write your text, with wrapping, which will wrap based on the bounds of the shape. Also, make sure you follow these instructions to tell Inkscape to maintain compatibility with SVG 1.1: https://wiki.inkscape.org/wiki/Frequently_asked_questions#What_about_flowed_text.3F

此外,还有一些JavaScript库可以用来动态自动化文本包装: https://old.carto.net/papers/svg/textFlow/

值得注意的是,CSVG将形状包装到文本元素的解决方案(例如,参见他们的“按钮”示例),尽管重要的是要提到他们的实现在浏览器中不可用: https://users.monash.edu/~clm/csvg/about.html

我提到这一点是因为我已经开发了一个csvg启发的库,它允许您做类似的事情,并且可以在web浏览器中工作,尽管我还没有发布它。

其他回答

之前的答案在使用圆角或描边宽度为>1时给出的结果很差。例如,你会期望下面的代码生成一个圆角矩形,但是角是由父svg组件剪辑的:

<svg width="200" height="100"> <!——这个矩形应该有圆角——> <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%" align -baseline="middle" text-anchor="middle"> clip BORDER</text> < / svg >

相反,我建议将文本包装在svg中,然后将新的svg和rect嵌套在g元素中,如下例所示:

< !——这里的外部SVG——> <svg width="400px" height="300px"> < !——矩形/文本组——> < g变换= "翻译(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%" align -baseline="middle" text-anchor="middle">正确的BORDER</text> < / svg > < / g > < !——图像的其余代码——> < / svg >

这修复了上面的答案中出现的剪辑问题。我还使用transform="translate(x,y)"属性翻译了rect/text组,以演示这提供了一种更直观的方法来在屏幕上定位rect/text。

我花了很长时间使用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);
}

如果你是用编程的方式创建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>

你可以直接使用text-anchor = "middle"属性。我建议在矩形和文本上创建一个包装器svg元素。这样你就可以使用一个css选择器来使用整个元素。确保你把'x'和'y'属性的文本为50%。

<svg class="svg-rect" width="50" height="40"> <矩形x = " 0 " y = " 0 " rx = =“3”变化中“3”宽度=“50”高度=“40”填补= " # e7e7e7 " > < /矩形> <text x="50%" y="50%" text-anchor="middle" stroke="black" stroke-width="1px" dy=".3em"> </text> . < / svg >

Full detail blog: https://web.archive.org/web/20180717015233/http://blog.techhysahil.com:80/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>