+ element:
}
]
},
diff --git a/src/Fretboard.jsx b/src/Fretboard.jsx
index 29609cb..d0aef1a 100644
--- a/src/Fretboard.jsx
+++ b/src/Fretboard.jsx
@@ -85,24 +85,28 @@ const Text = ({ x, y, children, ...rest }) => (
* @param {Number} props.outerRadius outer radius of circle
* @param {(String) => boolean} props.onNoteEnter function gets triggered if note is hovered
* @param {(String) => boolean} props.onNoteOut function gets triggered if note is not hovered anymore
- * @param {(String) => String} props.colorFunc color function which determines which color should be shown for specific note
+ * @param {(String) => string} props.onClick function gets triggered if note (arc) is clicked. parameter is the note itself
+ * @param {(String) => boolean} porps.noteFunc function which determines if note is highlighted or not. get called for every note with note as parameter
+ * @param {(String) => String} props.colorFunc color function which determines which color should be shown for specific note. gets called for every note with note as parameter
* @param {Array} props.scale scale to display (eg. `Scale.Chromatic`)
*/
-const Circle12Notes = ({ x, y, innerRadius, outerRadius, highlightNote, onNoteEnter = null, onNoteOut = null, colorFunc, scale }) => {
+const Circle12Notes = ({ x, y, innerRadius, outerRadius, noteFunc, onNoteEnter=null, onNoteOut=null, onClick=null, colorFunc, scale }) => {
const angle = 360. / 12
const halfAngle = angle / 2 - 1 // used for shifting arcs so they are centered. minus one just because it looks a little nicer
const padAngle = 2
return (
<>
- { /* Circle of fifths circle */}
+ { /* Circle arcs */}
{scale.map((notes, i) => (
onNoteEnter(notes[0])} onMouseOut={() => onNoteOut()}
- fill={Note.eq(highlightNote, notes[0]) ? colorFunc(notes[0]) : "white"} />
+ onMouseEnter={() => onNoteEnter && onNoteEnter(notes[0])}
+ onMouseOut={() => onNoteOut && onNoteOut()}
+ onClick={() => onClick && onClick(notes[0])}
+ fill={noteFunc(notes[0]) ? colorFunc(notes[0]) : "white"} />
))}
- { /* Circle of fifths texts */}
+ { /* Circle texts */}
{scale.map((notes, i) => {
const startAngle = i * angle - halfAngle, endAngle = (i + 1) * angle - halfAngle
// radiusOffset is used if two notes are displayed (eg. F# and Gb)
diff --git a/src/musictheory.js b/src/musictheory.js
index 96e6921..50eceec 100644
--- a/src/musictheory.js
+++ b/src/musictheory.js
@@ -123,10 +123,15 @@ class Scale {
this.key = key
this.scale = scale
let constructed = [key] // scale starts with key note
- let ints = undefined // intervals
- if (scale == "major") { ints = [2, 2, 1, 2, 2, 2, 1] }
- else if (scale == "minor" || scale == "natural minor") { ints = [2, 1, 2, 2, 1, 2, 2] }
- else { throw `Scale ${scale} not yet implemented` }
+
+ if (!Scale.supportedScales.includes(scale)) {
+ throw `Scale ${scale} not yet implemented`
+ }
+ const ints = {
+ "major": [2, 2, 1, 2, 2, 2, 1],
+ "minor": [2, 1, 2, 2, 1, 2, 2],
+ "natural minor": [2, 1, 2, 2, 1, 2, 2],
+ }[scale]
for (const interval of ints) {
// we get next note and then sharp or flat the note. this ensures that every note only appears once in the scale
const lastNote = constructed[constructed.length - 1] // get last constructed note
@@ -141,6 +146,17 @@ class Scale {
}
this.notes = constructed
}
+ /** Returns if given note is in scale or not
+ * @param {string} note Note to compare to scale
+ * @returns {boolean} is in scale
+ * @example new Scale("C", "major").has("D") == true
+ */
+ has(note) {
+ return this.notes.some(scaleNote => Note.eq(scaleNote, note))
+ }
+
+ static supportedScales = ["major", "minor", "natural minor"]
+
/**
* Notes of circle of fifths with enharmonic equivalents
*/