【问题标题】:Fitting text into an SVG path将文本放入 SVG 路径
【发布时间】:2015-06-07 22:51:35
【问题描述】:

我有一个绘制球衣轮廓的 SVG 路径,我想将球员的姓氏放在该球衣的中心。此外,由于我会将不同长度的名称放入球衣中,因此我想让文本的大小动态缩放以适合球衣。

我能够通过一些涉及 getBoundingClientRect() 的数学运算使文本居中,但我正在努力解决文本的动态大小问题。起初看起来不错,但是当我调整屏幕大小时,文本大小与球衣的大小不成比例。

我在下面包含了一个代码 sn-p 来演示。请帮助我理解为什么会出现这个大小问题,以及我可以做些什么来实现正确的文本大小调整。

编辑:我现在有足够的声望点来添加图像(哇!),所以这里有一些图片来演示我所指的调整大小问题。当我放大/缩小时,文本不会与球衣尺寸成比例缩放。但是,如果我在放大/缩小后刷新页面,即我从放大/缩小版本开始,文本大小会重新调整为当前球衣尺寸并根据需要适合球衣。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Jersey</title>
</head>

<body>
  <svg id="jersey">
    <switch>
      <g>
        <g id="jerseyShape">
          <path id="outline" fill="green" transform="translate(-40,0)" opacity="0.35" fill="none" stroke="#000000" stroke-width="1.5" d="M116.462,113.911V39.01
                           c0,0-18.493-5.977-15.317-30.633c0,0-8.033-2.616-8.78-3.363S91.617,9.311,79.29,9.124h-1.305
                           C65.656,9.311,65.656,4.268,64.909,5.015s-8.778,3.363-8.778,3.363C59.305,33.034,40.813,39.01,40.813,39.01v74.901
                           C40.813,113.911,74.434,126.427,116.462,113.911z" />
        </g>
        <g id="jerseyContent">
          <svg>
            <text id="name" font-family="Verdana" text-anchor="middle" dominant-baseline="central">
              Jordan
            </text>
            <!-- Dynamically re-size name to fit jersey -->
            <script type="application/ecmascript">
              //Get path's bounding rectangle
              var pathNode = document.getElementById("outline");
              var pRect = pathNode.getBoundingClientRect();

              //Get text's bounding rectangle
              var textNode = document.getElementById("name");
              var tRect = textNode.getBBox();

              //Calculate the necessary scale to make the text fit within the jersey width while
              //not exceeding a height of 30
              var widthRatio = (pRect.width * 0.85) / tRect.width;
              var heightRatio = (pRect.height*0.3) / tRect.height;
              var textScale = Math.min(widthRatio, heightRatio);

              //Translate text to center of jersey and scale to fit
              textNode.setAttribute("transform", "translate(" + (1 + pRect.width / 2) + " " + (pRect.top + pRect.height / 2) + ")scale(" + textScale + ")");
            </script>
          </svg>
        </g>
      </g>
    </switch>
  </svg>
</body>

</html>

【问题讨论】:

  • 我无法使用您的代码让球衣随窗口调整大小。
  • 什么浏览器?最新的 Chrome/Windows 似乎没问题
  • 感谢 Michael 的提问,我很尴尬地说我还没有测试过不同的浏览器(对于 Web 开发人员来说还是个新手!)。你是对的,我在 Chrome 上看不到这个问题,我在 Firefox 上也看不到它(尽管 Firefox 似乎有一个完全不同的对齐问题)。我只看Safari。看到每个浏览器都有如此不同的行为,我有点惊讶/担心/沮丧——这势必会让事情变得困难!

标签: javascript html svg


【解决方案1】:

您还应该使用getBBox() 来获取路径的大小。这样,即使在缩放之后,尺寸也会在相同的坐标空间中。

【讨论】:

  • 感谢 Paul,我一定会深入了解 getBoundingClientRect() 和 getBBox() 之间的区别。但是对于网页缩放(即 ctrl+ 或 ctrl-)呢?当我执行网页缩放时,这些功能似乎都没有给我正确的缩放行为,即文本不会与球衣成比例地增长。看起来问题是网页缩放时函数不会重新计算,因为当我缩放然后刷新页面时,一切似乎都被重新计算并且缩放是完美的。这些函数可以在网页缩放后重新计算边界框吗?
【解决方案2】:

问题是因为您正在计算包​​含文本节点的组的比例。

我已经解决了你的问题,给出了整个 g 元素的比例,id=“full”

所以现在您可以更改 id="full" 上的比例值并获得所需的结果,而不会出现标签。 我已经更新了代码,使其考虑到放大缩小时的比例值(ctrl +/ ctrl -)

$(window).on("resize", function(){ 
  var scale = "scale("+window.devicePixelRatio+")"
  $("#full").attr("transform", scale)
  console.log($("#full").attr("transform"));
  
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8">
      <title>Jersey</title>
    </head>
    
    <body style="width:100%; height:100%">
      <svg style="    height: 602px;    width: 100%;">
          <g id="full" transform="scale(1)">
            <g id="jerseyShape" transform="translate(-40,0)">
              <path id="outline" fill="green" opacity="0.35" fill="none" stroke="#000000" stroke-width="1.5" d="M116.462,113.911V39.01
                               c0,0-18.493-5.977-15.317-30.633c0,0-8.033-2.616-8.78-3.363S91.617,9.311,79.29,9.124h-1.305
                               C65.656,9.311,65.656,4.268,64.909,5.015s-8.778,3.363-8.778,3.363C59.305,33.034,40.813,39.01,40.813,39.01v74.901
                               C40.813,113.911,74.434,126.427,116.462,113.911z" />
                <text id="name" transform="translate(80,80)" font-family="Verdana" text-anchor="middle" dominant-baseline="central">
                  Jordan
                </text>                           
            </g>
          </g>
      </svg>
    </body>
    
    </html>

【讨论】:

  • 感谢西里尔的回复。但是,当我运行 sn-p 时,它似乎有与以前相同的文本大小调整问题——当我放大时,文本溢出球衣的两侧。我错过了什么吗?还有,2.7这个比例值是从哪里来的?
  • 哦,现在我明白你的意思了。 2.7 当然是任意的,通过更改该值,球衣和文本将一起缩放。感谢您指出这一点,因为它对我也有帮助,但不能解决我原来的问题。我的意思是如果我放大(例如,实际上通过 ctrl+ 或 ctrl- 缩放网页,而不仅仅是缩放组),文本不会与球衣成比例地增长/缩小。 (另外,我特意包含了 textnode 的缩放逻辑,b/c 名称可以任意长,我需要将文本高度按比例缩小,以便全名适合球衣。)
  • 好的,我已经更新了我的代码。解决ctrl+和ctrl-。我相信它现在会解决你所有的问题:)
  • 感谢您的更新! Michael Mullany 对我最初的问题的评论让我意识到我的问题实际上是 Safari 特定的,所以你的代码在 Chrome 和 Firefox 中就像一个魅力,但如果你碰巧安装了 Safari,你可能会观察到文本缩放的行为很奇怪仍然。我意识到跨浏览器支持将是一个巨大的挑战,我最好还是专注于 Chrome 和 Firefox 的发展......
  • 哦,好的,safari 中的问题是 window.devicePixelRatio 始终为 1,因此缩放不起作用...:( 需要特殊处理才能获得 safari 上的像素比,这应该可以解决它。
猜你喜欢
  • 2012-06-15
  • 2020-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-08
  • 2011-10-11
  • 2019-06-08
  • 2011-12-06
相关资源
最近更新 更多