为什么我无法围绕 SVG 中的给定点旋转路径 [英] Why am I failing to rotate a path around a given point in SVG

查看:70
本文介绍了为什么我无法围绕 SVG 中的给定点旋转路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们考虑

我现在想旋转指针,让时钟显示任意时间.

我已经确定时针是由这个 path 元素编码的:

我还确定双手交叉的中心圆是由这个ellipse元素编码的:

<椭圆cx="150.233"cy="151.011"rx="8.0819998"ry="8.125"id="ellipse542"sodipodi:cx="150.233"sodipodi:cy="151.011"sodipodi:rx="8.0819998"sodipodi:ry="8.125"style="fill:url(#radialGradient4393)"d =米158.315,151.011Ç0,4.48732 -3.61843,8.125 -8.082,8.125 -4.46356,0 -8.082,-8.082 -3.63768,-8.125 0,-4.48731 3.61844,-8.125 8.082,-8.125 4.46357,0 8.082,3.63769 8.082,8.125 z"/>

因为这个 ellipse 元素有属性 cx="150.233"cy="151.011" 我推断这个椭圆的中心位于point (150.233, 151.011) 并且,以合理的准确度,我可以假设两只手在这一点交叉,这是我应该旋转手的确切点.

因此,对于初学者来说,让我们尝试将小时时钟旋转 10°.

我不明白什么以及如何旋转这只手?

解决方案

SVG 使用坐标用户空间"的概念.如果一个元素有一个变换属性,它的属性中表达的坐标是指一个局部坐标系,用户空间,它是从它的父元素的坐标系转换而来的,就像transform代码> 属性描述.因此,它也不同于根 元素的坐标系.

当元素的父元素具有转换属性时,也会发生同样的情况:用户空间坐标系源自父元素,与根元素的坐标系不同.(建立视口"元素会变得更复杂,但让我们在这里跳过这个.)

您没有注意到的是,您为中心确定的椭圆有一个父 <g> 元素,其属性为 transform="scale(2.4444516,2.4444516)" 如果将 cx 和 cy 值与这些缩放因子相乘,您会得到

cx = 367.23729cy = 369.13908

这非常适合整个 SVG 的大小.它具有属性 width="734.47461" height="738.27081",如果将它们减半,则它们与椭圆的值仅相差无几.

检查手元素或其父元素的坐标系没有转换后,您现在可以将旋转设置为

transform="旋转(10 367.23729 369.13908)"

如果您继续使用 SVG,请阅读关于坐标系和变换的章节 在规范中当然是个好主意.

Let's consider this SVG file from Openclipart (link to raw SVG file). For reference, it looks like this:

I now want to rotate the hands so that I can make the clock show some arbitrary time.

I have determined that the hour hand is encoded by this path element:

<path
   d="m 458.13588,295.06406 c 1.74675,-16.11195 25.92429,-46.33386 37.207,-59.62773 l -0.0945,-0.0895 c -12.66188,11.97753 -41.49863,37.74816 -57.33149,40.35684 -30.58445,5.03466 -23.84883,26.09555 -19.57494,34.86553 l -52.97792,55.87976 6.16814,5.91214 53.02794,-55.93477 c 9.10302,3.92158 30.23513,9.51278 33.57547,-21.36261 z"
   id="path526"
   inkscape:connector-curvature="0"
   style="fill:url(#linearGradient4636);display:inline"
   inkscape:transform-center-y="-65.845483"
   sodipodi:nodetypes="cccccccccc"
   inkscape:transform-center-x="-63.497113" />

I have also determined that the central circle where both hands cross is encoded by this ellipse element:

<ellipse
     cx="150.233"
     cy="151.011"
     rx="8.0819998"
     ry="8.125"
     id="ellipse542"
     sodipodi:cx="150.233"
     sodipodi:cy="151.011"
     sodipodi:rx="8.0819998"
     sodipodi:ry="8.125"
     style="fill:url(#radialGradient4393)"
     d="m 158.315,151.011 c 0,4.48732 -3.61843,8.125 -8.082,8.125 -4.46356,0 -8.082,-3.63768 -8.082,-8.125 0,-4.48731 3.61844,-8.125 8.082,-8.125 4.46357,0 8.082,3.63769 8.082,8.125 z" />

Since this ellipse element has attributes cx="150.233" and cy="151.011" I reason that this ellipse's center is located at point (150.233, 151.011) and, with a reasonable accuracy, I can assume that both hands cross at this point and this is the exact point I should rotate the hands about.

So for starters let's try rotating the hour clock by, let's say, 10°. Having read the MDN documentation of the transform attribute I reason this can be done by adding the attribute transform="rotate(10 150.233 151.011)" to the aforementioned path element, obtaining the following code:

<path
   d="m 458.13588,295.06406 c 1.74675,-16.11195 25.92429,-46.33386 37.207,-59.62773 l -0.0945,-0.0895 c -12.66188,11.97753 -41.49863,37.74816 -57.33149,40.35684 -30.58445,5.03466 -23.84883,26.09555 -19.57494,34.86553 l -52.97792,55.87976 6.16814,5.91214 53.02794,-55.93477 c 9.10302,3.92158 30.23513,9.51278 33.57547,-21.36261 z"
   id="path526"
   inkscape:connector-curvature="0"
   style="fill:url(#linearGradient4636);display:inline"
   inkscape:transform-center-y="-65.845483"
   sodipodi:nodetypes="cccccccccc"
   inkscape:transform-center-x="-63.497113"
   transform="rotate(10 150.233 151.011)" />

Unfortunately, the results prove my assumption wrong:

What am I failing to understand and how to rotate this hand?

解决方案

SVG works with the notion of a "userspace" for coordinates. If an element has a transform attribute, the coordinates expressed in its attributes refer to a local coordinate system, the userspace, that is transformed from that of its parent element, just as the transform attribute describes. Consequently it also differs from the coordinate system of the root <svg> element.

The same happens when a parent of an element has a transform attribute: the userpace coordinate system derives from the parent and differs from that of the root. (It gets more complicated with elements "establishing a viewport", but lets skip this here.)

What you failed to notice is that the ellipse you identified for the center has a parent <g> element with an attribute transform="scale(2.4444516,2.4444516)" If you multiply the cx and cy values with these scaling factors, you get

cx = 367.23729
cy = 369.13908

That is a pretty good fit with the size of the SVG as a whole. It has attributes width="734.47461" height="738.27081", which, if you halve them, differ only insignificantly from the values for the ellipse.

Having checked that the coordinate systems of the hands elements or their parents are not transformed, you can now set the rotation as

transform="rotate(10 367.23729 369.13908)"

If you continue to work with SVGs, reading the chapter about coordinate systems and transformations in the spec is certainly a good idea.

这篇关于为什么我无法围绕 SVG 中的给定点旋转路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆