UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature.

206 lines (183 loc) 6.02 kB
// [VexFlow](https://vexflow.com) - Copyright (c) Mohit Muthanna 2010. // Author Larry Kuhns 2011 import { Font, FontInfo, FontStyle, FontWeight } from './font'; import { Glyph } from './glyph'; import { Stave } from './stave'; import { StaveModifier } from './stavemodifier'; import { Tables } from './tables'; import { Category } from './typeguard'; export class Repetition extends StaveModifier { static get CATEGORY(): string { return Category.Repetition; } static TEXT_FONT: Required<FontInfo> = { family: Font.SERIF, size: Tables.NOTATION_FONT_SCALE / 3, weight: FontWeight.BOLD, style: FontStyle.NORMAL, }; static readonly type = { NONE: 1, // no coda or segno CODA_LEFT: 2, // coda at beginning of stave CODA_RIGHT: 3, // coda at end of stave SEGNO_LEFT: 4, // segno at beginning of stave SEGNO_RIGHT: 5, // segno at end of stave DC: 6, // D.C. at end of stave DC_AL_CODA: 7, // D.C. al coda at end of stave DC_AL_FINE: 8, // D.C. al Fine end of stave DS: 9, // D.S. at end of stave DS_AL_CODA: 10, // D.S. al coda at end of stave DS_AL_FINE: 11, // D.S. al Fine at end of stave FINE: 12, // Fine at end of stave TO_CODA: 13, // To Coda at end of stave }; protected symbol_type: number; protected x_shift: number; protected y_shift: number; constructor(type: number, x: number, y_shift: number) { super(); this.symbol_type = type; this.x = x; this.x_shift = 0; this.y_shift = y_shift; this.resetFont(); } setShiftX(x: number): this { this.x_shift = x; return this; } setShiftY(y: number): this { this.y_shift = y; return this; } draw(stave: Stave, x: number): this { this.setRendered(); switch (this.symbol_type) { case Repetition.type.CODA_RIGHT: this.drawCodaFixed(stave, x + stave.getWidth()); break; case Repetition.type.CODA_LEFT: this.drawSymbolText(stave, x, 'Coda', true); break; case Repetition.type.SEGNO_LEFT: this.drawSignoFixed(stave, x); break; case Repetition.type.SEGNO_RIGHT: this.drawSignoFixed(stave, x + stave.getWidth()); break; case Repetition.type.DC: this.drawSymbolText(stave, x, 'D.C.', false); break; case Repetition.type.DC_AL_CODA: this.drawSymbolText(stave, x, 'D.C. al', true); break; case Repetition.type.DC_AL_FINE: this.drawSymbolText(stave, x, 'D.C. al Fine', false); break; case Repetition.type.DS: this.drawSymbolText(stave, x, 'D.S.', false); break; case Repetition.type.DS_AL_CODA: this.drawSymbolText(stave, x, 'D.S. al', true); break; case Repetition.type.DS_AL_FINE: this.drawSymbolText(stave, x, 'D.S. al Fine', false); break; case Repetition.type.FINE: this.drawSymbolText(stave, x, 'Fine', false); break; case Repetition.type.TO_CODA: this.drawSymbolText(stave, x, 'To', true); break; default: break; } return this; } drawCodaFixed(stave: Stave, x: number): this { const y = stave.getYForTopText(stave.getNumLines()) + this.y_shift; Glyph.renderGlyph( stave.checkContext(), this.x + x + this.x_shift, y + Tables.currentMusicFont().lookupMetric('staveRepetition.coda.offsetY'), 40, 'coda', { category: 'coda' } ); return this; } drawSignoFixed(stave: Stave, x: number): this { const y = stave.getYForTopText(stave.getNumLines()) + this.y_shift; Glyph.renderGlyph( stave.checkContext(), this.x + x + this.x_shift, y + Tables.currentMusicFont().lookupMetric('staveRepetition.segno.offsetY'), 30, 'segno', { category: 'segno' } ); return this; } drawSymbolText(stave: Stave, x: number, text: string, draw_coda: boolean): this { const ctx = stave.checkContext(); ctx.save(); ctx.setFont(this.textFont); let text_x = 0; let symbol_x = 0; const modifierWidth = stave.getNoteStartX() - this.x; switch (this.symbol_type) { // To the left with symbol case Repetition.type.CODA_LEFT: // Offset Coda text to right of stave beginning text_x = this.x + stave.getVerticalBarWidth(); symbol_x = text_x + ctx.measureText(text).width + Tables.currentMusicFont().lookupMetric('staveRepetition.symbolText.offsetX'); break; // To the right without symbol case Repetition.type.DC: case Repetition.type.DC_AL_FINE: case Repetition.type.DS: case Repetition.type.DS_AL_FINE: case Repetition.type.FINE: text_x = this.x + x + this.x_shift + stave.getWidth() - Tables.currentMusicFont().lookupMetric('staveRepetition.symbolText.spacing') - modifierWidth - ctx.measureText(text).width; break; // To the right with symbol default: text_x = this.x + x + this.x_shift + stave.getWidth() - Tables.currentMusicFont().lookupMetric('staveRepetition.symbolText.spacing') - modifierWidth - ctx.measureText(text).width - Tables.currentMusicFont().lookupMetric('staveRepetition.symbolText.offsetX'); symbol_x = text_x + ctx.measureText(text).width + Tables.currentMusicFont().lookupMetric('staveRepetition.symbolText.offsetX'); break; } const y = stave.getYForTopText(stave.getNumLines()) + this.y_shift + Tables.currentMusicFont().lookupMetric('staveRepetition.symbolText.offsetY'); if (draw_coda) { Glyph.renderGlyph(ctx, symbol_x, y, Font.convertSizeToPointValue(this.textFont?.size) * 2, 'coda', { category: 'coda', }); } ctx.fillText(text, text_x, y + 5); ctx.restore(); return this; } }