Hace unos años hice un Afinador de Guitarra Online en Flash para la web de Liyonel Guitars.
Flash va a morir, de hecho está agonizando ya… en el año 2016 estuvo presente solo en el 10% de las webs y a partir de 2017 Firefox y Chrome empezarán a bloquear el contenido Flash.
Por eso, pensé en hacer un nuevo afinador en HTML5, con algo de CSS3 y con Javascript puro (para evitar la carga de librerías externas).
La idea original era usar canvas para las animaciones, pero lo dejaremos para la siguiente versión y aquí las haremos con CSS y Javascript.
HTML / HTML5
El HTML se divide en tres partes para las que usaremos elementos de HTML5 :
header
Aqui pondremos el titulo que iluminaremos con CSS3 cuando suene alguna cuerda, para ello añadiremos con Javascript una clase extra al elemento h1
modificando sus estilos CSS.
1 2 3 |
<header> <h1 id="title">Online Guitar Tuner</h1> </header> |
section
En esta sección van las cuerdas que serán elementos button
, también hemos puesto las notas que se iluminarán al tocar cada cuerda. Igualmente con Javascript añadiremos una clase extra a cada elemento para modificar su CSS y aplicar el efecto de iluminado al tocar las cuerdas.
1 2 3 4 5 6 7 8 |
<section id="guitarBody"> <button id="s6" onclick="clickString(this.id)"></button> <!-- un button para cada cuerda --> <div class="notes"> <span id="s6Note">E<span class="notas">MI</span></span> <!-- un span para cada cuerda --> </div> </section> |
footer
En la última parte vamos a poner los controles del afinador; un botón para detener el sonido, otro botón para mantener el sonido, y la púa que hará que suenen las cuerdas onmouseover.
1 2 3 4 5 |
<footer> <button onclick="stopStrings()" id="btnStop">STOP</button> <button onclick="usePick()" id="btnPick">PICK</button> <button onclick="holdSound()" id="btnHold">HOLD</button> </footer> |
CSS / CSS3
Lo único destacable de lo estilos, más allá de imágenes de fondo y posiciones de los elementos, es el iluminado de las notas y el efecto metalizado del texto.
Iluminado de notas
Muy simple, con las propiedades color
y text-shadow
combinadas con la propiedad transition
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.notes span { width: 50px; display: inline-block; color: #171717; text-align: center; font-size: 50px; z-index: 0; text-shadow: -1px -1px 1px #000000, 0px 0px 1px #6f6f6f; } .notes span.lightOn { color: #71abeb; text-shadow: 0px 0px 15px #3779c5, 0px 0px 25px #3779c5, 0px 0px 35px #71abeb, -1px -1px 1px #000000, 0px 0px 1px #6f6f6f; transition: all 0.2s ease; } |
Efecto metalizado del texto
Algo más elaborado, pero muy fácil tambien, la clave está en las propiedades color
, background-color
, background-clip
y text-shadow
.
Para aplicar el efecto de iluminado basta con cambiar las propiedaes background-color
y text-shadow
en el selector :hover
, o añadiendo al elemento una clase con Javascript como en este caso:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
h1 { margin: 0.5vh 0; font-size: 2em; padding: 3vh 0; background-color: #333333; -webkit-background-clip: text; -moz-background-clip: text; background-clip: text; color: transparent; text-shadow: rgba(255,255,255,0.5) 0px 1px 3px; } h1.imgTitle{ text-shadow: 0 0 25px rgba(20, 139, 255, 0.8), 0 0 15px rgba(30, 144, 255, 0.54); background-color: rgba(77, 134, 189, 0.8); } |
Javascript
El Javascript son solo un puñado de variables y algunas funciones:
Variables
Creamos seis variables para almacenar los sonidos de las cuerdas:
1 2 3 4 5 6 |
var s1 = new Audio('../audio/s1.mp3'); var s2 = new Audio('../audio/s2.mp3'); var s3 = new Audio('../audio/s3.mp3'); var s4 = new Audio('../audio/s4.mp3'); var s5 = new Audio('../audio/s5.mp3'); var s6 = new Audio('../audio/s6.mp3'); |
Después podremos acceder a cada sonido para reproducirlo o detenerlo usando el método window
.
Funciones
Los nombres de las funciones son bastante descriptivos, lo que hacen básicamente es reproducir o detener los sonidos y añadir o quitar clases a elementos dependiendo de las cuerdas que toquemos, con ello cambiamos los estilos de los elementos para, por ejemplo, iluminarlos, y para ello usamos los métodos getElementById
y querySelectorAll
.
getElementById
Como vamos a usar bastante el método getElementById
lo podemos acortar en una función, y pasar de esto:
1 |
document.getElementById('id'); |
A esto otro;
1 |
elem(id); |
Con esta simple función:
1 2 3 4 |
function elem(id){ var element = document.getElementById(id); return element; } |
En el resto de funciones usaremos nuestra función elem()
acortando el código resultante.
Que suenen las cuerdas…
Una de las funciones clave es clickString
que se activará al tocar una cuerda, y funciona de la siguiente manera:
En el HTML se le pasa como argumento el valor del atributo id
de la cuerda que se ha tocado:
1 |
<button onclick="clickString(this.id)" class="string" id="s6"></button> |
La función identifica la cuerda y hace el resto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function clickString(thisString) { elem('title').className='imgTitle'; elem(thisString).className = "string"; window[thisString].currentTime = 0; window[thisString].play(); var thisNote = thisString+"Note"; elem(thisString).className = "string playingSound"; elem(thisNote).className = "lightOn"; setTimeout(function(){ if(window[thisString].loop != true){ elem(thisString).className = "string"; elem(thisNote).className = "lightOff"; if(document.querySelectorAll('.playingSound').length==0){ elem('title').className=''; } } }, 4500); } |
Empezando por la linea 2:
- Añadimos la clase
imgTitle
al título para encenderlo. - Nos aseguramos de que el botón solo tiene la clase
string
, para evitar duplicar clases. - Usamos el atributo
id
del botón para seleccionar el sonido de la cuerda elegida mediante el objetowindow
y lo detenemos al inicio del sonido concurrentTime
. - Reproducimos el sonido con el método
play()
. - Creamos la variable
thisNote
para encender las notas. - Le añadimos la clase
playingSound
al botón de la cuerda que está sonando, para encenderla. - Le añadimos la clase
lightOn
a la nota de la cuerda que está sonando, para encenderla. - Llamamos al método
setTimeout
, que se ejecutará 4 segundos y medio después… - - Si el sonido no está en bucle:
- – Quitamos la clase
playingSound
a la cuerda, para apagarla. - – Cambiamos la clase
lightOn
porlightOff
a la nota, para apagarla. - – Si no hay ningún elemento con la clase
playingSound
: - – Quitamos la clase
imgTitle
al título, para apagarlo. - –
- -
- Ejecutamos el contenido del método
setTimeOut
4 segundos y medio después de llamarlo (cuando el sonido ha dejado de sonar).
querySelectorAll
El método querySelectorAll
devuelve, en una lista de nodos, todos los elementos del documento que tienen un determinado selector CSS. Se puede acceder a estos nodos mediante números de índice. De manera que:
1 |
document.querySelectorAll(".notas"); |
Nos devolverá una lista de elementos con la clase notas:
1 |
[span.notas, span.notas, span.notas, span.notas, span.notas, span.notas] |
Y podemos acceder a ellos mediante números de índice:
1 2 3 |
var elemNotas = document.querySelectorAll('.notas'); elemNotas[0].className='primera'; elemNotas[1].className='segunda'; |
Que paren las cuerdas…
La función stopStrings
funciona con este método:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function stopStrings(){ elem('title').className=''; s1.pause(); s2.pause(); s3.pause(); s4.pause(); s5.pause(); s6.pause(); var auxString = document.querySelectorAll('.playingSound'); for (var x in auxString) { if(auxString[x]!==undefined){ auxString[x].className = "string"; } } var auxNote = document.querySelectorAll(".lightOn"); for (x in auxNote) { if(auxNote[x]!==undefined){ auxNote[x].className = "lightOff"; } } } |
Empezando por la linea 2:
- Quitamos la clase
imgTitle
del título para apagarlo. - Detenemos todos los sonidos con el método
pause()
. - Creamos la variable
auxString
que almacena las cuerdas que están sonando. - Con un bucle
for
recorremos la variable: - - Si la variable, con su índice, está definida: (esto es para evitar errores en firefox)
- – Quitamos la variable
playingSound
a cada elemento que la tenga, apagándolo. - …
- …
- Repetimos el proceso para apagar las notas buscando los elementos con la clase
lightOn
…
Demo
Es posible experimentar errores al mostar el código en la demo, es por el ancho del blog que todo a la vez no cabe… ya que el afinador necesita un mínimo de 320 pixels de ancho…
See the Pen Online Guitar Tuner by Josetxu (@josetxu) on CodePen.
…pero puedes probar la demo a tamaño completo:
Compatibilidad en navegadores | |||||
---|---|---|---|---|---|
El número indica la primera versión del navegador que soporta la característica. | |||||
Navegador ► ▼ Característica | |||||
getElementById() | ✔ | ✔ | ✔ | ✔ | ✔ |
querySelectorAll() | 4 | 3.5 | 9 | 10 | 3.2 |
background-clip | 4 | 4 | 9 | 10.2 | 3 |
text-shadow | 4 | 3.5 | 10 | 9.6 | 4 |
transition | 26 4 -webkit- |
16 4 -moz- |
10 | 12.1 10.5 -o- |
6.1 3.1 -webkit- |