Hello everyone,
Hope you all are safe during this pandemic. I have started a new series where I will be posting Javascript projects for beginners.
Each post in this series mainly comprises of two things,
1. TIL while building them.
2. Project explanation.
So Let's start,
What we are gonna build today is a Virtual Drum which,
1. Has visual representation of the keys
2. Plays a audio file when pressing its
corresponding key
3. A small animation indicating that the particular
key is pressed - Scales up(make it appear big)
for a fraction of a second and scales down while
maintaining a smooth transition.
TIL
1. transitionend
It is an event Listener which gets triggered when the transition gets over as the name specifies. To know its use case read the entire post.
2. data-*
Data attribute allow authors to create custom data to apply to their HTML elements to store extra data. They help extend the information that HTML can communicate to script.
3. defer vs window.onload
Both are used to load the script after the document has finished parsing inorder to prevent the script accessing the DOM elements even before parsing stage is over. Using defer and window.onload are not the same even though they serve the same purpose of loading script. Load events are triggered only after deferred scripts run.
4. background-size
cover:
Resize the background image to cover the entire container, even if it has to stretch the image or cut a little bit off one of the edgescontain:
Resize the background image to make sure the image is fully visibleauto:
Default value. The background image is displayed in its original size
Project Explanation
<div class="parent-key">
<div data-key=65 class="key">
<div>A</div>
<span>Clap</span>
</div>
</div>
<audio data-key=65 src="sounds/boom.wav"></audio>
This is the basic markup for a single key and its corresponding audio. audio
is the tag which is used to include sound in html . It has got the audio api which can be used to manipulate the audio file to play, pause, reset ... and much more. Data-*(data attribute) has the value equivalent to the ASCII value of the key.
body {
background-image: url('background.jpg');
background-size: cover;
}
.parent-key {
display: flex;
justify-content: space-around;
align-items: center;
min-height:100vh;
flex-wrap: wrap;
}
.key {
color: white;
font-size: 40px;
border:3px solid black;
background-color: rgba(0,0,0,0.4);
padding: 10px;
text-align: center;
text-transform: uppercase;
letter-spacing: .1rem;
transform: scale(1);
transition: all 0.2s ease;
}
.key span {
font-size: 14px;
color: #ffc600;
}
.playing {
transform: scale(1.2);
border: 4px solid #ffc600;
box-shadow: 0 0 1rem #ffc600;
}
For the styling part of the markup, I have used flex
to center align the keys vertically and horizontally. Background image is included using the url .For remote image, url is specified and for image available in your directory, path is specified.The class playing
is added to the element when the key corresponding to the key in the UI is pressed and removed after a fraction of a second. The class playing
makes the element bigger in size(transform: scale(1.2)), applies larger border and box-shadow(highlights the box).
Till now we have completed the markup and styling part. Now let's give functionality to the virtual drum kit. When a key is pressed,
1. Play the ``audio``
2. Attach the class ``playing``
3. Remove the class ``playing`` after the
transition is over.
Let's attach an eventListener(keydown
) to the window object so that whenever a key is pressed the eventListener gets triggered and the function execution starts. We should execute the function only if you press the keys for which the audio must be played, so let's give a if-check which looks for the audio element in the html file using the keyCode corresponding to the key pressed.
window.addEventListener('keydown',function(e){
let audio = document.querySelector(`audio[datakey="${e.keyCode}"]`)
if(!audio) return;
})
Using the audio element we now can play the audio using the play method in the audio element api- audio.play()
. when you run the code , when you press the key you want to play the audio file , audio is played but there is a problem here. Lets say the audio file is for 3 seconds for a particular beat, you cannot be waiting till the audio file finishes(in the case you want to press the same key multiple times),so we must reset the time to zero(audio.currentTime = 0;
).By now, if you press the audio keys we can hear the corresponding sound.
But we need some animation to indicate that the particular key is pressed. This can be done by adding the class playing
to pressed key element with a smooth transition using the transition
property in css. Get the key from the document api and add the class to it.
window.addEventListener('keydown',function(e){
if(!document.querySelector(`audio[data-key="${e.keyCode}"]`)) return;
let audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
let key = document.querySelector(`.key[data-key="${e.keyCode}"]`)
audio.currentTime = 0;
audio.play();
key.classList.add('playing');
})
Now when we press the key, the key element in UI scales up, but we need to scale down by removing playing
class after a fraction of second. One way of doing this using setTimeout
function. Using this function we can delay for a fraction of a second of a second and remove the class. It works fine but the issue we will face is, sometimes it messes up with the transition property in css(transition: all .07s ease;
). The better way of handling this situation is listening to transitionend
event, which executes a function when the transition ends. So now we can remove the class playing
after the transition gets over.
window.addEventListener('keydown',function(e){
if(!document.querySelector(`audio[data-key="${e.keyCode}"]`)) return;
let audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
let key = document.querySelector(`.key[data-key="${e.keyCode}"]`)
audio.currentTime = 0;
audio.play();
key.classList.add('playing');
})
let keys = document.querySelectorAll('.key');
keys.forEach((key)=>{
key.addEventListener('transitionend',function(){
this.classList.remove('playing')
})
})
I hope you were able to learn how to make a virtual drum. Follow me to read more javascript projects and don't forget to like because it will motivate me π.
Assets(audio files and background image) and code files available in this repoππ»
prashanthsasidharan / javascript-projects
This repo consist of assets and code files for every js project I create.
javascript-projects
This repo consist of assets and code files for every js project I create.
Header Image By PlayTheTunes
Top comments (0)