NDP Blog
Author
Davide Catani

Creating a dotted line animation with JS & HTML

Coding is a continuous learning experience and each project gives you the opportunity to learn some new techniques.

In one of my last projects, the client asked for a card based page with a vertical tracking line generated by a pin while scrolling down with the mouse.

The animation needed to be interrupted by the title of each card.

To obtain that effect I animated each element individually for each card with the ScrollMagic library:

  • A pin, which is just a fixed element repeated in each card.
    The animation controls how it shows and hides to manage the interruption caused by the card title
  • A line, which is divided into two elements: the one above the title and the one below.
    The elements are divs with the height set to 0 with a centered background image repeated vertically to create the dotted line. The element’s height increases with the scroll until they reach their maximum height.
  • A circle that appear at the end of the top line, just before the card title.

JAVASCRIPT

First of all I created the basic variables:

// the entire set of var set = $(".card-to-animate"); // the total number of cards. This can be used to make an exception on the animation in the last card var len = set.length;

 

Then I loop the set for each card that i want to animate:

set.each(function(index, element) { //Define an offset for the line bottom to start after the central card elements var offset_bottom = ($(this).find('.field-name-field-custom-programme-type').position()).top + $(this).find('.field-name-field-custom-programme-type').height() - 20; //IMPORTANT - Each card must be identified by an unique ID var id = '#' + $(this).attr('id'); //Check the height of the card var heightCard = $(id).height(); $(this).find('.dotted-line-bottom').css('top', offset_bottom + 'px'); //Define the height of the dotted line bottom var totalHeightDotBottom = heightCard - offset_bottom; //DOTTED LINE TOP var scene = new ScrollMagic.Scene({ triggerElement: id + " .trigger", duration: 52, offset: 0 }) .setTween(TweenMax.to(id + " .dotted-line-top", 800, {height: "52px", ease:Linear.easeNone})) // trigger a TweenMax.to tween .addTo(controller); //DOTTED LINE BOTTOM var scene1 = new ScrollMagic.Scene({ triggerElement: id + " .trigger", duration: totalHeightDotBottom, offset: offset_bottom }) .setTween(TweenMax.to(id + " .dotted-line-bottom", 800, {css:{height: (totalHeightDotBottom + 20) + "px"}, ease:Linear.easeNone})) // trigger a TweenMax.to tween .addTo(controller); //PIN var scene2 = new ScrollMagic.Scene({ triggerElement: id + " .trigger", duration: heightCard, offset: 0 }) .setPin(id + " .pin") .setClassToggle(id + " .pin", "show") .addTo(controller); //HIDE PIN var scene3 = new ScrollMagic.Scene({ triggerElement: id + " .trigger", duration: 30, offset: 40 }) .setTween(TweenMax.to(id + " .pin", 10, {css:{transform: "scale(0, 0)"}})) //transform: scale(0, 0) .addTo(controller); //SHOW CIRCLES var scene4 = new ScrollMagic.Scene({ triggerElement: id + " .trigger", duration: 30, offset: 40 }) .setTween(TweenMax.to(id + " .circle", 10, {css:{transform: "scale(1, 1)"}})) .addTo(controller); //SHOW PIN var scene5 = new ScrollMagic.Scene({ triggerElement: id + " .trigger", duration: 10, offset: offset_bottom }) .setTween(TweenMax.to(id + " .pin", 10, {css:{transform: "scale(1, 1)"}})) .addTo(controller); }

 

HTML

All the animated elements are at the top, together with the trigger element that allows the animation to start.

<section id="card1" class="entity-card"> <div class="trigger"></div> <div class="pin"></div> <div class="dotted-line dotted-line-top"></div> <div class="dotted-line dotted-line-bottom"></div> <div class="circle"></div> <div class="group-text-wrapper field-group-div"> <div class="group-header"> <div class="field field-name-field-programme field-type-entityreference field-label-hidden"> <div class="field-items"> <div class="field-item even"> <a href="/aenean-commodo-ligula-eget">Aenean commodo ligula eget</a> </div> </div> <div class="field field-name-field-programme-type"> <div class="field-items"> <div class="field-item even">Lorem ipsum</div> </div> </div> <div class="field field-name-field-year field-type-text field-label-hidden"> <div class="field-items"> <div class="field-item even">2016</div> </div> </div> <div class="field field-name-field-custom-programme-type field-type-ds field-label-hidden"> <div class="field-items"> <div class="field-item even">L</div> </div> </div> </div> <div class="group-left"> <div class="field field-name-field-why-i-chose-this-programme field-type-text-with-summary field-label-above"> <div class="field-label">Why:&nbsp;</div> <div class="field-items"> <div class="field-item even"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sit amet tempus leo. Aenean commodo lorem et turpis feugiat pellentesque. Cras malesuada libero nec eleifend commodo.</p> </div> </div> </div> </div> <div class="group-right"> <div class="field field-name-field-how-to-prepare field-type-text-with-summary field-label-above"> <div class="field-label">How:&nbsp;</div> <div class="field-items"> <div class="field-item even"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sit amet tempus leo. Aenean commodo lorem et turpis feugiat pellentesque. Cras malesuada libero nec eleifend commodo.</p> </div> </div> </div> </div> <div class="group-footer"></div> </div> </section>


See a full working example here:

See the Pen Scroll pointer by Davide Catani (@zave) on CodePen.

Written by Davide Catani