UNPKG

chordsong

Version:

ChordSong is a simple text format for the notation of lyrics with guitar chords, and an application that renders them to portable HTML pages.

107 lines (91 loc) 3.42 kB
import { Diagram } from './Diagram' import { readFileSync } from 'fs' import { join } from 'path' type StringType = 'open' | 'muted' | 'played' export interface SvgDiagramOptions { fretWidth?: number fretHeight?: number stringLineColor?: string stringLineWidth?: number fretLineColor?: string fretLineWidth?: number fingerOrBarreWidth?: number fingerOrBarreLineWidth?: number fingerOrBarreLineColor?: string openStringSymbolColor?: string openStringSymbolLineColor?: string } export class SvgDiagram { static svgDefs: string = readFileSync(join(__dirname, 'chord-defs.svg'), { encoding: 'utf8' }) diagram: Diagram constructor (diagram: Diagram, options?: SvgDiagramOptions) { this.diagram = diagram } get openStrings (): number[] { return this.diagram.fretStrings['0'] ?? [] } get mutedStrings (): number[] { return this.diagram.fretStrings['-1'] ?? [] } get playedStrings (): number[] { const playedStrings: number[] = [] this.diagram.stringFrets.forEach((fret, string) => { if (fret > 0) { playedStrings.push(string) } }) return playedStrings } svg (showVariant?: boolean): string { let minFret: number = this.diagram.minFret // make sure there are at most five frets if (this.diagram.maxFret - minFret > 4) minFret = this.diagram.maxFret - 4 // don't capo if a chord is within the first five frets if (this.diagram.maxFret <= 5) minFret = 1 return ` <svg width="64" height="64"> ${this.svgTitle(showVariant)} <g class="chord-chord" transform="translate(8.5,13.5)"> <use href="#chord-diapason" x="0" y="0" /> ${this.svgNut(minFret)} ${this.svgMinFretText(minFret)} ${this.svgFingersOrBarres(minFret)} ${this.svgStrings('muted')} ${this.svgStrings('open')} ${this.svgStrings('played')} </g> </svg>` } private svgTitle (showVariant?: boolean): string { let title = '' if (this.diagram.chordName !== undefined) { title = this.diagram.chordName if (showVariant === true && this.diagram.chordVariant !== undefined) { title = `${title}:${this.diagram.chordVariant}` } } return (title !== '') ? `<text class="chord-name" x="26" y="0" dominant-baseline="hanging" text-anchor="middle">${title}</text>` : '' } private svgNut (minFret: number): string { return (minFret > 1) ? '' : '<use href="#chord-nut" x="0" y="0" />' } private svgMinFretText (minFret: number): string { return (minFret > 1) ? `<text class="chord-min-fret" x="38" y="6.5" dominant-baseline="middle">${String(minFret)}</text>` : '' } private svgFingersOrBarres (minFret: number): string { let ret = '' this.diagram.fingersAndBarrels.forEach(barre => { const barreLength = barre.stringTo - barre.stringFrom + 1 ret += `<use href="#chord-barre${barreLength}" x="${barre.stringFrom * 7}" y="${(barre.fret - minFret) * 8}" />` }) return `<g class="chord-fingers-and-barres" transform="translate(-2,4)">${ret}</g>` } private svgStrings (stringType: StringType): string { let ret = '' const shape = (stringType === 'played') ? 'barre1' : stringType this[`${(stringType)}Strings`].forEach((chordString: number) => { ret += `<use href="#chord-${shape}" x="${chordString * 7}" y="0" />` }) return `<g class="chord-${stringType}-strings" transform="translate(-2,46)">${ret}</g>` } }