旋转后移动 SVG 元素

dan*_*iel 1 javascript svg

请帮助我理解使用普通 javascript 操作 svg 元素及其转换的最佳实践。

我知道坐标系是通过节点和链接等传递的。

我想要实现的是在旋转后继续对元素进行原始翻译。应用旋转后不沿轴。

我是否必须克隆复制第一个转换转换并将其添加到转换列表的末尾?

非常感谢如果有人能以一种雄辩的方式阐明一些观点。

Pau*_*eau 7

实现这一点的方法是嵌套变换。例如,查看以下示例 SVG。

<svg width="600" height="200">
  <g>
    <rect x="0" y="50" width="100" height="100" fill="blue"/>
  </g>
</svg>
Run Code Online (Sandbox Code Playgroud)

你可以申请一个转换到<g>与另一对<rect>。它们将是独立的,但会结合起来以获得整体效果。

例如,如果我想正确移动所有内容,我可以对组应用平移变换。

<svg width="600" height="200">
  <g transform="translate(200,0)">
    <rect x="0" y="50" width="100" height="100" fill="blue"/>
  </g>
</svg>
Run Code Online (Sandbox Code Playgroud)

然后,如果我想将矩形旋转到位,我可以通过对其应用旋转变换来实现。

<svg width="600" height="200">
  <g transform="translate(200,0)">
    <rect x="0" y="50" width="100" height="100" fill="blue"
          transform="rotate(45,50,100)"/>
  </g>
</svg>
Run Code Online (Sandbox Code Playgroud)

然后,如果我愿意,我可以通过更新组的变换将 rect 进一步向右移动。

<svg width="600" height="200">
  <g transform="translate(400,0)">
    <rect x="0" y="50" width="100" height="100" fill="blue"
          transform="rotate(45,50,100)"/>
  </g>
</svg>
Run Code Online (Sandbox Code Playgroud)

思考这个问题的方式是它<rect>在它自己的小世界中(“坐标空间”是官方术语:),并且完全不知道它的父元素中发生了什么。

因此,如果我们使用上面学到的知识,我们可以轻松创建您想要的那种动画。以下动画由三个阶段组成。首先我们向右移动矩形,然后旋转它,然后再次向右移动。中间阶段的旋转不会影响我们再次向右移动的第三阶段。

var  outer = document.getElementById("outer");
var  inner = document.getElementById("inner");

var  tx = 0;     // the animated X position
var  angle = 0;  // the animated angle

/*
 * The first phase of the animation.
 * Function to step to the right until we hit tx=200.
 */
var  stepRightTo200 = function() {
  setTimeout(function() {
    tx += 4;
    outer.setAttribute('transform', 'translate('+tx+',0)');
    if (tx < 200)  // schedule another step in this phase
      stepRightTo200();
    else           // start next phase of animation
      rotateTo45();
  }, 32);
};

/*
 * The second phase of the animation.
 * Step the angle around until we hit 45 degrees.
 */
var  rotateTo45 = function() {
  setTimeout(function() {
    angle += 1;
    inner.setAttribute('transform', 'rotate('+angle+',50,100)');
    if (angle < 45)
      rotateTo45()
    else
      stepRightTo400();   // start third phase of animation
  }, 32);
};

/*
 * The third phase of the animation.
 * Step to the right until we hit tx=400.
 */
var  stepRightTo400 = function() {
  setTimeout(function() {
    tx += 4;
    outer.setAttribute('transform', 'translate('+tx+',0)');
    if (tx < 400)
      stepRightTo400();
  }, 32);
};

// Kick off first phase of animation
stepRightTo200();
Run Code Online (Sandbox Code Playgroud)
<svg width="600" height="200">
  <g id="outer">
    <rect id="inner" x="0" y="50" width="100" height="100" fill="blue"/>
  </g>
</svg>
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,我已经将“外部”变换分离到父组中,但我们实际上不必这样做。我们可以将变换操作嵌套到单个变换中。

所以我们可以将上面的第三个 SVG 示例简化为:

<svg width="600" height="200">
  <rect x="0" y="50" width="100" height="100" fill="blue"
        transform="translate(400,0) rotate(45,50,100)"/>
</svg>
Run Code Online (Sandbox Code Playgroud)

“外部”变换成为变换列表中的第一个。如果您需要创建一个多部分转换,这是一种概念化多部分转换的好方法。首先创建(或想象)一个嵌套的组结构,然后将您的变换应用于从“外部”(左)到“内部”(右)的结构。

所以最后,我们可以使用这种非嵌套形式重写我们的动画脚本。

var  inner = document.getElementById("inner");

var  tx = 0;     // the animated X position
var  angle = 0;  // the animated angle

/*
 * The first phase of the animation.
 * Function to step to the right until we hit tx=200.
 */
var  stepRightTo200 = function() {
  setTimeout(function() {
    tx += 4;
    inner.setAttribute('transform',
                       'translate('+tx+',0) rotate('+angle+',50,100)');
    if (tx < 200)  // schedule another step in this phase
      stepRightTo200();
    else           // start next phase of animation
      rotateTo45();
  }, 32);
};

/*
 * The second phase of the animation.
 * Step the angle around until we hit 45 degrees.
 */
var  rotateTo45 = function() {
  setTimeout(function() {
    angle += 1;
    inner.setAttribute('transform',
                       'translate('+tx+',0) rotate('+angle+',50,100)');
    if (angle < 45)
      rotateTo45()
    else
      stepRightTo400();   // start third phase of animation
  }, 32);
};

/*
 * The third phase of the animation.
 * Step to the right until we hit tx=400.
 */
var  stepRightTo400 = function() {
  setTimeout(function() {
    tx += 4;
    inner.setAttribute('transform',
                       'translate('+tx+',0) rotate('+angle+',50,100)');
    if (tx < 400)
      stepRightTo400();
  }, 32);
};

// Kick off first phase of animation
stepRightTo200();
Run Code Online (Sandbox Code Playgroud)
<svg width="600" height="200">
  <rect id="inner" x="0" y="50" width="100" height="100" fill="blue"/>
</svg>
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助您了解转换的工作原理。