【问题标题】:Animate SVG on scroll滚动上的动画 SVG
【发布时间】:2017-11-14 19:07:05
【问题描述】:

我正在根据我的滚动位置为 SVG 线条制作动画。它可以工作,但 FPS 非常低,动画本身也很滞后。我很确定是我的原生 Javascript 技能搞砸了,但我不知道如何解决它。

我在实际网站上创建了一个快速而肮脏的 JSbin 副本;

http://jsbin.com/vigaqoxiru/edit?html,css,js,output

window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(f){setTimeout(f, 1000/60)}

document.addEventListener('DOMContentLoaded', function() {
    Timeline();
});

function Timeline() {
    requestAnimationFrame(animateLine)

    function convertRange( value, r1, r2 ) { 
         return ( value - r1[ 0 ] ) * ( r2[ 1 ] - r2[ 0 ] ) / ( r1[ 1 ] - r1[ 0 ] ) + r2[ 0 ];
    }

    function animateLine() {
        var offset = window.scrollY;
        var wheight = window.innerHeight;
        var timeline = document.querySelector(".Approach--steps");
        var theight = timeline.getBoundingClientRect().top - wheight;

        if (theight < 0) {
            var timelineMin = timeline.offsetHeight;
            var objectMin = timeline.offsetTop;
            var objectMax = timeline.offsetTop + timeline.offsetHeight;

            document.querySelector(".Approach--timeline svg").setAttribute("style", "transform: scaleY(" + Math.floor(convertRange( (offset + wheight), [objectMin, objectMax], [0, 1.0]) * 100) / 100 + ")");
        }
    }

    window.addEventListener('scroll', function(){
        requestAnimationFrame(animateLine)
    });
}

正如您所见,它不会以 60fps 的速度滚动,但我使用的是 scale 属性、requestAnimationFrame 和舍入值。知道实现这个动画的更好方法是什么吗?最好没有jQuery。 GSAP 没问题,因为我已经在运行它了。

【问题讨论】:

  • 为什么使用 SVG?为什么不用 CSS 使用常规 div 和动画高度?
  • 因为现在我只使用一个简单的行来进行演示,但是 svg 稍后会更复杂一些。这只是基础,我将添加一些圈子!

标签: javascript html css svg


【解决方案1】:

您为什么不添加transition 时间以使其工作更顺利?

.Approach--timeline svg {
    transition: .5s ease;
}

window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(f){setTimeout(f, 1000/60)}

document.addEventListener('DOMContentLoaded', function() {
    Timeline();
});

function Timeline() {
	requestAnimationFrame(animateLine)
  
    function convertRange( value, r1, r2 ) { 
        return ( value - r1[ 0 ] ) * ( r2[ 1 ] - r2[ 0 ] ) / ( r1[ 1 ] - r1[ 0 ] ) + r2[ 0 ];
    }

    function animateLine() {
        var offset = window.scrollY;
        var wheight = window.innerHeight;
        var timeline = document.querySelector(".Approach--steps");
        var theight = timeline.getBoundingClientRect().top - wheight;
        
        if (theight < 0) {
            var timelineMin = timeline.offsetHeight;
            var objectMin = timeline.offsetTop;
            var objectMax = timeline.offsetTop + timeline.offsetHeight;

            document.querySelector(".Approach--timeline svg").setAttribute("style", "transform: scaleY(" + Math.floor(convertRange( (offset + wheight), [objectMin, objectMax], [0, 1.0]) * 100) / 100 + ")");
        }
    }

    window.addEventListener('scroll', function(){
        requestAnimationFrame(animateLine)
    });
}
.Approach--steps {
  margin-top: 600px;
  margin-bottom: 200px
}

.Approach--header {
    margin-top: 80px;
}

.Approach--step {
    margin-top: 500px;
    padding-left: 56px;
}

.Approach--timeline {

}

.Approach--timeline svg {
    position: absolute;
    margin-top: -100px;
    height: 100%;
    width: 4px;
    transition: .5s ease;
    transform: scaleY(0);
    transform-origin: top left;
}

.Approach--steps {
    position: relative;
}
<div class="Approach--steps">
   <div class="Approach--timeline">
      <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">
          <linearGradient id="grad" x1="0%" y1="0%" x2="0%" y2="100%" gradientUnits="userSpaceOnUse">
              <stop stop-color="#22D9BC" stop-opacity="1.0" offset="0%" />
              <stop stop-color="#1674F5" stop-opacity="1.0" offset="50%" />
              <stop stop-color="#7D00FF" stop-opacity="1.0" offset="100%" />
          </linearGradient>
          <rect x="0" y="0" width="1" height="1" fill="url(#grad)" id="Approach--svg" />
      </svg>
  </div>
  
  <div class="Approach--step">
      <p>1. Khaled Ipsum</p>
      <p>Lorem Khaled Ipsum is a major key to success. Eliptical talk. How’s business? Boomin. They will try to close the door on you, just open it. You see the hedges, how I got it shaped up? It’s important to shape up your hedges, it’s like getting a haircut, stay fresh. Wraith talk. We don’t see them, we will never see them. Life is what you make it, so let’s make it. Another one. Hammock talk come soon. It’s important to use cocoa butter. It’s the key to more success, why not live smooth? Why live rough?</p>
  </div>

  <div class="Approach--step">
      <p>2. Lion</p>
      <p>The ladies always say Khaled you smell good, I use no cologne. Cocoa butter is the key. Hammock talk come soon. Put it this way, it took me twenty five years to get these plants, twenty five years of blood sweat and tears, and I’m never giving up, I’m just getting started. Major key, don’t fall for the trap, stay focused. It’s the ones closest to you that want to see you fail. The key to success is to keep your head above the water, never give up.</p>
  </div>

  <div class="Approach--step">
      <p>3. We the best</p>
  </div>
  
  
</div>

【讨论】:

  • 这就够了。也不是FPS低。只是当您滚动窗口时不会顺利通过每个像素。所以 svg 会跳跃,因为滚​​动是跳跃的。所以只需添加一个过渡就可以解决它。
  • 嘿嘿。这是一个简单的解决方案,它甚至可以工作。我的 Javascript 可能比我想象的要好。
【解决方案2】:

Here's a gist 的 GSAP 示例。

您提到您计划在 SVG 中添加其他元素。我建议您阅读 GSAP/SVG 文档here

使用 GSAP 制作动画时,我几乎总是建议使用 ID 选择器。

【讨论】:

  • 这让 FPS / 延迟问题一直存在。现在唯一要做的不是 scaleY 我们得到了 GSAP 集成,这并不重要。我个人认为 convertRange 函数对我的浏览器的要求太多,无法处理 60FPS 的动画。
  • 选择用 CSS 过渡来解决问题是一个糟糕的选择!祝你好运。
猜你喜欢
  • 2021-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 2021-02-10
相关资源
最近更新 更多