【问题标题】:How do I "perfectly" center an object following an SVG path in Anime.js?如何在 Anime.js 中按照 SVG 路径“完美”居中对象?
【发布时间】:2020-05-10 07:28:28
【问题描述】:

我在 SVG 中使用 Anime.jsa circle path 周围移动一个 20 像素的正方形。然而,正方形在它的圆形路径中并不完全居中:

anime({
    targets: '.square',
    translateX: path('x'),
    translateY: path('y'),
    rotate: path('angle'),
    easing: 'linear',
    duration: 10000,
    loop: true,
});

https://codepen.io/gremo/pen/wvKjrMW

我找到了类似的示例,但 我无法理解使这项工作发挥作用的数学原理

  • Here 对象使用 top/left/margin 居中(即使是负值)
  • Here 对象仅使用 top/left 居中(负值)

【问题讨论】:

  • top: -10px;left: -10px 更改为 .square 用于中心化的 css 类(正方形宽度和高度的一半)
  • 谢谢。这个技巧的来源,还是只是对元素宽度的补偿?
  • 我认为它适用于所有提示

标签: javascript css svg anime.js


【解决方案1】:

发生这种情况是因为您的对象(正方形)确实在跟随路径。但是,对象是根据左上角的第一个像素值平移的(因此,如果您制作1px x 1px 正方形,您应该会看到正方形很好地跟随路径)。这就是为什么对象的左上角总是粘在这条线上的原因。你想要的是让对象的中间部分粘在线条上。

使用静态和手动计算的值(框的原始宽度和高度的 50%)是合理的(例如,将 -10px 分配给 topleft)。但是,当有许多对象被动画时,您可能不想这样做(因为当发生更改时您需要更新所有 CSS 代码)。相反,我们可以在 .square 上使用伪元素 ::after,并将其向左平移 50% 的宽度,向顶部平移 50% 的高度。这样,物体的附着在直线上的点就是正方形的中心部分。现在,当您更新原始 .square 元素的宽度和高度时,您无需更新 topleft 值。您不能简单地将transform: translate(-50%, -50%) 值添加到原始.square div,因为它将使用Anime.js 进行动画处理,并且初始变换值将丢失。从 JS 中获取计算出的初始变换值很棘手。

document.addEventListener('DOMContentLoaded', function() {
  const path = anime.path('.circle path');

  anime({
    targets: '.square',
    translateX: path('x'),
    translateY: path('y'),
    easing: 'linear',
    duration: 10000,
    loop: true,
  });
});
body {
  background-color: #001f3f;
}

.container {
  position: relative;
  margin: 0 auto;
  max-width: 500px;
}

.circle {
  fill: none;
  stroke: #b10dc9;
}

.square {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-block;
  width: 20px;
  height: 20px;
}

.square::after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  transform: translate(-50%, -50%);
  background-color: #f012be;
}
<script src="https://unpkg.com/animejs@3.2.0/lib/anime.min.js"></script>
<div class="container">
  <svg class="circle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
    <path d="M400,250c0,82.84-67.16,150-150,150s-150-67.16-150-150s67.16-150,150-150S400,167.16,400,250z" />
  </svg>
  <span class="square"></span>
</div>

【讨论】:

  • 谢谢。实际上,我将该代码编写为我的代码的“简化”版本,包括按照另一个 SVG 路径制作另一个 SVG。我明白了。
  • 作为侧节点,我解决了这个问题,只是在制作动画之前通过 JavaScript 计算 SVG 宽度/高度。将样式设置为正确的(绝对)负位置。
  • @gremo 很高兴知道我可以提供帮助 ;-)
【解决方案2】:

要了解逻辑,请添加另一个具有不同宽度/高度的元素以查看每个对象的引用:

document.addEventListener('DOMContentLoaded', function() {
  const path = anime.path('.circle path');

  anime({
    targets: '.square',
    translateX:path('x'),
    translateY: path('y'),
    easing: 'linear',
    duration: 10000,
    loop: true,
  });
  anime({
    targets: '.square2',
    translateX: path('x'),
    translateY: path('y'),
    easing: 'linear',
    duration: 10000,
    loop: true,
  });
});
body {
  background-color: #001f3f;
}

.container {
  position: relative;
  margin: 0 auto;
  max-width: 500px;
}

.circle {
  fill: none;
  stroke: #b10dc9;
}

.square {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-block;
  width: 20px;
  height: 20px;
  background-color: #f012be;
}

.square2 {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-block;
  width: 40px;
  height: 40px;
  background-color: blue;
}
<script src="https://unpkg.com/animejs@3.2.0/lib/anime.min.js"></script>
<div class="container">
  <svg class="circle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
    <path d="M400,250c0,82.84-67.16,150-150,150s-150-67.16-150-150s67.16-150,150-150S400,167.16,400,250z" />
  </svg>
  <span class="square2"></span>
  <span class="square"></span>
</div>

如您所见,左上角与路径一致。为避免这种情况,您可以使用负左/上来偏移元素并使其居中,或者使用不同的 CSS 来制作通用内容。

我制作了 0 维的元素,并考虑使用box-shadw 来创建方形:

document.addEventListener('DOMContentLoaded', function() {
  const path = anime.path('.circle path');

  anime({
    targets: '.square',
    translateX:path('x'),
    translateY: path('y'),
    easing: 'linear',
    duration: 10000,
    loop: true,
  });
  anime({
    targets: '.square2',
    translateX: path('x'),
    translateY: path('y'),
    easing: 'linear',
    duration: 10000,
    loop: true,
  });
});
body {
  background-color: #001f3f;
}

.container {
  position: relative;
  margin: 0 auto;
  max-width: 500px;
}

.circle {
  fill: none;
  stroke: #b10dc9;
}

.square {
  content:"";
  position: absolute;
  left:0;
  right:0;
  width: 0;
  height: 0;
  box-shadow:0 0 0 10px #f012be;
}

.square2 {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  box-shadow:0 0 0 20px blue;
}
<script src="https://unpkg.com/animejs@3.2.0/lib/anime.min.js"></script>
<div class="container">
  <svg class="circle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
    <path d="M400,250c0,82.84-67.16,150-150,150s-150-67.16-150-150s67.16-150,150-150S400,167.16,400,250z" />
  </svg>
  <span class="square2"></span>
  <span class="square"></span>
</div>

【讨论】:

    猜你喜欢
    • 2016-05-28
    • 2017-12-05
    • 2021-09-14
    • 2016-05-25
    • 2012-10-24
    • 1970-01-01
    • 2020-02-19
    • 2019-10-09
    相关资源
    最近更新 更多