javascriptjquerysvgvelocity.js

Animated SVG has choppy framerate on mobile


I have been converting many of my old website's core graphics from bitmaps to vectors, and I've run into some pretty series issues with performance (fps) when browsing on mobile devices.

Here's a simplified recreation of the animated SVG on jsFiddle, plus a link to my website where it's implemented, and the javascript code below:

$(document).ready(function($) {

    var showreelActive = 0;

    //Showreel Handler
    $("#showSVG").click(function(){

        if(showreelActive == 0) {   
            showreelActive = 1;

            $("#showSVG").css({"pointer-events":"none"})        
            $("#showPlay").fadeOut( 250 )
            $("#showCurtainL").velocity({ x: "-785px" }, 1500 )
            $("#showCurtainR").velocity({ x: "1364px" }, 1500 )
            $("#showBorderB").velocity({ y: "228.5px" },{ delay: 400, duration: 600 });
            $("#vidContainer > div").velocity({ paddingBottom: "56.25%" },{ delay: 400, duration: 600 });
        }
    }); 
})(jQuery);

Plus the SVG:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="showSVG" viewBox="0 0 1158 693">
    <defs id="defs2">
      <linearGradient id="linearGradient17022">
        <stop id="stop17016" offset="0" stop-color="#a35a43"/>
        <stop id="stop17018" offset="0.48708007" stop-color="#db8261"/>
        <stop id="stop17020" offset="1" stop-color="#a35a43"/>
      </linearGradient>
      <linearGradient id="linearGradient9574">
        <stop id="stop9570" offset="0" stop-color="#6f3b2a"/>
        <stop id="stop9578" offset="0.36356074" stop-color="#ad583b"/>
        <stop id="stop9580" offset="0.5668717" stop-color="#ad583b"/>
        <stop id="stop9572" offset="1" stop-color="#6f3b2a"/>
      </linearGradient>
      <linearGradient id="linearGradient9576" x1="22.808819" x2="36.831341" y1="105.01706" y2="105.01706" gradientTransform="matrix(2.7710017,0,0,1,-54.88142,0)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient9574"/>
      <clipPath id="clipPath23779">
      <path style="fill:#ad583b;stroke-width:2.45015192;stroke-linecap:square;stroke-linejoin:bevel" id="path238581" d="M 546.82338,161.92901 V 53.80436 l 94.1365,53.68427 z"/>
      </clipPath>
      <linearGradient id="linearGradient17014" x1="20.525791" x2="39.644741" y1="105.01706" y2="105.01706" gradientTransform="matrix(2.2781889,0,0,1,-44.870386,-22.023521)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient17022"/>
      <pattern id="pattern17024" width="47.616009" height="158.04408" patternUnits="userSpaceOnUse" patternTransform="translate(29,0)">
        <path stroke-linecap="square" d="M0 0h47.6v158H0z" stroke-width="0.51002038" fill="url(#linearGradient17014)" id="rect17012" stroke-linejoin="bevel"/>
      </pattern>
      <clipPath id="clipPath17584">
        <use id="use17586" width="100%" height="100%" xlink:href="#use13896"/>
      </clipPath>

      <filter id="filter17608" width="1.05" height="3" x="0" y="0" color-interpolation-filters="sRGB">
        <feGaussianBlur id="feGaussianBlur17610" stdDeviation="4"/>
      </filter>
      <filter id="filter17612" width="1.05" height="3" x="0" y="-1" color-interpolation-filters="sRGB">
        <feGaussianBlur id="feGaussianBlur17614" stdDeviation="4"/>
      </filter>
      <filter id="filter17684" width="1.05" height="10" x="-0.045629408" y="-4.4277124" color-interpolation-filters="sRGB">
        <feGaussianBlur id="feGaussianBlur17686" stdDeviation="22"/>
      </filter>
      <clipPath id="clipPath17688">
        <use id="use17690" width="100%" height="100%" xlink:href="#use13896"/>
      </clipPath>
      <filter id="filter17700" width="1.05" height="10" x="0" y="-4.4" color-interpolation-filters="sRGB">
        <feGaussianBlur id="feGaussianBlur17702" stdDeviation="22"/>
      </filter>
      <clipPath id="clipPath17707">
        <use id="use17709" width="100%" height="100%" xlink:href="#use13896" transform="matrix(1,0,0,1,0,-166)"/>
      </clipPath>
      <filter id="filter17766" color-interpolation-filters="sRGB" height="1.2" width="1.2">
        <feGaussianBlur id="feGaussianBlur17768" stdDeviation="4"/>
      </filter>
      <filter id="filter17790" width="1.2" height="1.2" x="-0.1" y="-0.1" color-interpolation-filters="sRGB">
        <feGaussianBlur id="feGaussianBlur17792" stdDeviation="5"/>
      </filter>
      <filter id="filter17922" width="1" height="3.5" x="0" y="-1" color-interpolation-filters="sRGB">
        <feGaussianBlur id="feGaussianBlur17924" stdDeviation="5"/>
      </filter>
      <filter id="filter17930" width="1.25" height="1.6" x="-0.15" y="-0.8" color-interpolation-filters="sRGB">
        <feGaussianBlur id="feGaussianBlur17932" stdDeviation="5"/>
      </filter>
    </defs>
    <g id="parentShapes" display="none">
      <g id="bbparent">
        <use id="use11249" width="100%" height="100%" xlink:href="#use8431" clip-path="url(#clipPath17707)" filter="url(#filter17700)" fill="#000000"/>
        <use id="use8608" width="100%" height="100%" xlink:href="#use8431" clip-path="url(#clipPath17707)" opacity="0.8" filter="url(#filter17612)" fill="#000000"/>
        <use id="use8548" width="100%" height="100%" fill="#ecdda2" xlink:href="#use8431"/>
      </g>
      <path id="use13896" d="M0 17.8h 1158v 177.2H 0z"/>
      <path id="use8431" d="M0 17.8h 1158v 12H 0z"/>
      <path id="use8540" d="M463 24l 13-16.8h 206l 13 16.8z"/>
      <rect id="curtparent" width="579" height="158" ry="0"/>
    </g>
    <g id="showMain">   
    <use id="showCurtainL" width="100%" height="100%" fill="url(#pattern17024)" xlink:href="#curtparent" x="0px" y="29px"/>
      <use id="showCurtainR" width="100%" height="100%" fill="url(#pattern17024)" xlink:href="#curtparent" x="579px" y="29px"/>
      <g id="showBorderT">
        <use id="use11246" width="100%" height="100%" xlink:href="#use8431" clip-path="url(#clipPath17688)" filter="url(#filter17684)"/>
        <use id="use8605" width="100%" height="100%" xlink:href="#use8431" clip-path="url(#clipPath17584)" opacity="0.5" filter="url(#filter17608)"/>
        <use id="use8555" width="100%" height="100%" xlink:href="#use8431" opacity="0.8" filter="url(#filter17922)"/>
        <use id="use17392" width="100%" height="100%" xlink:href="#use8540" opacity="0.8" filter="url(#filter17930)"/>
        <use id="use8533" width="100%" height="100%" fill="#ecdda2" xlink:href="#use8431"/>
        <use id="use17376" width="100%" height="100%" fill="#ecdda2" xlink:href="#use8540"/>
        <path id="path13910" d="m 493,14.433287 c -1.13333,-0.866667 -2.66667,-1.3 -4.6,-1.3 -1.73333,0 -3.06667,0.333333 -4,1 -0.4,0.266667 -0.6,0.533333 -0.6,0.8 0,0.866667 0.9,1.466667 2.7,1.8 l 3.2,0.6 c 3.2,0.533333 5.2,1.266667 6,2.2 0.53333,0.533333 0.8,1.1 0.8,1.7 0,0.8 -0.5,1.533333 -1.5,2.2 -0.93333,0.666667 -2.26667,1.166667 -4,1.5 -1.06667,0.2 -2.13333,0.3 -3.2,0.3 -3.06667,0 -5.46667,-0.6 -7.2,-1.8 -0.8,-0.533333 -1.26667,-1.2 -1.4,-2 l 3.4,-0.3 c 0,0.466667 0.26667,0.9 0.8,1.3 1.06667,0.8 2.56667,1.2 4.5,1.2 1.33333,0 2.46667,-0.233333 3.4,-0.7 0.93333,-0.4 1.46667,-0.9 1.6,-1.5 v -0.5 c 0.13333,-0.666667 -0.33333,-1.2 -1.4,-1.6 -0.86667,-0.333333 -2.2,-0.666667 -4,-1 -2,-0.4 -3.33333,-0.733333 -4,-1 -2.13333,-0.533333 -3.2,-1.433333 -3.2,-2.7 0,-0.866667 0.66667,-1.633333 2,-2.3 1.66667,-0.666667 3.66667,-1 6,-1 3.2,0 5.6,0.666667 7.2,2 z" style="fill:#6a6145"/>
        <path id="path13912" d="m 502,11.833287 h 3.3 v 5.4 h 13.2 v -5.4 h 3.4 v 13.3 h -3.5 v -6.4 h -13.2 v 6.4 H 502 Z" style="fill:#6a6145"/>
        <path id="path13914" d="m 541.4,13.133287 c -2,0 -3.83333,0.233333 -5.5,0.7 -1.73333,0.466667 -3.06667,1.133333 -4,2 -1.06667,0.8 -1.6,1.7 -1.6,2.7 0,1 0.46667,1.933333 1.4,2.8 1,0.8 2.33333,1.466667 4,2 1.8,0.466667 3.66667,0.7 5.6,0.7 2,0 3.83333,-0.266667 5.5,-0.8 1.6,-0.466667 2.93333,-1.133333 4,-2 0.93333,-0.8 1.4,-1.666667 1.4,-2.6 0,-0.933333 -0.46667,-1.8 -1.4,-2.6 -1,-0.866667 -2.33333,-1.533333 -4,-2 -1.73333,-0.466667 -3.6,-0.7 -5.6,-0.7 z m 0,-1.5 c 4,0 7.4,0.666667 10.2,2 2.86667,1.333333 4.3,3 4.3,5 0,1.2 -0.66667,2.3 -2,3.3 -1.33333,1.066667 -3.1,1.933333 -5.3,2.6 -2.26667,0.666667 -4.7,1 -7.3,1 -2.66667,0 -5.06667,-0.333333 -7.2,-1 -2.2,-0.533333 -3.96667,-1.333333 -5.3,-2.4 -1.33333,-1.133333 -2,-2.3 -2,-3.5 0,-1.2 0.66667,-2.333333 2,-3.4 1.26667,-1.2 3,-2.133333 5.2,-2.8 2.2,-0.533333 4.6,-0.8 7.2,-0.8 z" style="fill:#6a6145"/>
        <path id="path13916" d="m 577.3,11.433287 8,10 7.6,-9.6 h 3.6 l -11.4,13.8 -8,-9.7 -7.7,9.8 -11.4,-14 h 3.8 l 7.7,9.6 z" style="fill:#6a6145"/>
        <path id="path13918" d="m 600.7,11.833287 h 5 c 3.2,0 5.53333,0.266667 7,0.8 2,0.666667 3,1.666667 3,3 0,0.933333 -0.56667,1.766667 -1.7,2.5 -1.2,0.666667 -2.8,1.066667 -4.8,1.2 l 8.7,5.7 h -4.3 l -8,-5.6 H 604 v 5.7 h -3.3 z m 3.3,1.6 v 4.8 c 2,0 3.6,-0.06667 4.8,-0.2 2.53333,-0.333333 3.8,-1.1 3.8,-2.3 0,-1.6 -2.43333,-2.4 -7.3,-2.4 z" style="fill:#6a6145"/>
        <path id="path13920" d="m 622.5,11.833287 h 15 v 1.6 H 626 v 3.7 h 11 v 1.5 h -11 v 5 h 11.4 v 1.5 h -15 z" style="fill:#6a6145"/>
        <path id="path13922" d="m 643.6,11.833287 h 14.8 v 1.6 H 647 v 3.7 h 11 v 1.5 h -11 v 5 h 11.4 v 1.5 h -14.8 z" style="fill:#6a6145"/>
        <path id="path13924" d="m 664.6,11.833287 h 3.4 v 11.8 h 8.4 v 1.5 h -11.8 z" style="fill:#6a6145"/>
      </g>
      <use id="showBorderB" width="100%" height="100%" fill="url(#pattern17024)" xlink:href="#bbparent" y="169px"/>
      <g id="showPlay">
        <circle id="path8436-2" cx="579" cy="108" r="70" stroke="#000" stroke-width="0.39687499" opacity="0.6" stroke-linejoin="bevel" filter="url(#filter17766)"/>
        <circle id="path8436" cx="579" cy="108" r="67" fill="#ecdda2"/>
        <path id="path8465-0" d="M 543.43818,46.999972 V 168.73434 L 649.2956,107.48825 Z" clip-path="url(#clipPath23779)" style="opacity:0.9;fill:none;stroke:#000000;stroke-width:8.20468426;filter:url(#filter17790)"/>
    </g>
  </g>
</svg>

So, is there an issue with this code, or maybe the SVG that it's applied to? And if it isn't some obvious error on my part what steps would I need to take for it to run smoothly?

As a side note, I'm only using velocity.js because I've read that it mitigates the slow performance of jQuery. If it's a bottleneck then I'll gladly use something else.


Solution

  • After researching a bit more I found that the bulk of my issues stemmed from my animations (which were applied directly to elements within the SVG file) were invalidating the layout, and were being redrawn every frame.

    This can be avoided by wrapping the SVG element you need animated in a <div> and using the proper hardware accelerated methods of animation (which I learnt from this website).

    I also moved away from the velocity library in favour of CSS, but I'm not sure if there was any substantial change in performance as a result of that specifically.

    Now the animation runs relatively smoothly with only occasional hiccups on my low spec smartphone.