3

Is there a way to add a class when the element that I want to apply the class to comes into the viewport? Or when the bottom of the screen is a certain distance past the top of the element?

Right now I have the effect that I want using something like this:

if ($(document).scrollTop() > 100) {
                    $(".graph-line.two").addClass("graph-75");

The problem with this is that it's relative to the document height, so when I shrink the page (or view on mobile) and the elements stack on top of each other, the page becomes taller and the class (animations) don't start when the element comes into view.

I've seen other people asking similar questions and I tried to implement the answers they got but I couldn't get anything working so any help would be greatly appreciated.

This is what I have:

$(document).ready(function() {
  $(".graph-line.one").addClass("graph-75");
  $(".graph-line-2.one").addClass("opacity");
  $(window).scroll(function() {

    if ($(document).scrollTop() > 100) {
      $(".graph-line.two").addClass("graph-75");
      $(".graph-line-2.two").addClass("opacity");
    }

    if ($(document).scrollTop() > 450) {
      $(".graph-line.three").addClass("graph-75");
      $(".graph-line-2.three").addClass("opacity");
    }

    if ($(document).scrollTop() > 800) {
      $(".graph-line.four").addClass("graph-75");
      $(".graph-line-2.four").addClass("opacity");
    }

    if ($(document).scrollTop() > 1150) {
      $(".graph-line.five").addClass("graph-75");
      $(".graph-line-2.five").addClass("opacity");
    }

    if ($(document).scrollTop() > 1500) {
      $(".graph-line.six").addClass("graph-75");
      $(".graph-line-2.six").addClass("opacity");
    }
  });
});
.graph {
  display: block;
  margin: 100px auto;
  transform: rotate(-90deg);
  will-change: transform;
}
.graph-line {
  stroke-dasharray: 628px;
  stroke-dashoffset: -628px;
  transform-origin: center;
}
.graph-75 {
  animation: graph-75 1200ms ease forwards;
}
@keyframes graph-75 {
  0% {
    stroke-dashoffset: 0;
    transform: rotate(360deg);
  }
  100% {
    stroke-dashoffset: 471;
    transform: rotate(0deg);
  }
}
.graph-line-2 {
  transition: opacity 700ms;
  opacity: 0.1;
}
.opacity {
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>

<h1>Scroll Down</h2>

<svg width="250" height="250" class="graph photoshop">
      <circle class="graph-line-2 one" cx="50%" cy="50%" r="100" stroke-width="20" fill="none" stroke="#2ECBE4" />
      <circle class="graph-line one" cx="50%" cy="50%" r="100" stroke-width="22" fill="none" stroke="#fff" opacity="0.92" />
      <text class="graph-text" text-anchor="middle" x="50%" y="-46%" fill="#fff">Photoshop</text>
     </svg>



<svg width="250" height="250" class="graph photoshop">
      <circle class="graph-line-2 two" cx="50%" cy="50%" r="100" stroke-width="20" fill="none" stroke="#2ECBE4" />
      <circle class="graph-line two" cx="50%" cy="50%" r="100" stroke-width="22" fill="none" stroke="#fff" opacity="0.92" />
      <text class="graph-text" text-anchor="middle" x="50%" y="-46%" fill="#fff">Photoshop</text>
     </svg>



<svg width="250" height="250" class="graph photoshop">
      <circle class="graph-line-2 three" cx="50%" cy="50%" r="100" stroke-width="20" fill="none" stroke="#2ECBE4" />
      <circle class="graph-line three" cx="50%" cy="50%" r="100" stroke-width="22" fill="none" stroke="#fff" opacity="0.92" />
      <text class="graph-text" text-anchor="middle" x="50%" y="-46%" fill="#fff">Photoshop</text>
     </svg>



<svg width="250" height="250" class="graph photoshop">
      <circle class="graph-line-2 four" cx="50%" cy="50%" r="100" stroke-width="20" fill="none" stroke="#2ECBE4" />
      <circle class="graph-line four" cx="50%" cy="50%" r="100" stroke-width="22" fill="none" stroke="#fff" opacity="0.92" />
      <text class="graph-text" text-anchor="middle" x="50%" y="-46%" fill="#fff">Photoshop</text>
     </svg>



<svg width="250" height="250" class="graph photoshop">
      <circle class="graph-line-2 five" cx="50%" cy="50%" r="100" stroke-width="20" fill="none" stroke="#2ECBE4" />
      <circle class="graph-line five" cx="50%" cy="50%" r="100" stroke-width="22" fill="none" stroke="#fff" opacity="0.92" />
      <text class="graph-text" text-anchor="middle" x="50%" y="-46%" fill="#fff">Photoshop</text>
     </svg>



<svg width="250" height="250" class="graph photoshop">
      <circle class="graph-line-2 six" cx="50%" cy="50%" r="100" stroke-width="20" fill="none" stroke="#2ECBE4" />
      <circle class="graph-line six" cx="50%" cy="50%" r="100" stroke-width="22" fill="none" stroke="#fff" opacity="0.92" />
      <text class="graph-text" text-anchor="middle" x="50%" y="-46%" fill="#fff">Photoshop</text>
     </svg>

Here's the codepen if you prefer

mrseanbaines
  • 823
  • 2
  • 12
  • 25
  • Shouldn't you use $(window)? here's a link to understand better http://stackoverflow.com/questions/17441065/how-to-detect-scroll-position-of-page-using-jquery – relentless-coder Dec 14 '16 at 13:49
  • Confused with your question, what do you mean with `add class when element comes into viewport?`. Btw, window.onload is the best option if you want to execute your js after all element have been loaded (render) http://stackoverflow.com/questions/588040/window-onload-vs-document-onload – Alfian Busyro Dec 14 '16 at 14:00
  • @arufian When the element is visible... The class I'm adding contains an animation which, obviously, I don't want to play before the user scrolls down to where the element is in view. – mrseanbaines Dec 14 '16 at 14:06

2 Answers2

9

You could do something like this: (See CodePen for implementation)

Function taken from here: Check if element is visible after scrolling

CodePen

$(window).on('scroll', function() {
  $(".graph").each(function() {
    if (isScrolledIntoView($(this))) {
      $(this).find(".graph-line").addClass("graph-75");
      $(this).find(".graph-line-2").addClass("opacity");
    }
  });
});

function isScrolledIntoView(elem) {
  var docViewTop = $(window).scrollTop();
  var docViewBottom = docViewTop + $(window).height();

  var elemTop = $(elem).offset().top;
  var elemBottom = elemTop + $(elem).height();

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

Altough this is not perfect, it should point you into the right direction.

Community
  • 1
  • 1
Founded1898
  • 977
  • 5
  • 13
  • You literally just copy + pasted the answer from the link I provided? – Craig Dec 14 '16 at 15:02
  • 1
    Haven't seen your answer when i wrote mine. Researched it by myself, we just ended on the same SO Question... Also note that i created a CodePen where i tested the solution, so its not just copy + pasting. – Founded1898 Dec 14 '16 at 15:14
  • Fair enough, it was just 20 minutes after mine! I guess a quick google is really all it takes. – Craig Dec 14 '16 at 15:23
  • @Founded1898 Thanks, both of you! That worked perfectly. I'm just wondering now if I can adjust the size of the gap between when the element comes into view and when the class is added. ie. I would like the class added at an earlier stage of scrolling, say, when the element is half in view. – mrseanbaines Dec 14 '16 at 21:43
  • 1
    @Sean well, you could change the return statement of the function so that it checks the elemTop & elemBottom minus half the height of your svg. Maybe something like this: `return ((elemBottom - circleHeight <= docViewBottom) && (elemTop - circleHeight >= docViewTop));` whereas circleHeight is `elem.height() / 2` – Founded1898 Dec 15 '16 at 13:32
1

You're on the right track, I think if you use the scroll event with a function such as the answer to this similar question:

Check if element is visible after scrolling

Hope that helps :)

Community
  • 1
  • 1
Craig
  • 332
  • 1
  • 7