【问题标题】:Rotating a Svg path around center using matrix使用矩阵围绕中心旋转 Svg 路径
【发布时间】:2015-07-16 06:20:26
【问题描述】:

我有许多不同大小的 svg 形状,我必须以不同的角度动态旋转它们。我想使用矩阵将它们集中旋转,我在计算矩阵的 e、f 时遇到了问题。如何计算矩阵中的 e,f (a,b,c,d,e,f)。我有一个角度,但不知道计算新位置,所以它看起来是中心旋转的。这是我旋转 45 度的示例形状,

     <rect x="0" y="0" width="50" height="50" style="stroke: #3333cc;fill:none;" transform="matrix(1,0,0,1,100,100)"></rect>

   <rect x="0" y="0" width="50" height="50" style="fill: #3333cc" transform="matrix(0.707,-0.707,0.707,0.707,100,100)"></rect>

【问题讨论】:

  • 你使用matrix()而不是rotate(angle, cx,cy)有什么原因吗?
  • 诀窍是绘制以原点(0,0) 为中心的&lt;rect&gt;,然后使用rotate(degree) 和translate(x,y)。与matrix(....) 相比,始终有效且更易于阅读
  • @PaulLeBeau 我想学习机制,旋转如何在矩阵中工作
  • @AlvinK。我仍然需要使用矩阵来解决它
  • rotate(degree offset-x offset-y) 其中offset-x = 宽度/2 & offset-y = 高度/2。检查docs matrix(...) 是否等同于rotate() 和translate()。换句话说,无论你使用一个或另一个,都相当于相同的轮换。

标签: javascript matrix svg


【解决方案1】:

关于转换和矩阵乘法如何工作的介绍超出了 Stack Overflow 答案的范围。有很多在线资源。

您可以在 SVG 规范中了解 SVG 转换的工作原理:

http://www.w3.org/TR/SVG/coords.html

但基本上要围绕特定点 (cx,cy) 旋转角度 (a),您必须结合(使用矩阵乘法)这三个操作:

  1. 将中心平移回原点(-cx,-cy)
  2. 执行旋转 (a)
  3. 翻译回原来的位置
[1 0 cx] [cos(a) -sin(a) 0] [1 0 -cx] [0 1 cy] [sin(a) cos(a) 0] [0 1 -cy] [0 0 1] [0 0 1] [0 0 1]

当您将这三个矩阵相乘时,您会得到如下形式的矩阵:

[cos(a) -sin(a) (-cos(a) * x + sin(a) * y + x)] [sin(a) cos(a) (-sin(a) * x - cos(a) * y + y)] [0 0 1]

或 SVG 格式:

matrix( ca, sa, -sa, ca, (-ca * x + sa * y + x), (-sa * x - ca * y + y) )

地点:

ca = cos(angle)
sa = sin(angle)

这是一个演示。绿色矩形使用transform="rotate(a,x,y)",红色矩形使用我们计算的等价物。

var matrix = getMatrixForRotation(45, 250, 250);

document.getElementById("myrect").setAttribute("transform", matrix);



function getMatrixForRotation(a, cx, cy)
{
  var ca = Math.cos(a * Math.PI / 180);
  var sa = Math.sin(a * Math.PI / 180);

  var a = ca.toFixed(4);
  var b = sa.toFixed(4);
  var c = (-sa).toFixed(4);
  var d = ca.toFixed(4);
  var e = (-ca * cx + sa * cy + cx).toFixed(4);
  var f = (-sa * cx - ca * cy + cy).toFixed(4);

  return "matrix(" + [a,b,c,d,e,f].join(' ') + ")";
}
<svg width="500" height="500">
  
  <rect x="100" y="150" width="300" height="200" fill="#eee"/>
  
  <rect x="100" y="150" width="300" height="200" fill="none"
        stroke="green" stroke-width="10"
        transform="rotate(45 250 250)"/>
  
  <rect x="100" y="150" width="300" height="200" fill="none"
        stroke="red" stroke-width="4"
        id="myrect"/>
  
</svg>

【讨论】:

  • 你为什么使用.toFixed?这会不必要地失去准确性!
  • 两个原因:(1)JS 数字是双精度的,而 SVG 数字是单精度的。所以我们不能直接将 JS 值输出为字符串。 (2) 更整洁的输出。大多数情况下,四位小数就足够了。
  • 两个反驳:(1)是的,你可以:看到这个jsfiddle。 (2)大部分时间不是所有时间;当您可以提供不准确的代码时,为什么要提供失去准确性的代码?
【解决方案2】:

基本上你需要做的是加上你的 X 位置和负你的 Y 位置。 例如

如果你有这个代码

    <rect x="0" y="0" width="50" height="50" style="stroke: #3333cc;          fill:none;" transform="matrix(1,0,0,1,100,100)"></rect>

    <rect x="25" y="-25" width="50" height="50" style="fill: #3333cc" transform="matrix(0.5,0.5,-0.5,0.5,100,100)"></rect>

</svg>

第一个矩形是没有旋转的正常直线。要在第一个矩形的中心旋转它,您需要先

Divide the width by your x transform (0.5) : 50 / 0.5 = 25
Divide the height by your y transform (0.5) : 50 / 0.5 = 25

然后只需在第二个矩形中使用这些值,这样新的 X 位置将为 25,新的 Y 位置为 -25

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-17
    • 2017-05-04
    • 1970-01-01
    • 2015-03-29
    • 2018-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多