Saturday, December 31, 2016

JS30 Challenge Day1 - JS Drum Kit

Here are the things I learned from Day 1 of the JS30 challenge:

Github Link
  • HTML/CSS

Reminded me of putting the following in every project
<html lang="en-US">
<meta charset="UTF-8">
and optionally
<meta name="author" content="Arjun Khode">

To add the stylesheet, we use href and not src.
<link rel="stylesheet" href="style.css">

-We can find the keyCode of each key on the site keycode.info

What <kbd> does
The HTML Keyboard Input Element <kbd> represents user input and produces an inline element displayed in the browser's default monospace font.

I gave a transparent background to the drum item using rgba()

In box shadow, the 0 0 15px was not bright enough, so I used the 4th parameter ‘spread’ to make the shadow-spread more vivid, as: 0 0 15px 5px

The align-items in the flexbox wasn’t working by default because it had no height of its own. I had to give a height of 100vh to the flexbox element to get the contents to appear in the vertical center.


  • JS

We bind an event to our keys when they are pressed, as follows:
window.addEventListener(‘keydown’, function(e){}) //note keydown is in quotes. And it is window, not document.
document stands for DOM
and window is the global object in a browser, or the root object of the DOM

Inside the function, we write
const audio=document.querySelector(‘’);
the document.querySelector acts like $() in jQuery

Inside the querySelector, we write
`audio[data-key=“{e.key}”]` //where data-key has to have its value in double quotes, the whole querySelector expression has to be in back ticks (`) for template literal notation and the value is a variable inside the event e, which is called keyCode, a property of event 'e'.

${} is just syntactic sugar. Read more about it here (look for “Expression interpolation”)

So we get
const audio = document.querySelector(`audio[data-key=“${e.keyCode}”]`);

audio.play();
if we keep hitting a key, it needs to rewind to the beginning
so we add,
audio.currentTime=0; before audio.play(); The 0 stands for seconds.

I have defined a .play class in CSS which makes the items glow when the corresponding key is pressed

To add a class to an element, we use item.classList.add(‘className’);
This is the same as element.addClass(‘className’); in jQuery

Instead of removing the class play normally, we remove the play class on the transitionend event of the transform property

Regarding forEach, it is not just forEach but items.forEach(); which means that forEach function is a property of an array.

One final comment:
This app does not work well on Safari because it takes too long for Safari to parse the keydown event.
It works great on Chrome though.

UPDATE:

Here is the code to enable playing by clicking on the buttons as well



//code for click functionality
const items=document.querySelectorAll('.item');

function clickTrigger(){
let key=(this.dataset.key);
const audio=document.querySelector(`audio[data-key="${key}"]`);
const item=this;
item.classList.add('play');
audio.currentTime = 0;
audio.play();

}

function unclickTrigger(){
this.classList.remove('play');
}
items.forEach(item=>item.addEventListener('mousedown',clickTrigger));
items.forEach(item=>item.addEventListener('mouseup',unclickTrigger));

Explanation:

1.Select all item divs and call them "items"

const items=document.querySelectorAll('.item');

2. Attach mousedown and mouseup events to every item in "items" using forEach

items.forEach(item=>item.addEventListener('mousedown',clickTrigger));
items.forEach(item=>item.addEventListener('mouseup',unclickTrigger));

3. Create function clickTrigger and unclickTrigger

4. clickTrigger function explanation:

In clickTrigger, "this" variable will select the particular "item" div clicked.
Inside "this" we have a data-key property.

To access any data- element in JS, we use "dataset" property
So, if you have data-key, it becomes:

dataset.key

Store the data-key of the clicked item in a variable called "key"
let key=(this.dataset.key);

Then using key, select corresponding audio to trigger
const audio=document.querySelector(`audio[data-key="${key}"]`);

(Notice how "key" variable has been slid into the template string)

Then simply add the regular code to add to item a class "play" (for the animation)
and play the audio
audio.play();

5.unTrigger function explanation:

Simply remove the class play from "this" (which is the item div on which mouseup has happened)
This removes the animation

6 comments:

  1. Hi, mate! How can we do the same acts by clicking mouse, not only with pressing buttons on keyboard?

    ReplyDelete
    Replies
    1. Hi Igor, I have updated this post with the solution for your problem. I hope that helps. Let me know if you have any questions :)

      Delete
    2. What is item div here?
      There's nothing like this in index.html. Can u please help?
      I have been trying to do this for quite some time now.

      Delete
  2. Hiya Arjun,

    Thanks for posting. Question: To make use of the audio files, did you clone Wes's repo into a directory on your local machine? Just trying to figure out how to get those drum sounds. Thanks

    ReplyDelete
  3. Thank you very much.
    This is my first JavaScript project. I do not know almost anything. I really wanted to make it work for a click but it took hours without progress. I learned something new with your solution. Thank you very much.
    In case you want to look at it. https://lunkaz.github.io/cutie-keyboard/

    ReplyDelete
  4. Hi, i'm facing some problems about this project. if u hold a key e.g. "A" about 2-3sec and use the mouse, removeTransition will not be able to work again for that specific key. And it will cause problems.. is it same on your device and how we can solve this problem thanks..

    ReplyDelete