已知箱子大小。文本字符串长度未知。使文本适合框而不会破坏其宽高比。
经过一天的谷歌搜索和阅读SVG规范后,我很确定没有javascript就不可能。我能得到的最接近的是使用textLength和lengthAdjust文本属性,但这只是沿着一个轴拉伸文本。
<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>
我知道SVG Scaling Text to fit container和fitting text into the box
答案 0 :(得分:37)
我没有找到一种方法直接在没有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 = 500
和height = 30
,则文字会一直增长到height == 30
。< / p>
答案 1 :(得分:13)
首先:只是看到答案没有准确地满足您的需求 - 它可能仍然是一个选项,所以我们走了:
你正确地观察到svg不直接支持自动换行。但是,您可能会受益于foreignObject
元素作为xhtml片段的包装器,其中可以使用自动换行。
看看这个自包含的演示(可用online):
<?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>
答案 2 :(得分:2)
我已经开发了@Roberto回答,但我们只是简单地转换(缩放)textNode:
font-size
1em
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);
答案 3 :(得分:0)
我不认为它是您想要做的解决方案,但您可以使用textlenght
全长的百分比="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>
您还可以添加textanchor="middle"
并更改x
位置,使文字完美居中
这不会改变fontsize,你会有奇怪的空格字母间距......