A javascript Piano(An invitation to review my code)

In line with doing things on my own, yesterday I built a keyboard with vanilla Js. I watched a tutorial by WebDevSimplified on Youtube and saw that he used arrays for the white and black keys, but I had to break through the pattern of copying and decided to go with storing all my piano's information in an array of objects. I decided not to create the keys in my html, but instead to display them dynamically with javascript.

image.png

My html file is basically empty with just a placeholder div for the piano:

 <div class="piano"></div>

The piano looks like this:
https://liz-piano.netlify.app/

Nothing too fancy because I will be changing the css later.

Now, for the Javascript. I created an array of objects like I stated earlier to implement this in an OOP fashion. A snippet of this can be found here:

const data = [
  {
    keyColor: "white",
    keyNote: "C",
    keyAudio: "notes/C.mp3",
    keyLetter: "z",
  },
  {
    keyColor: "black",
    keyNote: "Db",
    keyAudio: "notes/Db.mp3",
    keyLetter: "s",
  },
  {
    keyColor: "white",
    keyNote: "D",
    keyAudio: "notes/D.mp3",
    keyLetter: "x",
  },
etc]

So there are 4 keys;keyColor, keyNote, keyAudio and keyLetter

I wrote a function for the data to be able to create the keys with a createPianoKey() function:

function createPianoKey(item) {
  const pianoKey = document.createElement("div");
  const { keyColor, keyNote, keyAudio, keyLetter } = item;
  const styles = ["key", keyColor];
  pianoKey.classList.add(...styles);
  piano.appendChild(pianoKey); 
}

I destructured each of the keys in my array of objects and stored them in the 'item'

I was looking for a way to add multiple styles to the keys and since I have .white and .black styles, at first I tried to add them in my array of styles, but for some reason the .black styles ended up overlapping. On reddit, someone suggested that I match the .key style with the keyColor key and this worked fine. That was a cool trick to know.

I wanted the keys to reflect the keyLetters since there was nothing in the html and so I added the following line in my fucntion:

pianoKey.innerHTML =

<span style='font-weight:bold;font-size:30px; color:teal; '>${keyLetter}</span>;

Next was thinking of how to add the sounds upon clicking the keys. I did the following:

const sound = new Audio();
 pianoKey.addEventListener("click", () => {
   sound.src = keyAudio;
   sound.play();
   pianoKey.classList.add("active");

   setTimeout(function () {
     pianoKey.classList.remove("active");
   }, 1000);
 });

I consoled.logged keyAudio, so I knew that each key was correctly associated with the audionote for the key. The setTimeout was necessary to remove the active class upon clicking the key.

I also wanted the user to be able to utilize their keyboard so I needed to write a keydown event listener function:

document.addEventListener("keydown", (e) => {
    if (e.key == keyLetter) {
      sound.src = keyAudio;

      sound.play();
      pianoKey.classList.add("active");

      setTimeout(function () {
        pianoKey.classList.remove("active");
      }, 1000);
    }

The keydown takes an event and if you write a simple console.log like :
console.log(key=${e.key},code=${e.code}); you will be able to see the keycode of every key you have pressed. Also, I could not add the eventListener directly on the pianoKey as I did with the clickListener because this event listener listens to the activities on the window. I hope this is a correct way of explaining things.

So, my entire function block looks like this:

data.forEach(createPianoKey);


function createPianoKey(item) {
  const pianoKey = document.createElement("div");



  const { keyColor, keyNote, keyAudio, keyLetter } = item;

  const styles = ["key", keyColor];
  pianoKey.classList.add(...styles);
  piano.appendChild(pianoKey);

  pianoKey.innerHTML = `${keyLetter}`;



  const sound = new Audio();
  pianoKey.addEventListener("click", () => {
    sound.src = keyAudio;
   

    sound.play();
    pianoKey.classList.add("active");

    setTimeout(function () {
      pianoKey.classList.remove("active");
    }, 1000);
  });

  document.addEventListener("keydown", (e) => {

    if (e.key == keyLetter) {
      sound.src = keyAudio;

      sound.play();
      pianoKey.classList.add("active");

      setTimeout(function () {
        pianoKey.classList.remove("active");
      }, 1000);
    }
  });
}


I have some repeated code which is visible in the following lines:

sound.src = keyAudio;
  

   sound.play();
   pianoKey.classList.add("active");

   setTimeout(function () {
     pianoKey.classList.remove("active");
   }, 1000);

I'm wondering if I could get some help refactoring those lines in a new function and also some suggestions on what could be done better using OOP principles.

please note I'm aware the css is not optimized for phones unless you auto-rotate. I have it in mind to code a 3d version of this, as I'm more focused on the Javascript bit.

Thanks!

H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now
Logo
Center