将文本放入框中的纯 SVG 方法

盒子大小已知。文本字符串长度未知。在不破坏其长宽比的情况下将文本放入盒子。

enter image description here

经过一个晚上的谷歌和阅读 SVG 规范,我非常肯定,没有 JavaScript,这是不可能的。我所能得到的最接近的结果是使用 textLengthlengthAdjust文本属性,但这只能沿着一个轴拉伸文本。

<svg width="436" height="180"
style="border:solid 6px"
xmlns="http://www.w3.org/2000/svg">
<text y="50%" textLength="436" lengthAdjust="spacingAndGlyphs">UGLY TEXT</text>
</svg>

enter image description here

我知道 缩放文本以适应容器将文本放入框中

56464 次浏览

首先,我发现答案并不能精确地满足你的需求——它可能仍然是一个选项,所以我们开始吧:

您正确地观察到 svg 不支持直接进行字包装。但是,您可以利用 foreignObject元素作为 xhtml 片段的包装器,其中可以使用字包装。

看看这个独立的演示(Rel = “ nofollow noReferrer”> online 可用 < a href = “ http://stack.lapsar.bplaceed.net/data/so/svg/so. 15430189.svg”rel = “ nofollow noReferrer”> 在线 ) :

<?xml version="1.0" encoding="utf-8"?>
<!-- SO: http://stackoverflow.com/questions/15430189/pure-svg-way-to-fit-text-to-a-box  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="20cm" height="20cm"
viewBox="0 0 500 500"
preserveAspectRatio="xMinYMin"
style="background-color:white; border: solid 1px black;"
>
<title>simulated wrapping in svg</title>
<desc>A foreignObject container</desc>


<!-- Text-Elemente -->
<foreignObject
x="100" y="100" width="200" height="150"
transform="translate(0,0)"
>
<xhtml:div style="display: table; height: 150px; overflow: hidden;">
<xhtml:div style="display: table-cell; vertical-align: middle;">
<xhtml:div style="color:black; text-align:center;">Demo test that is supposed to be word-wrapped somewhere along the line to show that it is indeed possible to simulate ordinary text containers in svg.</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>


<rect x="100" y="100" width="200" height="150" fill="transparent" stroke="red" stroke-width="3"/>
</svg>

我没有找到一种没有 Javascript 的直接方法,但是我找到了一个非常简单的 JS 解决方案,不需要 for 循环,也不需要修改字体大小,而且可以很好地适应所有维度,也就是说,文本可以增长到最短边的极限。

基本上,我使用 transform属性,计算所需大小和当前大小之间的正确比例。

这是密码:

<?xml version="1.0" encoding="UTF-8" ?>
<svg version="1.2" viewBox="0 0 1000 1000" width="1000" height="1000" xmlns="http://www.w3.org/2000/svg" >
<text id="t1" y="50" >MY UGLY TEXT</text>
<script type="application/ecmascript">


var width=500, height=500;


var textNode = document.getElementById("t1");
var bb = textNode.getBBox();
var widthTransform = width / bb.width;
var heightTransform = height / bb.height;
var value = widthTransform < heightTransform ? widthTransform : heightTransform;
textNode.setAttribute("transform", "matrix("+value+", 0, 0, "+value+", 0,0)");


</script>
</svg>

在前面的例子中,文本一直增长到 width == 500,但是如果我使用 width = 500height = 30的框大小,那么文本一直增长到 height == 30

我不认为这是解决你想做什么,但你可以使用 textLength 以百分比 ="100%"为全宽。

<svg width="436" height="180"
style="border:solid 6px"
xmlns="http://www.w3.org/2000/svg">
<text x="0%" y="50%" textLength="100%">blabla</text>
</svg>

您也可以添加 text-anchor="middle"和改变 x位置,以完全中心您的文本

这不会改变字体大小,你会有奇怪的空格字母间距..。

JSFIDDLE DEMO

我已经开发了@Roberto answer,但是我们没有转换(缩放) textNode,而是简单地:

  • 1emfont-size开始
  • 根据 getBBox计算刻度
  • font-size调到那个刻度

(你也可以使用 1px等)

下面是做到这一点的 React HOC:

import React from 'react';
import TextBox from './TextBox';


const AutoFitTextBox = TextBoxComponent =>
class extends React.Component {
constructor(props) {
super(props);
this.svgTextNode = React.createRef();
this.state = { scale: 1 };
}


componentDidMount() {
const { width, height } = this.props;
const textBBox = this.getTextBBox();
const widthScale = width / textBBox.width;
const heightScale = height / textBBox.height;
const scale = Math.min(widthScale, heightScale);


this.setState({ scale });
}


getTextBBox() {
const svgTextNode = this.svgTextNode.current;
return svgTextNode.getBBox();
}


render() {
const { scale } = this.state;
return (
<TextBoxComponent
forwardRef={this.svgTextNode}
fontSize={`${scale}em`}
{...this.props}
/>
);
}
};


export default AutoFitTextBox(TextBox);

这在2022年仍然是一个问题。在纯粹的可伸缩矢量图形中,没有定义边界和使文本缩放的方法。手动调整字体大小似乎仍然是唯一的解决方案,并且给出的示例有很多错误。有人想出一个干净的解决方案吗?从 svg 规范来看,似乎不存在纯解。

为了给我自己提供一些答案,这个资源是我所发现的最好的,它很粗糙,但是工作起来更稳定: 文字-故事书 | Fitrsvgtext-GitHub