纯SVG方式适合文本框

Bem*_*mmu 55 svg

箱子大小已知.文本字符串长度未知.使文本适合框而不会破坏其纵横比.

在此输入图像描述

经过一天的谷歌搜索和阅读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>
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我知道SVG Scaling Text可以将容器文本拟合到框中

Rob*_*rto 40

我没有找到一种方法直接在没有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>
Run Code Online (Sandbox Code Playgroud)

在前面的示例文本增长到width == 500,但如果我使用的箱体尺寸width = 500height = 30,然后将文本增长,直到height == 30.

  • 或者简单地说...... textNode.setAttribute("transform","scale("+ value +")"); (7认同)
  • 快速注释 - scale属性也会影响当前项的坐标系,因此如果您希望元素处于相同位置,则需要将x和y位置除以标量以获得相同的相对位置 (4认同)
  • 或者更简单...将文本“font-size”设置为 1(在我们的例子中为“1em”);然后,一旦您有了比例因子(本答案中的“值”),只需为其设置“字体大小”即可。请参阅下面的示例。 (2认同)

col*_*sar 14

首先:只是看到答案没有准确地满足您的需求 - 它可能仍然是一个选项,所以我们走了:

你正确地观察到svg不直接支持自动换行.但是,您可能会受益foreignObject于用作xhtml片段包装器的元素,其中包装字可用.

看看这个自包含的演示(在线提供):

<?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>
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,但对自动换行不感兴趣。 (3认同)
  • @collapsar,您的演示链接已损坏 (2认同)

Izh*_*aki 5

我已经开发了@Roberto 的答案,但不是转换(缩放)textNode,我们只是:

  • 给它font-size1em开始与
  • 计算比例基于 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);
Run Code Online (Sandbox Code Playgroud)