Skip to content

Commit

Permalink
feat: use vexflow to render note name (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
gregjopa committed Apr 1, 2023
1 parent 898e3d7 commit 1226a1f
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 32 deletions.
20 changes: 11 additions & 9 deletions src/App.tsx
Expand Up @@ -174,6 +174,10 @@ function App() {
playNote(noteValue, octave);
}

const waitingForGuess =
gameState === GameState.WaitingForGuess ||
gameState === GameState.NotStarted;

return (
<>
<div className="mx-auto h-[900px] max-w-2xl bg-slate-50 px-8 pb-8 text-lg text-slate-600 md:border-x md:border-b md:border-solid md:border-gray-500">
Expand All @@ -186,16 +190,14 @@ function App() {
<NoteSelector
selectedNote={guessedNoteName}
onNoteNameChange={handleGuess}
isDisabled={
gameState !== GameState.WaitingForGuess &&
gameState !== GameState.NotStarted
}
shouldFocus={
gameState === GameState.WaitingForGuess ||
gameState === GameState.NotStarted
}
isDisabled={!waitingForGuess}
shouldFocus={waitingForGuess}
/>
<StaveNote
note={actualNote}
onClick={handleStaveNoteClick}
shouldDisplayNoteName={!waitingForGuess}
/>
<StaveNote note={actualNote} onClick={handleStaveNoteClick} />
<div>Score: {countOfCorrectGuesses}</div>

<ResultsPage
Expand Down
90 changes: 67 additions & 23 deletions src/components/StaveNote.tsx
Expand Up @@ -6,18 +6,29 @@ import type { Note } from "../notes";
type StaveNoteProps = {
note: Note;
onClick: () => void;
shouldDisplayNoteName: boolean;
};

export const StaveNote: React.FC<StaveNoteProps> = ({ note, onClick }) => {
export const StaveNote: React.FC<StaveNoteProps> = ({
note,
onClick,
shouldDisplayNoteName,
}) => {
const vexflowRef = useCallback(
(node: HTMLDivElement) => {
if (node !== null) {
const nodeWidth = node.getBoundingClientRect().width;
const width = nodeWidth > 300 ? nodeWidth : 300;
draw(node, { note, width, height: 250 });
draw({
container: node,
note,
width,
height: 250,
shouldDisplayNoteName,
});
}
},
[note]
[note, shouldDisplayNoteName]
);

return (
Expand All @@ -27,11 +38,23 @@ export const StaveNote: React.FC<StaveNoteProps> = ({ note, onClick }) => {
);
};

function draw(
container: HTMLDivElement,
{ note, width, height }: { note: Note; width: number; height: number }
) {
const { Renderer, Stave, StaveNote, Voice, Accidental, Formatter } = Vex.Flow;
type DrawParams = {
container: HTMLDivElement;
note: Note;
width: number;
height: number;
shouldDisplayNoteName: boolean;
};

function draw({
container,
note,
width,
height,
shouldDisplayNoteName,
}: DrawParams) {
const { Renderer, Stave, StaveNote, TextNote, Voice, Accidental, Formatter } =
Vex.Flow;
container.innerHTML = "";
const renderer = new Renderer(container, Renderer.Backends.SVG);

Expand All @@ -48,23 +71,44 @@ function draw(
stave.addKeySignature(keySignature);
stave.setContext(context).draw();

const notes = [
new StaveNote({
clef,
keys: [`${noteName}/${octave}`],
duration: "4",
auto_stem: true,
align_center: true,
}),
];

const voice = new Voice({ num_beats: 1, beat_value: 4 })
const staveNote = new StaveNote({
clef,
keys: [`${noteName}/${octave}`],
duration: "4",
auto_stem: true,
align_center: true,
});

const textNote = new TextNote({
text: noteName + octave,
duration: "4",
align_center: true,
})
.setContext(context)
.setJustification(TextNote.Justification.CENTER)
.setLine(11)
.setFont(
'-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif',
10,
400
);

const staveNoteVoice = new Voice({ num_beats: 1, beat_value: 4 })
.setStrict(false)
.addTickables([staveNote]);

const textNoteVoice = new Voice({ num_beats: 1, beat_value: 4 })
.setStrict(false)
.addTickables(notes);
.addTickables([textNote]);

Accidental.applyAccidentals([voice], keySignature);
Accidental.applyAccidentals([staveNoteVoice], keySignature);

new Formatter().joinVoices([voice]).format([voice], scaledWidth / 2);
new Formatter()
.joinVoices([staveNoteVoice, textNoteVoice])
.format([staveNoteVoice, textNoteVoice], scaledWidth / 2);

voice.draw(context, stave);
staveNoteVoice.draw(context, stave);
if (shouldDisplayNoteName) {
textNoteVoice.draw(context, stave);
}
}

0 comments on commit 1226a1f

Please sign in to comment.