Skip to content

Commit

Permalink
feat(chord chart): set colors for individual fingers and barre chords
Browse files Browse the repository at this point in the history
Allow overriding the global color for each individual finger and barre chords. Both the color of the
finger or barre chord, as well as the text on the finger or barre chord can be overridden.
  • Loading branch information
Voellmy Raphael authored and Voellmy Raphael committed Jun 7, 2020
1 parent fce074a commit 2dcdef4
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 21 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,21 @@ Here's an example of a customized chart:
```javascript
new SVGuitarChord('#some-selector')
.chord({
// array of [string, fret, text]
// array of [string, fret, text | options]
fingers: [
// finger at string 1, fret 2, with text '2'
[1, 2, '2'],
[2, 3, '3'],

// finger at string 2, fret 3, with text '3', colored red
[2, 3, { text: '3', color: '#F00' }],

[3, 3],
[6, 'x']
],

// optional: barres for barre chords
barres: [
{ fromString: 5, toString: 1, fret: 1, text: '1' },
{ fromString: 5, toString: 1, fret: 1, text: '1', color: '#0F0', textColor: '#F00' },
],
})
.configure({
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/roughjs/roughjs-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ export class RoughJsRenderer extends Renderer {
return RoughJsRenderer.boxToElement(txtElem.getBBox(), txtElem.remove.bind(txtElem))
}

static boxToElement(box: DOMRect, remove: () => void): GraphcisElement {
private static boxToElement(box: DOMRect, remove: () => void): GraphcisElement {
return {
width: box.width,
height: box.height,
Expand All @@ -279,7 +279,7 @@ export class RoughJsRenderer extends Renderer {
}
}

static roundedRectData(
private static roundedRectData(
w: number,
h: number,
tlr: number,
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/svgjs/svg-js-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export class SvgJsRenderer extends Renderer {
return SvgJsRenderer.boxToElement(element.bbox(), element.remove.bind(element))
}

static boxToElement(box: Box, remove: () => void): GraphcisElement {
private static boxToElement(box: Box, remove: () => void): GraphcisElement {
return {
width: box.width,
height: box.height,
Expand Down
54 changes: 42 additions & 12 deletions src/svguitar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@ import { Alignment, GraphcisElement, Renderer, RoughJsRenderer, SvgJsRenderer }
export type SilentString = 'x'
export type OpenString = 0
export type Finger = [number, number | OpenString | SilentString, (string | FingerOptions)?]
export type Barre = { fromString: number; toString: number; fret: number; text?: string }
export type Barre = {
fromString: number
toString: number
fret: number
text?: string
color?: string
textColor?: string
}
export type Chord = { fingers: Finger[]; barres: Barre[] }

export interface FingerOptions {
text?: string
color?: string
textColor?: string
}

/**
Expand Down Expand Up @@ -614,26 +622,25 @@ export class SVGuitarChord {
.forEach(([stringIndex, fretIndex, textOrOptions]) => {
const nutCenterX = startX + stringIndex * stringSpacing
const nutCenterY = y + fretIndex * fretSpacing - fretSpacing / 2
const fingerOptions = SVGuitarChord.getFingerOptions(textOrOptions)

this.renderer.circle(
nutCenterX - nutSize / 2,
nutCenterY - nutSize / 2,
nutSize,
0,
nutColor,
nutColor,
fingerOptions.color || nutColor,
fingerOptions.color || nutColor,
)

const text = typeof textOrOptions === 'string' ? textOrOptions : textOrOptions?.text

// draw text on the nut
if (text) {
if (fingerOptions.text) {
this.renderer.text(
text,
fingerOptions.text,
nutCenterX,
nutCenterY,
nutTextSize,
nutTextColor,
fingerOptions.textColor || nutTextColor,
fontFamily,
Alignment.MIDDLE,
true,
Expand All @@ -642,7 +649,7 @@ export class SVGuitarChord {
})

// draw barre chords
this.chordInternal.barres.forEach(({ fret, fromString, toString, text }) => {
this.chordInternal.barres.forEach(({ fret, fromString, toString, text, color, textColor }) => {
const barreCenterY = fretYPositions[fret - 1] - fretSpacing / 2
const fromStringX = stringXPositions[this.toArrayIndex(fromString)]
const distance = Math.abs(toString - fromString) * stringSpacing
Expand All @@ -653,8 +660,8 @@ export class SVGuitarChord {
distance + stringSpacing / 2,
nutSize,
0,
nutColor,
nutColor,
color || nutColor,
color || nutColor,
nutSize * barreChordRadius,
)

Expand All @@ -665,7 +672,7 @@ export class SVGuitarChord {
fromStringX + distance / 2,
barreCenterY,
nutTextSize,
nutTextColor,
textColor || nutTextColor,
fontFamily,
Alignment.MIDDLE,
true,
Expand Down Expand Up @@ -722,4 +729,27 @@ export class SVGuitarChord {
remove(): void {
this.renderer.remove()
}

/**
* Helper method to get an options object from the 3rd array value for a finger, that can either
* be undefined, a string or and options object. This method will return an options object in
* any case, so it's easier to work with this third value.
*
* @param textOrOptions
*/
private static getFingerOptions(
textOrOptions: string | FingerOptions | undefined,
): FingerOptions {
if (!textOrOptions) {
return {}
}

if (typeof textOrOptions === 'string') {
return {
text: textOrOptions,
}
}

return textOrOptions
}
}
89 changes: 87 additions & 2 deletions test/svguitar.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,99 @@ describe('SVGuitarChord', () => {
.configure({
strings: 5,
frets: 6,
title: 'Text on Nuts',
nutTextColor: 'tomato',
title: 'Colored Nuts',
})
.draw()

saveSvg('colored nuts', container.outerHTML)
})

it('Should render text on nuts with a different color', () => {
svguitar
.chord({
fingers: [
[1, 2, { text: 'G', textColor: 'green' }],
[2, 1, { text: 'B', textColor: 'blue' }],
[3, 1, { textColor: 'green' }], // no effect
],
barres: [],
})
.configure({
strings: 5,
frets: 6,
title: 'Colored Text on Nuts',
})
.draw()

saveSvg('colored text on nuts', container.outerHTML)
})

it('Should render barre chords with a different color', () => {
svguitar
.chord({
fingers: [],
barres: [
{
fret: 1,
fromString: 4,
toString: 1,
color: 'blue',
},
{
fret: 3,
fromString: 5,
toString: 2,
color: 'red',
},
],
})
.configure({
strings: 5,
frets: 6,
title: 'Colored Barre Chords',
})
.draw()

saveSvg('colored barre chords', container.outerHTML)
})

it('Should render text on barre chords with a different color', () => {
svguitar
.chord({
fingers: [],
barres: [
{
fret: 1,
fromString: 4,
toString: 1,
text: 'Blue Text',
textColor: 'blue',
},
{
fret: 3,
fromString: 5,
toString: 2,
text: 'Red Text',
textColor: 'red',
},
{
fret: 2,
fromString: 3,
toString: 2,
textColor: 'red',
},
],
})
.configure({
strings: 5,
frets: 6,
title: 'Colored Text on Barre Chords',
})
.draw()

saveSvg('colored text on barre chords', container.outerHTML)
})

it('Should render text on the barre chords', () => {
svguitar
.chord({
Expand Down
2 changes: 1 addition & 1 deletion test/testutils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ export function saveSvg(name: string, svg: string) {
mkdirSync(svgOutputDir)
}

writeFileSync(join(svgOutputDir, `${name}.svg`.replace(' ', '-')), svg)
writeFileSync(join(svgOutputDir, `${name}.svg`.replace(/\s+/g, '-')), svg)
}

0 comments on commit 2dcdef4

Please sign in to comment.