从圆心起波纹

Ripple from center of circles

我将每个圆圈作为一个点数组,我正在尝试使用来自中心的 Anime.js 创建涟漪效果。我已经尝试了各种方法并努力让它发挥作用,有人知道我该怎么做吗?

到目前为止我的代码,这里有一个 CodePen the animation part is at the bottom. I'd like it to ripple like this 但不能让它在这种情况下工作。

var container     = document.getElementById('container');
var numberOfDots    = 512;
var numberOfCircles = 8;
var dotsPerCircle   = numberOfDots / numberOfCircles;
var circles         = [];

function createDot(i, circleDepth) {
    var rotation  = (360 / dotsPerCircle) * i;
    var height    = "calc( 30% + " + (circleDepth * 10) + "px)";
    var container = document.createElement('div');
          container.classList = 'dot';
          container.style.height = height;
          container.style.transform = 'rotate(' + rotation + 'deg) translateY(-50%)';

    var dot       = document.createElement('span');
        container.appendChild(dot);

    return container;
}

function createCircle(circleDepth) {
    var dotArray = [];
    for (var i = 1; i <= dotsPerCircle; i++) {
        var dot = createDot(i, circleDepth);
        container.appendChild(dot);
        dotArray.push(dot.querySelector('span'));
    }
    return dotArray;
}

for (var i = 1; i <= numberOfCircles; i++) {
    circles.push(createCircle(i));
}

// Animation
var duration   = 6000;
var delay      = duration / numberOfDots;
var myTimeline = anime.timeline({
    complete: function() { myTimeline.restart(); }
});
for (var i = 0; i < circles.length; i++) {
    var dotArray = circles[i];
    myTimeline.add({
        targets: dotArray,
        easing: 'easeInOutSine',
        direction: 'alternate',
        duration: duration * .1,
        scale: [
            {value: 1.6, easing: 'spring(1, 80, 10, 0)', duration: 1000},
            {value: 1, easing: 'spring(1, 80, 10, 0)', duration: 1000}
        ],
    }, "-=990")
}

这是我的建议:使用 css 动画!它们总是比库更流畅、更高效,比如 anime.js。您可以通过为 .dot 元素设置不同的 animation-delay 属性,根据它们所在的层,使点一次波纹一层,从内圈传播到最外层。

我认为以下内容看起来还不错。请注意,这实际上仅使用 html 和 css; javascript 仅用于生成 html!

let makeRipple = (numRings=8, dotsPerRing=64, ringEndAmt=0.5, rippleMs=1000) => {
  
  // ringEndAmt: The portion of ripple filled by rings (0.5 = half the radius is empty of dots)
  // rippleMs: The amount of time between the inner layer and outer layer pulsing
  
  let ripple = document.createElement('div');
  ripple.classList.add('ripple');
  
  for (let r = 0; r < numRings; r++) { for (let d = 0; d < dotsPerRing; d++) {
    
    // `r` indexes the layer we're in, from inner to outermost
    // `d` indexes the specific dot within layer `r`
    
    let radius = 1 - ((r / numRings) * ringEndAmt);
    let angAmt = (d / dotsPerRing) * Math.PI * 2;
    
    let [ x, y ] = [ Math.cos(angAmt), Math.sin(angAmt) ].map(v => v * radius);
    
    let dot = document.createElement('div');
    dot.classList.add('dot');
    dot.style.left = `${(x + 1) * 50}%`;
    dot.style.top = `${(y + 1) * 50}%`;
    dot.style.animationDelay = `${Math.round((1 - ((r + 1) / numRings)) * rippleMs)}ms`;
    ripple.appendChild(dot);
    
  }}
  
  return ripple;
  
};

document.body.appendChild(makeRipple());
@keyframes pulseRipple {
  0%   { transform: scale(0.8); }
  12%  { transform: scale(0.8); }
  16%  { transform: scale(0.82); }
  24%  { transform: scale(0.993); }
  26%  { transform: scale(1); }
  33%  { transform: scale(0.8); }
  100% { transform: scale(0.8); }
}

@keyframes pulseDot {
  0%  { background-color: rgba(0, 150, 0, 0.1); transform: translate(0px, 0px) scale(1); }
  10% { background-color: rgba(0, 150, 0, 0.1); transform: translate(0px, 0px) scale(1); }
  20% { background-color: rgba(0, 150, 0, 0.8); transform: translate(2px, 2px) scale(2); }
  30% { background-color: rgba(0, 150, 0, 0.1); transform: translate(0px, 0px) scale(1); }
}

.ripple {
  position: relative;
  background-color: rgba(0, 150, 0, 0.02);
  border-radius: 100%;
  width: 45%; padding-bottom: 45%;
  box-shadow: 0 0 0 2px rgba(0, 150, 0, 0.02);
    
  animation-name: pulseRipple;
  animation-duration: 8000ms;
  animation-iteration-count: infinite;
  animation-timing-function: ease-in;
}
.ripple > .dot {
  position: absolute;
  background-color: rgba(0, 150, 0, 0.1);
  width: 4px;
  height: 4px;
  margin-left: -2px; margin-top: -2px; /* Dots are centered */
  border-radius: 100%;
  
  animation-name: pulseDot;
  animation-duration: 8000ms;
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
}