【问题标题】:Controlled Multi - Rotation of SVG text elements受控多轮旋转 SVG 文本元素
【发布时间】:2021-06-26 22:48:26
【问题描述】:

我真的很难理解<text> 元素应该如何在<svg> 中以可控方式旋转。具体例子在这里:

<svg version="1.1" baseProfile="full" viewBox="0 0 1000 200" xmlns="http://www.w3.org/2000/svg" id="timeline-container">
  <line x1="11" x2="200" y1="11" y2="142.2" stroke="black"/>
  <line x1="200" x2="400" y1="142.2" y2="121" stroke="black"/>
  <line x1="400" x2="600" y1="121" y2="167.6" stroke="black"/>
  <line x1="600" x2="989" y1="167.6" y2="11" stroke="black"/>
  <rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="11" y="11" transform="translate(-10,-10)"/>
  <text text-anchor="end" x="17" y="32" transform="rotate(-90,17,32)" class="label-below-project-point" >abcdef</text>
  <rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="200" y="142.2" transform="translate(-10,-10)"/>
  <text x="206" y="121.2" transform="rotate(-90,206,121.2)" class="label-above-project-point" >abc</text>
  <rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="400" y="121" transform="translate(-10,-10)"/>
  <text x="406" y="100" transform="rotate(-90,406,100)" class="label-above-project-point" >abcdefghijklmnopq</text>
  <rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="600" y="167.6" transform="translate(-10,-10)"/>
  <text x="606" y="146.6" transform="rotate(-90,606,146.6)" class="label-above-project-point" >abcdefg</text>
  <rect stroke="black" stroke-width="2" fill="white" width="20" height="20" x="989" y="11" transform="translate(-10,-10)"/>
  <text text-anchor="end" x="995" y="32" transform="rotate(-90,995,32)" class="label-below-project-point" >abcdefghijklmnopqrstuvwxy</text>
</svg>

当用户单击其中一个矩形时间轴点时,我想将文本元素旋转 90 度以水平显示它们,并将标签与其所指的时间轴矩形对齐。 更准确地说:

  • 当点击最左边的时间线点时,标签会旋转90度以水平显示+左对齐最左边矩形的左边框。

  • 对于最右边的点,首先旋转 90 度以产生水平显示,然后将文本元素与最右边矩形的右边框右对齐。

  • 对于所有中间点,也先旋转 90° 以进行水平显示,然后将文本相对于相应时间线点的中心居中对齐。

&lt;text&gt; 元素是使用提供的文本标签以编程方式生成的,因此它们可以包含 1 到 30 个字符之间的任意数字;导致可变的宽度和高度。

示例

旋转永远不会像我期望的那样。例如,当我尝试通过将旋转原点设置为左下角并将旋转角度设置为 90 来旋转最左边的 &lt;text&gt; 元素时,&lt;text&gt; 元素会在 svg 的顶部边框顶部旋转.不知道为什么。重现它:

  • getBBox() 应用于文本元素以获取其宽度W
  • W + text 元素的y 属性的值相加得到最左侧文本元素左下角的y 坐标; Y
  • 将相应的旋转命令:rotate(90,0,Y) 添加到最左侧文本元素的transform 元素中,您会得到:
  • transform="rotate(-90,17,32) rotate(90,0,Y)。旋转完全不像您预期​​的那样...

示例 2

我误会了什么?让我也用@Danny '365CSI' Engelman 提供的 sn-p 来说明我的问题:

<style>
  svg   { height: 180px }
  circle{ r:2px; fill:red }
</style>

<svg id=SVG viewbox="0 0 100 100">
  <rect width="100%" height="100%" fill="pink"></rect>

  <circle cx="25" cy="50"></circle>
  <text    x="25"  y="50" text-anchor="start" 
           transform="rotate(-90 25 50)">Hello</text>

  <circle cx="50" cy="50"></circle>
  <text    x="50"  y="50" text-anchor="end" dominant-baseline="hanging" 
           transform="rotate(90 50 50)">SVG</text>

  <circle cx="75" cy="50"></circle>
  <text    x="75"  y="50" text-anchor="middle" dominant-baseline="middle" 
           transform="rotate(-45 75 50)">World</text>
</svg>

假设我现在想将“Hello”文本元素旋转 90 度以使其水平显示,其旋转原点位于文本元素的中心。因此,我首先按如下方式计算文本元素的中心:

  1. 使用document.getElementsByTagName("text")[0].getBBox(); 获取相关元素的尺寸。这将返回一个高度为 16.38888931274414 SVG 单位、宽度为 36.10185241699219 SVG 单位的 SVG 矩形。

  2. 我现在计算文本元素中心的坐标,如下所示:

x = 25 - 16.38888931274414 / 2 = 大约16.81

y = 50 - 36.10185241699219 / 2 = 大约。 31.95

  1. 我现在将rotate(90 16.81 31.95) 添加到transform 属性中,然后完全无法按预期获得文本元素的90° 旋转;如您在此处所见:

<style>
  svg   { height: 180px }
  circle{ r:2px; fill:red }
</style>

<svg id=SVG viewbox="0 0 100 100">
  <rect width="100%" height="100%" fill="pink"></rect>

  <circle cx="25" cy="50"></circle>
  <text    x="25"  y="50" text-anchor="start" 
           transform="rotate(-90 25 50) rotate(90 16.81 31.95)">Hello</text>

  <circle cx="50" cy="50"></circle>
  <text    x="50"  y="50" text-anchor="end" dominant-baseline="hanging" 
           transform="rotate(90 50 50)">SVG</text>

  <circle cx="75" cy="50"></circle>
  <text    x="75"  y="50" text-anchor="middle" dominant-baseline="middle" 
           transform="rotate(-45 75 50)">World</text>
</svg>

我在这里不明白什么/如何计算旋转中心+从而正确预测旋转?????????

【问题讨论】:

  • 如果你想垂直显示文本,使用写作模式和文本方向有一个更简单的方法。否则,它取决于文本是如何垂直旋转的。 IE。提供一个minimal reproducible example,以您要旋转的方向显示它。
  • 尽量简化问题和我sn-p的代码。任何线索@RobertLongson?

标签: html css svg rotation transform


【解决方案1】:

旋转还取决于text-anchor 和其他文本定位属性。

但要注意;转换转换 BBox,
所以:hover 作用于文本所在的位置

另见:SVG textpath, determine when text goes beyond the path

游乐场:

<style>
  svg   { height: 180px }
  circle{ r:2px; fill:red }
  text:hover{ transform:rotate(0)}
</style>

<svg id=SVG viewbox="0 0 100 100">
  <rect width="100%" height="100%" fill="pink"></rect>

  <circle cx="25" cy="50"></circle>
  <text    x="25"  y="50" text-anchor="start" 
           transform="rotate(-90 25 50)">Hello</text>

  <circle cx="50" cy="50"></circle>
  <text    x="50"  y="50" text-anchor="end" dominant-baseline="hanging" 
           transform="rotate(90 50 50)">SVG</text>

  <circle cx="75" cy="50"></circle>
  <text    x="75"  y="50" text-anchor="middle" dominant-baseline="middle" 
           transform="rotate(-45 75 50)">World</text>
</svg>

【讨论】:

  • 那么这种方法的工作条件是专门使用文本锚来实现我想要进行的旋转功能?例如,您将如何放置第一个时间线点的标签?这样它就出现在我的 sn-p 中的垂直方向上的固定距离处,考虑到文本的宽度可能在 1-30 个字符之间变化,因此需要“开始”的文本锚点?我看到的唯一解决方案是使用getComputedTextLength() 等进行计算;但我更喜欢整个服务器端计算的解决方案。有什么想法吗?
  • 一个完整的服务器端计算解决方案,包括图形在内。标签已准备好在页面加载时显示,无需任何额外的计算+需要通过 js 进行标签的移动,这将在页面加载时对用户可见(隐藏它们不是一种选择)..
  • 等等,这实际上意味着,即使你在rotate()中指定了一个旋转原点,它仍然是根据text-anchor进行旋转的坐标?
  • 将代码复制到 JSFiddle 或 CodePen 或...并使用它
【解决方案2】:

好的,知道了!主要感谢this。实际上,当您在 SVG 元素上执行两个后续 rotate() 变换时,您始终需要在应用任何变换之前参考原始坐标,即使对于后续旋转也是如此。因此,按预期旋转“Hello”元素的分步方法(请参阅我的问题,示例 2):

状态:

<style>
  svg   { height: 180px }
  circle{ r:2px; fill:red }
</style>

<svg id=SVG viewbox="0 0 100 100">
  <rect width="100%" height="100%" fill="pink"></rect>

  <circle cx="25" cy="50"></circle>
  <text    x="25"  y="50" text-anchor="start" 
           transform="rotate(-90 25 50)">Hello</text>

  <circle cx="50" cy="50"></circle>
  <text    x="50"  y="50" text-anchor="end" dominant-baseline="hanging" 
           transform="rotate(90 50 50)">SVG</text>

  <circle cx="75" cy="50"></circle>
  <text    x="75"  y="50" text-anchor="middle" dominant-baseline="middle" 
           transform="rotate(-45 75 50)">World</text>
</svg>

上面的方法是正确的,但是我应用到了“Hello”元素的错误状态。为了让旋转原点成为它的中心,你实际上必须回想那个元素的原始状态; = 应用任何旋转之前的状态,所以:

原始状态:

<style>
  svg   { height: 180px }
  circle{ r:2px; fill:red }
</style>

<svg id=SVG viewbox="0 0 100 100">
  <rect width="100%" height="100%" fill="pink"></rect>

  <circle cx="25" cy="50"></circle>
  <text    x="25"  y="50" text-anchor="start">Hello</text>

  <circle cx="50" cy="50"></circle>
  <text    x="50"  y="50" text-anchor="end" dominant-baseline="hanging" 
           transform="rotate(90 50 50)">SVG</text>

  <circle cx="75" cy="50"></circle>
  <text    x="75"  y="50" text-anchor="middle" dominant-baseline="middle" 
           transform="rotate(-45 75 50)">World</text>
</svg>

现在,按照我的问题中描述的完全相同的方法,计算“Hello”元素的中心点的坐标,使用:

document.getElementsByTagName("text")[0].getBBox()

哪个给你宽度和高度:

  • 宽度:36.10185241699219
  • 身高:16.38888931274414

现在,根据“Hello”元素的初始状态,计算中心的坐标:

  • x = x 偏移 + 宽度 / 2 = 大约43.05
  • y = y 偏移 - 高度 / 2 = 大约41.81

现在您应用所需的旋转rotate(90 43.05 41.81),瞧:

<style>
  svg   { height: 180px }
  circle{ r:2px; fill:red }
</style>

<svg id=SVG viewbox="0 0 100 100">
  <rect width="100%" height="100%" fill="pink"></rect>

  <circle cx="25" cy="50"></circle>
  <text    x="25"  y="50" text-anchor="start" 
           transform="rotate(-90 25 50) rotate(90 43.05 41.81)">Hello</text>

  <circle cx="50" cy="50"></circle>
  <text    x="50"  y="50" text-anchor="end" dominant-baseline="hanging" 
           transform="rotate(90 50 50)">SVG</text>

  <circle cx="75" cy="50"></circle>
  <text    x="75"  y="50" text-anchor="middle" dominant-baseline="middle" 
           transform="rotate(-45 75 50)">World</text>
</svg>

【讨论】:

  • 这就是我在回答中所说的......注意:转换不会转换 BBox......你仍然不在那里......如果你设置了 @987654328 @位置不对。如果属性对旋转点有影响,那么你需要在你的旋转点计算中包含那些属性
  • 我的答案与我的问题中修改后的计算恰好对应于考虑文本的初始位置 - 我的计算中的锚点,我没有先做,因此我赞成你的答案。设置一个不同的文本锚然后说我考虑到start文本锚的计算是错误的,嗯......转换不转换BBox与实际问题无关,即旋转不会随之旋转旋转元素的 xy 系统。如果旋转元素的 x-y 系统的定义对你来说是 BBox,好吧,对我来说不是。
  • 无论如何,感谢您的帮助和解释以及说明性的 sn-ps,我的所有转换和多旋转现在都可以按照我的要求完美地工作,无论它们的文本锚点、方向、位置如何。等等。当然,在考虑所有旋转原点计算的文本锚位置时。
猜你喜欢
  • 2020-04-07
  • 2014-04-25
  • 2013-05-18
  • 2015-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-14
  • 2018-08-26
相关资源
最近更新 更多