mardi 24 avril 2012
Mon dernier billet sur la programmation avec le canvas HTML5 datait d'un bout de temps déjà. Je me demandais quel genre de petit projet pratique je pourrais développer en l'espace d'une soirée et comme j'ai amorcé un cours de guitare, je me suis dit que ça pourrait être intéressant d'apprendre à dessiner un diagramme d'accord de guitare.
Qu'est-ce que le diagramme doit afficher ?
- le nom de la note
- le sillet de tête (communément appelé nut - la barre horizonale foncée)
- pour faire simple, les 4 premières frettes (pour illustrer des open chords)
- les 6 cordes (de gauche à droite EADGBE)
- la position des doigts (cercles noirs)
- les cordes ouvertes à jouer (cercles blancs)
- les cordes à ne pas jouer (avec un X au bout du sillet)
Code HTML :
<canvas id="myCanvas" width="250" height="300"> Le canvas HTML5 ne fonctionne pas avec ton browser déficient :-( </canvas> <p> <button type="button" id="btnA">A</button> <button type="button" id="btnB">B</button> <button type="button" id="btnC">C</button> <button type="button" id="btnD">D</button> <button type="button" id="btnE">E</button> <button type="button" id="btnF">F</button> <button type="button" id="btnG">G</button> </p> <p> <button type="button" id="btnC7">C7</button> <button type="button" id="btnAsus4">Asus4</button> </p>Définition de quelques formules d'accords sous forme de tableau :
// chaque array contient dans l'ordre la position des doigts de la corde 6 à 1 (mi grave à mi aigu) var a = { "name" : "A", "notes" : [null,0,2,2,2,0] }; var b = { "name" : "B", "notes" : [null,2,4,4,4,2] }; var c = { "name" : "C", "notes" : [null,3,2,0,1,0] }; var d = { "name" : "D", "notes" : [null,null,0,2,3,2] }; var e = { "name" : "E", "notes" : [0,2,2,1,0,0] }; var f = { "name" : "F", "notes" : [1,3,3,2,1,1] }; var g = { "name" : "G", "notes" : [3,2,0,0,0,3] }; var c7 = { "name" : "C7", "notes" : [null,3,2,3,1,0] }; var asus4 = { "name" : "Asus4", "notes" : [null,0,2,2,3,0] };Initialisation JavaScript des boutons :
// inclure jQuery $(document).ready( function(){ $('#btnA').click( function(){ drawChordDiagram(a); } ); $('#btnB').click( function(){ drawChordDiagram(b); } ); $('#btnC').click( function(){ drawChordDiagram(c); } ); $('#btnD').click( function(){ drawChordDiagram(d); } ); $('#btnE').click( function(){ drawChordDiagram(e); } ); $('#btnF').click( function(){ drawChordDiagram(f); } ); $('#btnG').click( function(){ drawChordDiagram(g); } ); $('#btnC7').click( function(){ drawChordDiagram(c7); } ); $('#btnAsus4').click( function(){ drawChordDiagram(asus4); } ); } );La fonction qui dessine le diagramme ainsi que la note :
function drawChordDiagram(chord){ var canvas = $('#myCanvas'); if(canvas && canvas.get(0).getContext){ var context = canvas.get(0).getContext('2d'); // initialiser la surface de dessin context.setTransform(1, 0, 0, 1, 0, 0); context.clearRect(0, 0, canvas.width(), canvas.height()); context.translate(50, 0); var nbFrets = 4; var nutWidth = 120; var stringLength = 140; var nbStrings = 6; var fretWidth = stringLength/nbFrets; // nom de l'accord context.font = "30px arial"; context.fillText(chord.name, 0, 70); // décalage sous le nom de la note context.translate(0, 100); // "nut" context.strokeRect(0,0,nutWidth,5); context.fillRect(0,0,nutWidth,5); // déplacement vers le bas avant de dessiner les frettes context.translate(0, 3); // frettes context.lineWidth = 2; for(var fret=1 ; fret<=nbFrets; fret++){ context.beginPath(); context.moveTo(0, fret*fretWidth); context.lineTo(nutWidth, fret*fretWidth); context.closePath() context.stroke(); } // cordes for(var string=0; string<nbStrings ; string++){ context.beginPath(); context.moveTo(string*(nutWidth/(nbStrings-1)), 0); context.lineTo(string*(nutWidth/(nbStrings-1)), stringLength); context.closePath() context.stroke(); } // taille pour le X context.font = "24px arial"; // l'accord $.each(chord.notes, function(string, fret){ var x = nutWidth/(nbStrings-1) * string var y = (stringLength/nbFrets) * fret - (stringLength/nbFrets)/2; if(fret == null){ // position approximative du X context.fillText('x', string*(nutWidth/(nbStrings-1))-7, -10); } else{ context.beginPath(); context.arc(x, y, 8, 0, Math.PI*2, false); context.closePath() if(fret > 0){ // cercle plein (noir) context.fill(); } else{ // cercle vide (blanc) context.stroke(); } } } ); } }Avec ces quelques lignes de code, nous voilà avec un gabarit de diagramme capable d'illustrer un bon nombre d'accords en position ouverte. Dans ce prototype, plusieurs validations sont manquantes (entre autre lorsqu'on sort des limites du manche) et il reste à implémenter le décalage de la position sur le manche (généralement indiqué par le numéro de la frette à gauche). Je reparlerai sans doute des améliorations apportées lors de mes prochaines expérimentations.
Pas mal du tout ce code, c'est bien pratique.
Merci !