How can I add a pulse animation to a div in an array of divs, in Javascript?


Tags: javascript,html,css,animation,css-transitions

Problem :

I have an array of divs that I create programmatically, like so:

// Create grid of pads dynamically, 16x16 in size
var padIdCount = 0;
for (var i = 0; i < 16; i++) {
    for (var j = 0; j < 16; j++) {
        var newPad = document.createElement("div");
        WinJS.Utilities.addClass(newPad, "pad");
        WinJS.Utilities.addClass(newPad, "row" + i);
        WinJS.Utilities.addClass(newPad, "col" + j);
        newPad.id = "pad" + padIdCount;
        document.getElementById("padContainer").appendChild(newPad);
        padIdCount++;
    }

    // Add a single line break after 16 pads
    var newLineBreak = document.createElement("br");
    document.getElementById("padContainer").appendChild(newLineBreak);
}

Pads are dark grey, but if a user taps on a pad it becomes an "active pad"

// Assign handler to pads, to toggle activation on click
var pads = document.querySelectorAll(".pad");
for (var padCount = 0; padCount < pads.length; padCount++) {
   pads[padCount].addEventListener("click", togglePadActivation, false);
}

function togglePadActivation(e) {
    // Get id of pad in question
    var padId = e.target.id;

    // Change pad from active to inactive and vice versa
    var clickedPad = document.getElementById(padId);
    WinJS.Utilities.toggleClass(clickedPad, "activePad");
}

Styles

    /* dark grey */
    .pad {
        height: 40px;
        width: 40px;
        margin: 1px;
        padding: 0px;
        background-color: #363636;
        display: inline-table;
    }

    /* dark orange */
.activePad {
    background-color: orangered;
    opacity: 0.6;
}

.playingPad {
    background-color: orangered;
    opacity: 0.6;
    /* workaround for pulse bug */
    animation: pulselightonanimation 3.2s ease-out;
    animation-iteration-count: infinite;
}

@keyframes pulselightonanimation {
    0% {opacity: 1.0;}
    50% {opacity: 0.8;}
    100% {opacity: 0.6;}
}

Now that setup is complete, and event handlers are hooked up, the user can click a button that starts looping through all active pads (row 1 first, simultaneously, then row 2 simultaneously, and so on). To achieve this, I implemented a setTimeout.

// Run this method every 200ms
function playActiveNotes(rowCount) {
    timer = setTimeout(function () {

        // Reset after the last row, because we are looping indefinitely
        if (rowCount === 16) {
            rowCount = 0;
        }

        // Select all pads from the same row at once
        var currentRow = ".row" + rowCount;
        var currentRowPads = document.querySelectorAll(currentRow);

        // Cycle through each pad, animate and play it if active
        for (var padCount = 0; padCount < currentRowPads.length; padCount++) {

            // If the pad is active play the note
            if (WinJS.Utilities.hasClass(currentRowPads[padCount], "activePad")) {

                // Show the pulse animation
                WinJS.Utilities.addClass(currentRowPads[padCount], "playingPad");

                // TODO: Play short mp3 file here

                // Remove the animation class. This is where it fails
                //currentRowPads[padCount].addEventListener("animationend", callback(currentRowPads[padCount]), false);
                //currentRowPads[padCount].addEventListener("transitionend", callback(currentRowPads[padCount]), false);

                // If I use a nested setTimeout, this removeClass code never gets called. If I comment it out, I don't see the pulse, i.e. add + remove happens too quickly
                //setTimeout(function () {
                    if (padCount < 16)
                        WinJS.Utilities.removeClass(currentRowPads[padCount], "playingPad");
                //}, 1000);

            }
        }

        // Go to the next row
        rowCount++;

        // Then call self to setup a recursive loop.
        playActiveNotes(rowCount);
    }, 200);
}

function callback(element) {
    element.classList.remove('playingPad');
}

When the active pad is being played (I play a short mp3 file), I want it to pulse, i.e. become bright orange quickly (but not instantaneously), then fade back to the original dark orange. How can I achieve this? I tried using a playing pad class with css animation, and removing the class on transitionend/animation end, but that didn't work.

Use of WinJS is allowed in addition to Javascript, but no JQuery.



Solution :

I think if somehow you can get a CSS animation going, that that would still be the best solution.

However, this is an alternative solution, using CSS transitions:

/* dark grey */
.pad {
    height: 40px;
    width: 40px;
    margin: 1px;
    padding: 0px;
    background-color: #363636;
    display: inline-table;
}

/* dark orange */
.activePad {
    background-color: #B2371B;
    transition: background-color .5s;
    -webkit-transition: background-color .5s;
}

/* bright orange */
.brightPad {
    background-color: #FFFFFF;
    transition: background-color .1s;
    -webkit-transition: background-color .1s;
}

This should make it so that if you add the .brightPad class to a pad, that it goes quickly to bright orange (in .1s). As soon as you remove that class and set .activePad again, it should go slowly back to dark orange (.5s). You will have to set the .brightPad right on touch, and then remove it again using a timeout of 100ms or more.

Here is a quick JSFiddle: http://jsfiddle.net/R5VjH/1/

(sorry, used white instead of picking a nice bright orange)


    CSS Howto..

    How to apply css, after Jquery adds a class?

    Want to duplicate css styles for an ID based style, how to do this with least duplication?

    How to customize the EditorFor CSS with razor

    How Can I use CSS to Add an Element Below another Element?

    How is a CSS “display: table-column” supposed to work?

    How do you create an arrow for sub navigation like this?

    How can I apply my CSS stylesheet to an RSS feed

    How to include Glyphicons without using Bootstrap CSS

    How to select nth line of text (CSS/JS)

    How to align multiple input using css

    How do i add a fading border to my nav bar CSS

    How to rotate a div, while jQuery animates the same div

    How to display a div next to another div with no width defined?

    how to apply stylesheet to wp frontend, via plugin i created?

    How to deal with different stylesheets (WYSIWYG Editor and Webpage one) in the same page?

    CSS - How to make IE7 respect min-width

    CSS Have a div which can fit 5 li per row how to make 6 go to new line

    How to make background image with aspect ratio in html and css [closed]

    A scrollbar showing within DIV. What CSS is causing this?

    How can I remove a bootstrap buttons hover effect?

    How to preserve styles of embedded widget?

    How to display (
  • ) menu items over divs - z-index not working
  • How to convert a HTML/CSS template to haml/sass template? [closed]

    how to pause css animation on hover using jquery

    How can I make clickable list with sublinks ?

    CSS: how to layout 3 columns, 2 are optional

    how to customize css ellipse for a text string [duplicate]

    How to reference JSF image resource as CSS background image url

    How to define CSS styles if Javascript is turned off? [duplicate]

    How do I require main.css.erb in application.css