ElevenEggos ElevenEggos - 1 month ago 7
jQuery Question

Convert script from manual text input to pre-defined message

I found this script on CodePen that allows you to simulate the light wall from Stranger Things, currently you have to manually enter a message for the lights to light up and I was wondering how I could make it so that you could enter a pre-defined message in the script and loop it with a timer.

Codepen

// Using jQuery because I'm lazy
var str = "Hello";
var lights = {

// Set up event listeners for keyboard keys
init: function() {

// Use pre-defined message
for (var i = 0, len = str.length; i < len; i++) {
var el = $('#item--'+str[i]);
setTimeout(function () {
lights.blink(el);
}, 3000);
}

// Every time a key is pressed...
$(document).keypress(function(e){
// ... get its value
// and find the matching DOM element, if any...
var ch = String.fromCharCode(e.charCode),
el = $('#item--'+ch);
// ... then send it to the 'blink' function
lights.blink(el);
// If user hits enter, flash everything randomly
// Kinda crappy effect, I know
if (e.which === 13) {
lights.random();
}
});

// Lights also respond to being clicked
$('.item').on('click',function(e){
lights.blink($(this));
});
},

// Turn a single bulb on and off
blink: function(el){
var bulb = el.find('.bulb');
bulb.addClass('lit');
setTimeout(function(){
bulb.removeClass('lit');
},600);
},

// Flash lights randomly
random: function(){
(function(count){
if (count < 36) {
var caller = arguments.callee;
window.setTimeout(function() {
var rand = Math.floor(Math.random() * 26) + 1;
var el = $('.item').eq(rand);
var el2 = $('.item').eq(rand*2);
lights.blink(el);
lights.blink(el2);
$('html').toggleClass('flicker');
caller(count + 1);
}, Math.floor(Math.random() * 100));
}
})(0)
}
}

$(function(){
lights.init();
})

Answer

Here is a working example. I have removed the keypress event to prevent typing a message over the predefined one. You could always just put it back.

First let's discuss what the issue is with your code attempt. You are calling timeOut inside the for loop which essentially creates a problem where you fire all these time out request at once. You have to make a timer request one after another.

In my code, I use setInterval to run the defined function about once a second. The function gets the next character to blink, figures out which element on the page it corresponds to then calls the blink function on that element (letter on the page). At the end, I do a simple bounds check to loop back to the first letter.

One other thing to note is that your HTML elements are all defined with lowercase identifiers (item--h instead of item--H) so this solution only works with a predefined string that contains lowercase letters. I'll leave that as exercise to figure out how to correct for uppercase as well as detect non-letter characters (a space, numbers, etc.) and skip them.

// Using jQuery because I'm lazy
var str = "hello";
var strCounter = 0;
var lights = {

  // Set up event listeners for keyboard keys
  init: function() {

    // Use pre-defined message
    setInterval(function() {
      console.log('Blinking: ' + str[strCounter]);
      var ch = str[strCounter];
      var el = $('#item--'+ch);
      // ... then send it to the 'blink' function
      lights.blink(el);

      // next character in the message and bounds check
      strCounter += 1;
      if (strCounter >= str.length) {
        strCounter = 0;
      }
    }, 1000);

    // ALL CODE BELOW IS UNCHANGED AND KEYPRESS FUNCTION IS REMOVED

    // Lights also respond to being clicked
    $('.item').on('click',function(e){
      lights.blink($(this));
    });
  },

  // Turn a single bulb on and off
  blink: function(el){
    console.log(el);
    var bulb = el.find('.bulb');
    bulb.addClass('lit');
    setTimeout(function(){
      bulb.removeClass('lit');
    },600);
  },

  // Flash lights randomly
  random: function(){
    (function(count){
      if (count < 36) {
        var caller = arguments.callee;
        window.setTimeout(function() {
          var rand = Math.floor(Math.random() * 26) + 1;
          var el = $('.item').eq(rand);
          var el2 = $('.item').eq(rand*2);
          lights.blink(el);
          lights.blink(el2);
          $('html').toggleClass('flicker');
          caller(count + 1);
        }, Math.floor(Math.random() * 100));
      }
    })(0)
  }
}

$(function(){
  lights.init();
})