2
\$\begingroup\$

The data (news items) comes from a <ul>. I'm using setInterval and setTimeout for the timing aspects, and jQuery animate for the movement to the right. I know that setInterval and setTimeout start acting weirdly when the tab is not active, but that's not a problem for my specific use-case.

I'm looking for any comments, specifically the entire displayItem() function -- is there a better way to do this?

var items = [];
$('.news li').each(function() { //get all items from <ul> and add to array
  items.push($(this).html());
});

//Ticker
var duration = 5000; //take 5 seconds to show one item
$('.news ul').remove();
$('.news').append('<span class="title">Headlines</span><span class="item"></span>');

function displayItem(html, i) {
  setTimeout(function() {
    $('.news .item').html(items[i]).animate({
      "left": "+=400px"
    }, {
      duration: duration,
      easing: "linear",
      complete: function() {
        $('.news .item').css('left', '0');
      }
    });
  }, (duration + 75) * i);
}

function loopAndDisplayItems() {
  for (var i = 0; i < items.length; i++) {
    var time = (i + 1) * 1000;
    displayItem(items[i], i);
  }
}

setInterval(loopAndDisplayItems, items.length * duration);
loopAndDisplayItems();
.news {
  border-radius: 7px;
  background-color: lightgray;
  padding: 8px;
  font-size: 12px;
}
.news .title {
  color: red;
}
.news .item {
  margin-left: 5px;
  position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='news'>
  <ul>
    <li>Headline 1</li>
    <li>Headline 2</li>
  </ul>
</div>

\$\endgroup\$
2
\$\begingroup\$

Reminds me of the days where <marquee> was the easiest way to add this kind of animation.

In terms of markup, your markup makes sense. However, I suggest you also move the title inside the markup instead of being in the JS.

With regards to your problem with timers, browsers usually slow down timers when the tab is inactive. This is to conserve battery life. As far as I know, setInterval, setTimeout and requestAnimationFrame are all affected.

Another problem I see is you animate in intervals. You don't let the animation finish before animating the next item. What you should do here is put your animation in a function, and when it finishes, it calls itself recursively from the complete callback. That way, you know it finishes before pulling in the next item.

Now if you don't mind CSS3, you can simply use transition or the more advanced animation property coupled with @keyframes block.

Now here's my take on your problem. The main difference here is I animate the entire list. That way, I only need to deal with 1 item when animating. There is a padding on each item to show a gap between items.

var list = $('.news ul');
var totalWidth = 0;
var items = $('.news li').each(function(){
  totalWidth += $(this).outerWidth();
});

function scrub() {
  // Note that we added a wrapper. That's so the entire list scrubs in,
  // and you don't have to deal with it individually.
  list.animate({
    // We animate the left all the way past negative so text travels from
    // right to left and we read left to right.
    left: -totalWidth
  }, {
    easing: 'linear',
    // We adjust speed here. Here it is 20ms per pixel.
    duration: totalWidth * 20,
    complete: function(){
      // When the animation is done, we just move the element back to its
      // starting position, which is off-screen to the right.
      $(this).css({ left: '100%' });
      // Run scrub again.
      scrub();
    }
  });
}
// Start the scrub
scrub();
.news {
  border-radius: 7px;
  background-color: lightgray;
  padding: 8px;
  font-size: 12px;
  overflow: hidden;
}
.news header {
  float: left;
  color: red;
}
.news .wrapper {
  overflow: hidden;
}
.news ul {
  left: 100%;
  position: relative;
  margin: 0;
  padding: 0;
  list-style: none;
  white-space: nowrap;
}
.news li {
  padding-right: 50%;
  min-width: 100%;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='news'>
  <header>Headlines</header>
  <div class="wrapper">
    <ul>
      <li><strong>Foo!</strong>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ac ligula nec tortor facilisis pharetra a ut arcu. Ut lacus libero, finibus sit amet risus id, rutrum malesuada odio.</li>
      <li><strong>Bar!</strong>Aliquam luctus dapibus eros id eleifend. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ac tellus sem. Integer laoreet sem in ex tincidunt fringilla.</li>
    </ul>
  </div>
</div>

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.