Play drums using Lightning Web Component. In this article we we learn some new concepts in LWC with some interesting example.
Are you ready ? Let’s Begin !
playDrums.html
<template>
<main>
<section class="main-wrapper">
<div class="key-map-wrapper">
<h2>Key Mapping</h2>
<ul class="key-map-list">
<template for:each={SOUND_KEYS} for:item="currentItem">
<li key={currentItem.code}>
<kbd class="key-code" >{currentItem.code}</kbd>
<span class="key-sound">{currentItem.sound}</span>
</li>
</template>
</ul>
</div>
<h1 class="main-title"> Play drums using <br/>Lightning Web Component</h1>
<div class="drum-kit-wrapper">
<img class="crash-ride crash-cymbal" ontransitionend={removeCrashRideTransition} src="https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/img/crash.png" alt="Crash cymbal">
<img class="hihat-top hihat-top-cymbal" ontransitionend={removeHiHatTopTransition} src="https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/img/hihat-top.png" alt="Hi Hat cymbal">
<!-- https://theasciicode.com.ar/ adding ascii on div using data-key -->
<template for:each={DRUM_KEYS} for:item="currentItem">
<div key= {currentItem.key} data-key={currentItem.key} ontransitionend={removeKeyTransition} class={currentItem.class}>
<kbd>{currentItem.kbd}</kbd>
</div>
</template>
<img class="drum-kit" src="https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/img/drum-kit.png" alt="Drum Kit" />
</div>
</section>
</main>
<!-- one audio for one div-->
<template for:each={SOUNDS} for:item="currentItem">
<audio key={currentItem.key} data-key={currentItem.key} src={currentItem.url}></audio>
</template>
</template>
playDrums.css
html,body {
padding: 0;
margin: 0;
background-color: #fff;
}
.main-wrapper {
margin: 30px auto 0;
width: 1080px;
text-align: center;
}
.main-title {
font-family: 'Pacifico', cursive;
text-align: center;
font-size: 3.2em;
color: #cb2026;
text-shadow: 1px 1px 1px #5a0b0d;
padding-bottom: 50px;
}
.drum-kit-wrapper {
position: relative;
width: 600px;
margin: -100px auto 0;
}
.drum-kit {
width: 100%;
height: 520px;
position: relative;
}
.crash-cymbal {
position: absolute;
top: 114px;
left: 80px;
transform: rotate(-7.2deg) scale(1.5);
transition: all ease-in-out .042s;
}
.hihat-top-cymbal {
position: absolute;
top: 166px;
right: 71px;
transform: scale(1.35);
z-index: 0;
transition: all ease-in-out .042s;
}
.key {
display: inline-block;
transition: all ease-in-out .042s;
position: absolute;
background: #eaeaea;
font-size: 1.5em;
height: 32px;
width: 32px;
text-align: center;
border-radius: 4px;
border: 3px solid #aaa;
color: #444;
box-shadow: 1px 1px 1px rgba(0,0,0,.65);
z-index: 2;
}
.key.kick {
top: 355px;
right: 250px;
}
.key.kick2 {
top: 355px;
right: 308px;
}
.key.snare {
right: 145px;
top: 280px;
}
.key.tom-high {
right: 227px;
top: 240px;
}
.key.tom-mid {
left: 222px;
top: 220px;
}
.key.tom-low {
top: 320px;
left: 133px;
}
.key.crash {
top: 80px;
left: 75px;
}
.key.ride {
left: 165px;
top: 87px;
}
.key.hihat-open {
right: 165px;
top: 144px;
}
.key.hihat-close {
right: 60px;
top: 150px;
}
.playing {
transform: scale(1.12);
}
.key-map-wrapper {
position: absolute;
right: 0;
top: 0;
height: 700px;
background: #111;
width: 250px;
z-index: 3;
}
.key-map-wrapper > h2 {
color: #fff;
font-family: 'Handlee', cursive;
margin-bottom: 35px;
border-bottom: 1px solid #fff;
padding-bottom: 20px;
}
.key-map-list {
list-style: none;
color: #fff;
text-align: left;
}
.key-map-list > li {
margin-bottom: 25px;
}
.key-code {
color: #444;
background-color: #eaeaea;
font-size: 1.25em;
padding: 5px 10px;
border-radius: 4px;
border: 3px solid #aaa;
}
.key-sound {
font-size: 1.2em;
margin-left: 10px;
font-family: 'Handlee', cursive;
vertical-align: middle;
}
playDrums.js
import { LightningElement } from 'lwc';
const SOUNDS = [
{ key: "74", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/snare.wav"},
{ key: "66", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/kick.wav" },
{ key: "86", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/kick.wav" },
{ key: "72", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/tom-high.wav" },
{ key: "71", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/tom-mid.wav" },
{ key: "70", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/tom-low.wav" },
{ key: "69", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/crash.wav" },
{ key: "82", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/ride.wav" },
{ key: "73", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/hihat-open.wav" },
{ key: "75", url:"https://raw.githubusercontent.com/ArunMichaelDsouza/javascript-30-course/master/src/01-javascript-drum-kit/sounds/hihat-close.wav" }
]
const SOUND_KEYS = [{ "code": "E", "sound": "Crash" }, { "code": "R", "sound": "Ride" }, { "code": "F", "sound": "Floor tom" }, { "code": "G", "sound": "Mid tom" }, { "code": "H", "sound": "High tom" }, { "code": "V", "sound": "B" }, { "code": "J", "sound": "Snare" }, { "code": "I", "sound": "Hi-Hat Open" }, { "code": "K", "sound": "Hi-Hat Closed" }]
const DRUM_KEYS =
[{ "key": "74", "class": "key snare", "kbd": "J" }, { "key": "66", "class": "key kick", "kbd": "B" }, { "key": "86", "class": "key kick2", "kbd": "V" }, { "key": "72", "class": "key tom-high", "kbd": "H" }, { "key": "71", "class": "key tom-mid", "kbd": "G" }, { "key": "70", "class": "key tom-low", "kbd": "F" }, { "key": "69", "class": "key crash", "kbd": "E" }, { "key": "82", "class": "key ride", "kbd": "R" }, { "key": "73", "class": "key hihat-open", "kbd": "I" }, { "key": "75", "class": "key hihat-close", "kbd": "K" }]
export default class App extends LightningElement {
playingClass = 'playing';
SOUND_KEYS= SOUND_KEYS
DRUM_KEYS = DRUM_KEYS
SOUNDS = SOUNDS
connectedCallback(){
window.addEventListener('keydown', this.playSound);
}
playSound = e => {
const keyCode = e.keyCode;
console.log('keycode',keyCode);
var keyElement = this.template.querySelector(`div[data-key="${keyCode}"]`);
console.log('keyElement',keyElement);
const audioElement = this.template.querySelector(`audio[data-key="${keyCode}"]`);
audioElement.currentTime = 0;
audioElement.play();
switch(keyCode) {
case 69:
case 82:
this.animateCrashOrRide();
break;
case 73:
case 75:
this.animateHiHatClosed();
break;
}
keyElement.classList.add(this.playingClass);
};
animateCrashOrRide() {
console.log('inside animatedcrash ride');
this.template.querySelector('.crash-ride').style.transform = "rotate(0deg) scale(1.5)";
};
animateHiHatClosed() {
console.log('inside animateHiHatClosed');
this.template.querySelector('.hihat-top').style.top = "171px";
//hiHatTop.style.top = '171px';
};
removeCrashRideTransition = e => {
console.log('inside removeCrashRideTransition');
if(e.propertyName !== 'transform') return;
e.target.style.transform = 'rotate(-7.2deg) scale(1.5)';
};
removeHiHatTopTransition = e => {
console.log('inside removeHiHatTopTransition');
if(e.propertyName !== 'top') return;
e.target.style.top = '166px';
};
removeKeyTransition = e => {
console.log('inside removeKeyTransition');
if(e.propertyName !== 'transform') return;
e.target.classList.remove(this.playingClass);
};
}