代码之家  ›  专栏  ›  技术社区  ›  Roland Jegorov

延迟SVG动画

  •  1
  • Roland Jegorov  · 技术社区  · 7 年前

    什么?

    我正在编写一个react应用程序,其中我有一个使用css延迟的序列动画。我正在制作 <path /> svg中的元素。


    问题

    在手机上 (不如桌面设备强大) 动画控制柄已附加 (看起来) 异步的。因此,动画不能保证完全按照预期执行。

    /* Elements.pcss file */ 
    
    .element {
        opacity: 0.1;
        animation-duration: 1.7s;
        animation-iteration-count: infinite;
    }
    
    .isAnimated {
        @for $i from 1 through $animatedItems {
            .element:nth-child($i) {
                animation-delay: calc(500ms - ($i * 100ms - 100ms)); /* <--- adding delay */
                animation-name: glow$i; /* <--- attaching animation */
            }
        }
    }
    


    结构

    以下是我的代码结构的抽象:

    父.tsx

    <Parent>
        <Elements /> {/* Renders all animating elements */}
    </Parent>
    

    元素.tsx

    import * as styles from "./Elements.pcss";
    
    // ...
    
    export class Elements extends React.PureComponent<{}, { isLoaded: boolean; }> {
        public state = {
            isLoaded: false,
        };
    
        public componentDidMount() {
            // The following is a hack to make it work. 
            // This is not a reliable solution. Thus, I want suggestions
            // from smarter people. 
    
            setTimeout(() => {
                this.setState({
                    isLoaded: true,
                });
            }, 2000);
        }
    
        public render() {
            return (
                <div className={{ [styles.isAnimated]: this.state.isLoaded }}>
                    <div className={styles.element} />
                    <div className={styles.element} />
                    <div className={styles.element} />
                    <div className={styles.element} />
                    <div className={styles.element} />
                    <div className={styles.element} />
                </div>
            );
        }
    }
    


    应该有点像这样。平滑顺序动画。相反,有时一些块同时启动动画,有时所有动画一起启动,有时发生其他一些随机组合。

    enter image description here

    • 实施或解决这一问题的最佳方法是什么?
    • 有没有人选择了mp4和gif而不是css动画?


    如果有什么不清楚的地方,我会修改描述。
    2 回复  |  直到 7 年前
        1
  •  0
  •   Temani Afif    7 年前

    你可以用一个动画和一个元素来组合。

    这里有一个想法:

    .box {
      height:250px;
      width:50px;
      background:
      /*Gradient that we will animate*/
      linear-gradient(to bottom,
        red 0px,red 30px,
        transparent 30px,transparent 50px,
        rgba(255,0,0,0.5) 50px, rgba(255,0,0,0.5) 80px,
        transparent 80px,transparent 100px,
        rgba(255,0,0,0.2) 100px, rgba(255,0,0,0.2) 0) 
        0 0/100% 130px no-repeat,
      /*Bottom gradient*/  
      repeating-linear-gradient(to bottom,
          rgba(255,0,0,0.3) 0px,rgba(255,0,0,0.3) 30px,
          transparent 30px,transparent 50px); 
       animation:change 1s infinite steps(10);
    }
    @keyframes change {
      from {
        background-position:0 250px,0 0
      }
      to {
        background-position:0 -250px,0 0;
      }
    }
    <div class="box">
    
    </div>
        2
  •  0
  •   Roland Jegorov    7 年前

    好吧,如果有人无意中发现了这个问题,并且遇到了类似的问题,那么我的解决方案与前面提到的完全不同:

    const canvas = document.querySelector("canvas");
    const cHeight = 249;
    const cWidth = 72;
    canvas.height = cHeight;
    canvas.width = cWidth;
    
    const ctx = canvas.getContext("2d");
    const bW = 72;
    const bH = 48;
    
    
    const fps = 120;
    const duration = 1700;
    const frameTime = 1000 / fps;
    const elementCount = 6;
    
    const startTime = Date.now();
    let previousFrame = startTime;
    
    const timings = {
      0: [0.1, 0.1, 0.1, 0.1, 0.1, 1.0, 1.0, 1.0, 1.0, 0.5, 0.1],
      1: [0.1, 0.1, 0.1, 0.1, 1.0, 0.9, 0.8, 0.5, 0.5, 0.1, 0.1],
      2: [0.1, 0.1, 0.1, 1.0, 0.8, 0.7, 0.6, 0.3, 0.1, 0.1, 0.1],
      3: [0.1, 0.1, 1.0, 0.6, 0.4, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
      4: [0.1, 1.0, 0.5, 0.2, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
      5: [1.0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
    };
    
    const timingFunction = (animationTime, animationLength, timing) => {
    
       // How many steps there are in timing definition, we count spaces not steps
      const positions = timing.length - 1;
    
      const stepSize = animationLength / positions; // How long time is for each step
      // For which step to take values
    
      const animationStep = Math.floor(animationTime / stepSize);
      // How much time is elapsed in step
    
      const minMaxTimingDelta = timing[animationStep + 1] - timing[animationStep];
      const timingAddition = timing[animationStep];
    
      const timeInStep = animationTime % stepSize;
      // Coificient to multiply max value with
      const coefficient = timeInStep / stepSize;
      const timingCoefficient = coefficient * minMaxTimingDelta;
    
      return timingAddition + timingCoefficient;
    };
    
    
    function drawElement(animationTime) {
      ctx.clearRect(0, 0, cWidth, cHeight)
      const min = 0;
      const max = 1;
    
      const delay = 700;
      const inDelay = animationTime < delay;
      const newAnimTime = duration - delay;
    
      for (let i = 0; i < elementCount; i++) {
        const alpha = inDelay ? 0.1 : timingFunction(
          animationTime - delay,
          newAnimTime,
          timings[i],
          min,
          max,
        )
    
    
        ctx.globalAlpha = alpha;
        ctx.fillStyle = 'green';
        ctx.fillRect(0, i * (bH + 3), bW, bH);
        
      }
    }
    
    
    const animate = () => {
      if (Date.now() - previousFrame > frameTime) {
          previousFrame = Date.now();
          drawElement((previousFrame - startTime) % duration);
      }
    
      requestAnimationFrame(animate);
    };
    requestAnimationFrame(animate);
    body {
      height: 100%;
      width: 100%;
    }
    
    canvas {
      position: absolute;
      top: 0;
      left: 0;
    }
    
    .1 {
      opacity: .9;
      background-color: blue;
      width: 50px;
      height: 50px;
      border: 1px solid red;
    }
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
    </head>
    <body> 
      <canvas />
    </body>
    </html>


    注意。 之所以需要这种方法,只是因为案件的具体情况。这里的问题是在应用程序仍在加载时安装带有动画的组件。这意味着可能有一些遗留的js进程正在进行dom元素的错误装载。

    主要的收获是:

    添加有或没有延迟的css动画并不保证所有动画都将同时初始化,因此是“同步的”。