【问题标题】:Animation optimization in pure js纯js中的动画优化
【发布时间】:2020-12-26 15:45:36
【问题描述】:

纯js里有树叶飞舞的动画。问题是它需要优化以获得最佳性能,因为页面上会有更多此类动画。除了优化原始 SVG 图像和减少传单的数量之外,您还可以提供哪些提示来提高代码的性能?

var LeafScene = function(el) {
    this.viewport = el;
    this.world = document.createElement('div');
    this.leaves = [];

    this.options = {
      numLeaves: 6,
      wind: {
        magnitude: 0,
        maxSpeed: 12,
        duration: 300,
        start: 0,
        speed: 10
      },
    };

    this.width = this.viewport.offsetWidth;
    this.height = this.viewport.offsetHeight;

    this.timer = 0;

    this._resetLeaf = function(leaf) {

      leaf.x = this.width * 2 - Math.random()*this.width*1.75;
      leaf.y = -10;
      leaf.z = Math.random()*200;
      if (leaf.x > this.width) {
        leaf.x = this.width + 10;
        leaf.y = Math.random()*this.height/2;
      }
      if (this.timer == 0) {
        leaf.y = Math.random()*this.height;
      }

      leaf.rotation.speed = Math.random()*10;
      var randomAxis = Math.random();
      if (randomAxis > 0.5) {
        leaf.rotation.axis = 'X';
      } else if (randomAxis > 0.25) {
        leaf.rotation.axis = 'Y';
        leaf.rotation.x = Math.random()*180 + 90;
      } else {
        leaf.rotation.axis = 'Z';
        leaf.rotation.x = Math.random()*360 - 180;
        leaf.rotation.speed = Math.random()*3;
      }

      leaf.xSpeedVariation = Math.random() * 0.8 - 0.4;
      leaf.ySpeed = Math.random() + 1.5;

      return leaf;
    }

    this._updateLeaf = function(leaf) {
      var leafWindSpeed = this.options.wind.speed(this.timer - this.options.wind.start, leaf.y);

      var xSpeed = leafWindSpeed + leaf.xSpeedVariation;
      leaf.x -= xSpeed;
      leaf.y += leaf.ySpeed;
      leaf.rotation.value += leaf.rotation.speed;

      var t = 'translateX( ' + leaf.x + 'px ) translateY( ' + leaf.y + 'px ) translateZ( ' + leaf.z + 'px )  rotate' + leaf.rotation.axis + '( ' + leaf.rotation.value + 'deg )';
      if (leaf.rotation.axis !== 'X') {
        t += ' rotateX(' + leaf.rotation.x + 'deg)';
      }
      leaf.el.style.webkitTransform = t;
      leaf.el.style.MozTransform = t;
      leaf.el.style.oTransform = t;
      leaf.el.style.transform = t;

      if (leaf.x < -10 || leaf.y > this.height + 10) {
        this._resetLeaf(leaf);
      }
    }

    this._updateWind = function() {

      if (this.timer === 0 || this.timer > (this.options.wind.start + this.options.wind.duration)) {

        this.options.wind.magnitude = Math.random() * this.options.wind.maxSpeed;
        this.options.wind.duration = this.options.wind.magnitude * 50 + (Math.random() * 20 - 10);
        this.options.wind.start = this.timer;

        var screenHeight = this.height;

        this.options.wind.speed = function(t, y) {
          var a = this.magnitude/2 * (screenHeight - 2*y/3)/screenHeight;
          return a * Math.sin(2*Math.PI/this.duration * t + (3 * Math.PI/2)) + a;
        }
      }
    }
  }

  LeafScene.prototype.init = function() {

    for (var i = 0; i < this.options.numLeaves; i++) {
      var leaf = {
        el: document.createElement('div'),
        x: 0,
        y: 0,
        z: 0,
        rotation: {
          axis: 'X',
          value: 0,
          speed: 0,
          x: 0
        },
        xSpeedVariation: 0,
        ySpeed: 0,
        path: {
          type: 1,
          start: 0,

        },
        image: 1
      };
      this._resetLeaf(leaf);
      this.leaves.push(leaf);
      this.world.appendChild(leaf.el);
    }

    this.world.className = 'leaf-scene';
    this.viewport.appendChild(this.world);
    this.world.style.webkitPerspective = "400px";
    this.world.style.MozPerspective = "400px";
    this.world.style.oPerspective = "400px";
    this.world.style.perspective = "400px";
    
    var self = this;
    window.onresize = function(event) {
      self.width = self.viewport.offsetWidth;
      self.height = self.viewport.offsetHeight;
    };
  }

  LeafScene.prototype.render = function() {
    this._updateWind();
    for (var i = 0; i < this.leaves.length; i++) {
      this._updateLeaf(this.leaves[i]);
    }

    this.timer++;

    requestAnimationFrame(this.render.bind(this));
  }

  var leafContainer = document.querySelector('.falling-leaves'),
      leaves = new LeafScene(leafContainer);

  leaves.init();
  leaves.render();
body, html {
  height: 100%;
}

.falling-leaves {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 100%;
  max-width: 880px;
  max-height: 880px;
  transform: translate(-50%, 0);
  border: 20px solid #fff;
  border-radius: 50px;
  background-size: cover;
  overflow: hidden;
}

.leaf-scene {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 100%;
  transform-style: preserve-3d;
}

.leaf-scene div {
  position: absolute;
  top: 0;
  left: 0;
  width: 20px;
  height: 20px;
  background: url(https://www.flaticon.com/svg/static/icons/svg/892/892881.svg) no-repeat;
  background-size: 100%;
  transform-style: preserve-3d;
  -webkit-backface-visibility: visible;
          backface-visibility: visible;
}
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">

<div class="falling-leaves"></div>

【问题讨论】:

    标签: javascript css animation optimization mathematical-optimization


    【解决方案1】:

    除非您使用 HTML Canvas,否则由于浏览器调用堆栈的原因,普通 JS 解决方案与 CSS/JS 混合解决方案相比相当繁重。

    看起来像这样:

    JS > 样式 > 布局 > 绘画 > 合成

    通过最小化浏览器在 JS 中必须执行的计算量并将对 DOM 的读取/写入分组,您将看到性能显着提高。可以使用“性能”选项卡下的 Chrome 开发工具记录工作量。您将能够看到浏览器显示内容所采取的每一步。步骤越少,性能越好……就这么简单。

    您正在向 DOM 写入每个转换,即使使用 3d 加速也是如此繁重。 我通常使用 CSS 变量和过渡来逐步更新动态动画。

    否则你所做的很棒。尝试在 HTML Canvas 上进行渲染,您的性能问题就会消失。这是一个开始:

    https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API

    但是,如果您想要或无法使用 CSS 来调整画布,使其不会比 Paint 浏览器对大多数帧的调用更远。

    【讨论】:

      猜你喜欢
      • 2012-09-07
      • 2021-09-05
      • 2011-09-21
      • 2019-10-29
      • 2017-11-12
      • 2018-01-26
      • 1970-01-01
      • 1970-01-01
      • 2014-03-19
      相关资源
      最近更新 更多