首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >具有固定宽度和自动高度的SVG文本的叠加实例

具有固定宽度和自动高度的SVG文本的叠加实例
EN

Stack Overflow用户
提问于 2022-08-16 12:26:32
回答 2查看 51关注 0票数 1

我希望创造一个文本效果,在其中的文本线自动缩放,以达到一个特定定义的宽度,与自动调整高度。

理想情况下,我可以将多个单词堆叠在一起,以实现与下面类似的视觉效果。

示例图像

对于SVG文本来说,这是可能的吗?它能通过纯CSS来完成吗?

EN

Stack Overflow用户

发布于 2022-08-16 18:40:16

很可能,您应该包括一些javaScript以获得所需的结果。

主要问题:

svg <text>元素没有类似于多行文本或行高的任何东西。因此,您需要将文本内容拆分为许多具有不同<tspan>偏移量的y元素,以模拟类似于HTML的内容。

此外,许多重要的属性还不能用css进行样式处理。最重要的是,xy是模拟直线高度的关键。

示例:模拟多行svg文本缩放字体大小到宽度

代码语言:javascript
运行
复制
let svg = document.querySelector('svg')
let svgPseudoP = document.querySelector('.svgPseudoP');
svgSplitTextLines(svgPseudoP)

//split newlines
function svgSplitTextLines(el) {
  let texts = el.querySelectorAll('text');
  for (let t = 0; t < texts.length; t++) {
    let text0 = texts[t];
    let [x0, y0] = [text0.getAttribute('x'), text0.getAttribute('y')];

    //trim empty elements and whitespace
    let lines = text0.innerHTML.split(/\r?\n/);
    lines = lines.map((str) => {
      return str.trim()
    }).filter(Boolean)

    //set first line as textContent
    text0.textContent = lines[0];

    // calculate proportions
    let width0 = text0.getComputedTextLength();
    let style0 = window.getComputedStyle(text0);
    let fontSize0 = parseFloat(style0.getPropertyValue('font-size'));

    // ratio between capital letter height and font size
    let ascenderRatio = 0.71582;
    // define ideal leading
    let leading = fontSize0 * 0.2;

    for (let i = 1; i < lines.length; i++) {
      let str = lines[i];
      let tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
      tspan.textContent = str;
      tspan.setAttribute('x', x0);
      text0.appendChild(tspan);

      // scale font size according to width
      let width = tspan.getComputedTextLength();
      let scale = width0 / width;
      let newFontSize = parseFloat(fontSize0) * scale;
      tspan.setAttribute('style', 'font-size:' + newFontSize + 'px');

      // emulate line height by increasing  Y offset
      let tspanPrev = tspan.previousElementSibling;
      let yPrev = tspanPrev ? +tspanPrev.getAttribute('y') : +text0.getAttribute('y');

      let newY = yPrev + (newFontSize * ascenderRatio)
      tspan.setAttribute('y', newY + leading);
    }
  }
}
代码语言:javascript
运行
复制
svg {
  width: 50%;
  border: 1px solid #ccc;
}

text {
  font-family: Arial;
  font-weight: bold;
  text-anchor: middle;
  text-transform: uppercase;
}
代码语言:javascript
运行
复制
<svg class="svgPseudoP" viewBox="0 0 100 100">
        <text x="50%" y="20" font-size="10">
            Example
            Text
            Goes here
        </text>
        <text x="25%" y="60" font-size="8">
            Example2
            Text
            Goes 
            here
        </text>
    </svg>

本质上需要以下步骤:

text.getComputedTextLength()

  • scale
  • 设置了所有行应该得到的线宽(例如,这可以是第一个行/文本元素),
  • 通过字体大小获得每一行的宽度:

let scale = widthIdeal / widthCurrentLine;

let newFontSize = fontSizeFirst * scale

  • calculate线高/前导

这将需要获得大写字母高度与字体em正方形之间的比率,否则字体大小较大的行将比较小的行增加更大的边距。

例如,在inkscape、Illustrator等的100个点用Arial写一个大写,并将其转换为路径/轮廓,并检查它的高度: 71.582 pt

因此,资本与经济的平方比是:100/71.582 = 0.71582

这个值取决于实际的字体文件度量,因此没有标准化的大写字母高度。但是,对于许多字体家族来说,0.72-0.75的比值应该是可以接受的。

的例子:不均衡导致由于不理想的资本对em平方比。

上面的示例代码还将基于标记的新行拆分为<tspan>元素:

代码语言:javascript
运行
复制
<text x="50%" y="20" font-size="10">
    Example
    Text
    Goes here
</text>   

将改为:

代码语言:javascript
运行
复制
<text x="50%" y="20" font-size="10">
  Example
  <tspan x="50%" style="font-size:18.9px" y="35.5">Text</tspan>
  <tspan x="50%" style="font-size:8.1px" y="43.3">Goes here</tspan>
</text>
票数 1
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73373975

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档