Question

I wrote some JQuery and JS to power a single message element that:

  • reads a new message from an array for each loop
  • starts off-screen,
  • animates right, to center screen for 1/4 of the loop duration
  • waits at the center to be read for 1/2 of the loop duration
  • animates right again, off screen for another fourth of the loop duration
  • changes to the next loop with a new message
  • repeats

And what sounds like a simple task became (in relation to the feature) many lines of code:

function flow(i, duration){

    var message = Game.activities[i]

    var transTime = duration / 4;

    var idleTime = duration / 2;

    var windowDouble = $(window).width() * 2;

    $(".message-flow").text(message);

    $(".message-flow")
    .animate({transform:"translateX(-" + windowDouble + "px)"},0)
    .animate({transform:"translateX(0px)"},transTime)
    .delay(idleTime)
    .animate({transform:"translateX(" + windowDouble + "px)"},transTime);

}

function flowFunc(i, duration){

    return function(){

        flow(i, duration);

    }
}


function activityFlowInit(duration){

    var delay = 0;

    for (var i = 0; i < Game.activities.length; i++){

        setTimeout(flowFunc(i, duration),delay);

        delay += duration;

    }

    totalDuration = duration * Game.activities.length;

    setTimeout(function(){
        activityFlowInit(duration);
    },totalDuration);

}

Which produces a timing flaw where the message slowly begins to change during the transition period rather than when hidden;


I then thought of removing all of this code (which handles closures, in the midst of it all) and replacing the message's animation functionality with 11 simple lines of CSS:

.message{
   animation: transit 4s;
   animation-iteration-count:infinite;
}

@keyframes transit
{
   0% {transform:translateX(-150%)}
   25% {transform:translateX(50%)}
   75% {transform:translateX(50%)}
   100% {transform:translateX(150%)}
}

Afterwards changing the message at a set interval, in coordination with the time that the message is off screen.

However, I don't know how I can do this.

I'm thinking I need some sort of hybrid of setInterval and a loop; a loop that only loops after an interval of time has passed.


How is this (or the next best thing) achieved?

Was it helpful?

Solution

I started thinking about the way a loop and setInterval() works, and I realized that what a loop is really doing is setting an interval of 0, checking a condition and then incrementing a variable. I can make my own for loop-setInterval hybrid by setting the interval, (in my case) skipping the condition, and incrementing my own variable.

JS:

var i = 0;
var messages = ["message 1", "message2", "message 3"];

function writeAdd() { // Handling the closure

    return function () {
        $(".message").text(messages[i]);
        //if (condition === true){ // condition excluded
            i++;
            if(i === messages.length) i = 0; //creating the loop's repetition
        //}
    };
}

function loopMessage(duration) {
    $(".message").css("-webkit-animation-play-state","running");
    setInterval(writeAdd(), duration); //setting the interval
}

loopMessage(4000);

CSS:

.message-flow{
    -webkit-animation: transit 8s;
    -webkit-animation-iteration-count:infinite;
    -webkit-animation-play-state:paused;
}

@-webkit-keyframes transit {
    0% {
        -webkit-transform:translateX(-2000px);
    }
    25% {
        -webkit-transform:translateX(0px);
    }
    75% {
        -webkit-transform:translateX(0px);
    }
    100% {
        -webkit-transform:translateX(2000px);
    }
}

The JSFiddle


Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top