vexflow
Version:
A JavaScript library for rendering music notation and guitar tablature.
120 lines (119 loc) • 3.99 kB
JavaScript
import { Glyph } from './glyph.js';
import { StaveModifier, StaveModifierPosition } from './stavemodifier.js';
import { Tables } from './tables.js';
import { TimeSignatureGlyph } from './timesigglyph.js';
import { defined, RuntimeError } from './util.js';
const assertIsValidTimeSig = (timeSpec) => {
const numbers = timeSpec.split('/');
if (numbers.length !== 2 && numbers[0] !== '+' && numbers[0] !== '-') {
throw new RuntimeError('BadTimeSignature', `Invalid time spec: ${timeSpec}. Must be in the form "<numerator>/<denominator>"`);
}
numbers.forEach((number) => {
if (/^[0-9+\-()]+$/.test(number) == false) {
throw new RuntimeError('BadTimeSignature', `Invalid time spec: ${timeSpec}. Must contain valid signatures.`);
}
});
};
export class TimeSignature extends StaveModifier {
static get CATEGORY() {
return "TimeSignature";
}
static get glyphs() {
return {
C: {
code: 'timeSigCommon',
line: 2,
},
'C|': {
code: 'timeSigCutCommon',
line: 2,
},
};
}
constructor(timeSpec = '4/4', customPadding = 15, validate_args = true) {
super();
this.timeSpec = '4/4';
this.line = 0;
this.is_numeric = true;
this.validate_args = validate_args;
const padding = customPadding;
const musicFont = Tables.currentMusicFont();
this.point = musicFont.lookupMetric('digits.point') || Tables.NOTATION_FONT_SCALE;
const fontLineShift = musicFont.lookupMetric('digits.shiftLine', 0);
this.topLine = 2 + fontLineShift;
this.bottomLine = 4 + fontLineShift;
this.setPosition(StaveModifierPosition.BEGIN);
this.setTimeSig(timeSpec);
this.setPadding(padding);
}
parseTimeSpec(timeSpec) {
var _a, _b;
if (timeSpec === 'C' || timeSpec === 'C|') {
const { line, code } = TimeSignature.glyphs[timeSpec];
return {
line,
num: false,
glyph: new Glyph(code, Tables.NOTATION_FONT_SCALE),
};
}
if (this.validate_args) {
assertIsValidTimeSig(timeSpec);
}
const parts = timeSpec.split('/');
return {
line: 0,
num: true,
glyph: this.makeTimeSignatureGlyph((_a = parts[0]) !== null && _a !== void 0 ? _a : '', (_b = parts[1]) !== null && _b !== void 0 ? _b : ''),
};
}
makeTimeSignatureGlyph(topDigits, botDigits) {
return new TimeSignatureGlyph(this, topDigits, botDigits, 'timeSig0', this.point);
}
getInfo() {
const { line, is_numeric, glyph } = this;
return { line, num: is_numeric, glyph };
}
setTimeSig(timeSpec) {
this.timeSpec = timeSpec;
const info = this.parseTimeSpec(timeSpec);
this.setGlyph(info.glyph);
this.is_numeric = info.num;
this.line = info.line;
return this;
}
getTimeSpec() {
return this.timeSpec;
}
getLine() {
return this.line;
}
setLine(line) {
this.line = line;
}
getGlyph() {
return this.glyph;
}
setGlyph(glyph) {
this.glyph = glyph;
this.setWidth(defined(this.glyph.getMetrics().width));
}
getIsNumeric() {
return this.is_numeric;
}
setIsNumeric(isNumeric) {
this.is_numeric = isNumeric;
}
draw() {
const stave = this.checkStave();
const ctx = stave.checkContext();
this.setRendered();
this.applyStyle(ctx);
ctx.openGroup('timesignature', this.getAttribute('id'));
this.glyph.setStave(stave);
this.glyph.setContext(ctx);
this.placeGlyphOnLine(this.glyph, stave, this.line);
this.glyph.renderToStave(this.x);
ctx.closeGroup();
this.restoreStyle(ctx);
}
}