About design and nearby

How to animate SVG on scrolling

Posted: October 15th, 2016 | Author: | Filed under: Development, Tips and Tricks | Tags: , , , , , , , | No Comments »

Working with SVG consists of two parts: designing itself and development. They are tired very closely and depend each on another. The nature of SVG as both an image format and a XML format, every step taken in the graphics editor directly affects the resulting code.

There are a lot of ways to animate SVG. It could be done with the tag that goes right into the SVG code, with javascript libraries or using inline SVG code inside HTML) and animating the parts right through CSS. My task was animating SVG on page scrolling and as a base I used “Masking SVG Animations” by Nathan Gordon tutorial.

Final image
I love to work with Adobe Illustrator, so I started with my design firstly. The final image should be:

Creating your *.svg image is the most critical step — if you have problems making it work, probably it’s because your SVG assets weren’t correctly produced.

1. The design stage: drawing vector image.

I decided to draw my picture using ‘path’.
*The ‘path’ element is the most powerful element in the SVG library of basic shapes (lines, curves, arcs, etc.). The shape of a path element is defined by one attribute – ‘d’ (‘d’ stands for data and it could just as well stand for directions.).
There are a number of stroke related properties within SVG that allow us to control the details of strokes, some of them are: stroke, stroke-width, stroke-linecap, stroke-dasharray, stroke-dashoffset.

It’s important to start drawing the path with the right direction – to avoid a headache at the development stage. Well, you can change the direction in the XML code or via styles or javascript.. but for complicated shapes it’s easier to think about the final result while drawing )).

See my source file:

Illustrator screen: shapes and layers

I gave a stroke-width property for all my animated paths. And created compound paths from ‘line’ and ‘circle’ objects:

How to create compound path

2. The development stage.

All the magic comes with CSS attributes ‘stroke-dasharray’ and ‘stroke-dashoffset’ of the path’s length:

  1. function pathPrepare($el) {
  2.         var lineLength = $el[0].getTotalLength();
  3.         $el.css("stroke-dasharray", lineLength);
  4.         $el.css("stroke-dashoffset", lineLength);
  5.     }

And a tween animates the stroke-dashoffset property to zero.

I included ScrollMagic and animation.gsap in the html, just after the TweenMax.min.js reference – to react to the user’s current scroll position.

We need the ScrollMagic controller, then timeline and then – add this timeline to a ScrollMagic scene:

  1. // init controller
  2. var controller = new ScrollMagic.Controller();
  3.  
  4. // timeline
  5. var tween = new TimelineMax()
  6.         .add(TweenMax.to(blockLineFirst, 0.3, { strokeDashoffset: 0, ease: Linear.easeNone })) // draw word for 0.3
  7.         .add(TweenMax.to(blockCircleFirst, 0.3, { strokeDashoffset: 0, ease: Linear.easeNone }));  
  8.  
  9. // scene
  10.  var scene = new ScrollMagic.Scene({ triggerElement: blockTrigger, duration: blockTriggerHeight, tweenChanges: true })
  11.         .setTween(tween)
  12.         .addTo(controller);

The triggerElement element for this animation is set to #blockTrigger.

The HTML code with inline SVG and it’s wrapper (trigger) looks:

  1. <div id="blockTrigger">
  2. <svg version="1.1" id="graphycs" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;"
  3.        xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1140px" height="800px"
  4.        viewBox="0 0 1140 800" enable-background="new 0 0 1140 800" xml:space="preserve">
  5.      <g id="group">
  6.       <g id="text">
  7.        <g id="customers_text_3_">
  8.         <text transform="matrix(1 0 0 1 49 185.3682)" fill="#222222" font-family="'OpenSans-Light'" font-size="48">I love to work with </text>
  9.         <text transform="matrix(1 0 0 1 161 267.8086)" fill="#51BBE3" font-family="'OpenSans-Bold'" font-size="92">SVG</text>
  10.        </g>
  11.       </g>
  12.       <!–<circle id="circle" fill="none" stroke="#51BBE3" stroke-width="10" stroke-miterlimit="10" cx="249.667" cy="581.111" r="187"/>–><!–this is the default circle–>
  13.      
  14.   <path id="circlepath" fill="none" stroke="#51BBE3" stroke-width="10" stroke-miterlimit="10" d="M249.667,394.111
  15.   c103.277,0,187,83.723,187,187s-83.723,187-187,187s-187-83.723-187-187S146.39,394.111,249.667,394.111z"/> <!–this is the same circle, but converted to path–>
  16.       <g>
  17.        <defs>
  18.         <path id="SVGID_1_" d="M0,0v790.5h502.5V0H0z M390.5,295.5h-287v-169h287V295.5z"/>
  19.        </defs>
  20.        <clipPath id="SVGID_2_">
  21.         <use xlink:href="#SVGID_1_"  overflow="visible"/>
  22.        </clipPath>
  23.        <path clip-path="url(#SVGID_2_)" id="linepath" fill="none" stroke="#51BBE3" stroke-width="10" stroke-miterlimit="10" d="M249.667,1v391.111" />
  24.       </g>
  25.      </g>
  26.      </svg>
  27. </div>

And javascript:

  1. $(document).ready(function () {
  2.  
  3.     //store trigger heights
  4.     var blockTriggerHeight;
  5.  
  6.  
  7.     // For each path, set the stroke-dasharray and stroke-dashoffset
  8.     // equal to the path's total length, hence rendering it invisible
  9.     function pathPrepare($el) {
  10.         var lineLength = $el[0].getTotalLength();
  11.         $el.css("stroke-dasharray", lineLength);
  12.         $el.css("stroke-dashoffset", lineLength);
  13.         //$el.css("stroke", "none");
  14.         //$el.css("stroke-width", 10);
  15.         //$el.css("stroke-linecap", "round");
  16.     }
  17.  
  18.     // Store a reference to our paths
  19.     var blockLineFirst = $("path#linepath");
  20.     var blockCircleFirst = $("path#circlepath");
  21.  
  22.     // prepare SVG paths
  23.     pathPrepare(blockLineFirst);
  24.     pathPrepare(blockCircleFirst);
  25.  
  26.     // Store a reference to our triggers
  27.     var blockTrigger = "#blockTrigger";
  28.  
  29.     // init controller
  30.     var controller = new ScrollMagic.Controller();
  31.  
  32.     blockTriggerHeight = $(blockTrigger).height();
  33.  
  34.     // Create a timeline for ease of manipulation and the possibility
  35.     // to play the animation back and forth at the requested speed.
  36.     // Add each separate line animation to the timeline, animating the
  37.     // stroke-dashoffset to 0. Use the duration, delay and easing to
  38.     // achieve the perfect animation.
  39.  
  40.     // build tween
  41.  
  42.     var tween = new TimelineMax()
  43.         .add(TweenMax.to(blockLineFirst, 0.3, { strokeDashoffset: 0, ease: Linear.easeNone })) // draw word for 0.3
  44.         .add(TweenMax.to(blockCircleFirst, 0.3, { strokeDashoffset: 0, ease: Linear.easeNone }));
  45.  
  46.     var scene = new ScrollMagic.Scene({ triggerElement: blockTrigger, duration: blockTriggerHeight, tweenChanges: true })
  47.         .setTween(tween)
  48.         .addTo(controller);
  49.  
  50.     function setTriggerHeight() {
  51.         // re-calculation height.
  52.         //blockFirstTriggerHeight = $(blockFirstTrigger).height();
  53.         blockTriggerHeight = $(blockTrigger).height();
  54.  
  55.         // update duration.
  56.         scene3.duration(blockTriggerHeight);
  57.  
  58.     }
  59.  
  60.     //event on window resize
  61.     $(window).on("resize", function () {
  62.         setTriggerHeight();
  63.     });
  64.  
  65.     // show indicators (requires debug extension)
  66.     scene3.addIndicators();
  67.  
  68. });

The important part is the ‘duration: blockTriggerHeight’ in the ScrollScene, which defines the length of the scrolling distance when the animation will play.

Check standalone example: How to animate a SVG image with CSS and javascript >> or Download the source files

Now you know!

Important note: I encountered an issue on default Android browser (everything was tested successfully on IE, Edge, Safari, Chrome and Firefox). The SVG element in a relative ‘div’ takes the correct width and wrong top position. It was fixed with adding style=’max-height:100%;’ to the ‘svg’ element.

Share Button

Check Related Posts:


Leave a Reply


  • 9 + = fourteen

Ready to contact a Freelance UI & UX designer for your project? I’m ready to jump onboard!

Let's discuss your project now