vexflow
Version:
A JavaScript library for rendering music notation and guitar tablature.
215 lines (214 loc) • 6.29 kB
JavaScript
import { Element } from './element.js';
import { Fraction } from './fraction.js';
import { Tables } from './tables.js';
import { defined, RuntimeError } from './util.js';
export class Tickable extends Element {
static get CATEGORY() {
return "Tickable";
}
constructor() {
super();
this._preFormatted = false;
this._postFormatted = false;
this.ticks = new Fraction(0, 1);
this.intrinsicTicks = 0;
this.tickMultiplier = new Fraction(1, 1);
this.width = 0;
this.x_shift = 0;
this.modifiers = [];
this.tupletStack = [];
this.align_center = false;
this.center_x_shift = 0;
this.ignore_ticks = false;
this.formatterMetrics = {
freedom: { left: 0, right: 0 },
duration: '',
iterations: 0,
space: {
used: 0,
mean: 0,
deviation: 0,
},
};
}
reset() {
return this;
}
getTicks() {
return this.ticks;
}
shouldIgnoreTicks() {
return this.ignore_ticks;
}
setIgnoreTicks(flag) {
this.ignore_ticks = flag;
return this;
}
setWidth(width) {
this.width = width;
}
getWidth() {
if (!this._preFormatted) {
throw new RuntimeError('UnformattedNote', "Can't call GetWidth on an unformatted note.");
}
return this.width + (this.modifierContext ? this.modifierContext.getWidth() : 0);
}
setXShift(x) {
this.x_shift = x;
return this;
}
getXShift() {
return this.x_shift;
}
getX() {
const tickContext = this.checkTickContext(`Can't getX() without a TickContext.`);
return tickContext.getX() + this.x_shift;
}
getFormatterMetrics() {
return this.formatterMetrics;
}
getCenterXShift() {
if (this.isCenterAligned()) {
return this.center_x_shift;
}
return 0;
}
setCenterXShift(centerXShift) {
this.center_x_shift = centerXShift;
return this;
}
isCenterAligned() {
return this.align_center;
}
setCenterAlignment(align_center) {
this.align_center = align_center;
return this;
}
getVoice() {
return defined(this.voice, 'NoVoice', 'Tickable has no voice.');
}
setVoice(voice) {
this.voice = voice;
}
getTuplet() {
return this.tuplet;
}
getTupletStack() {
return this.tupletStack;
}
resetTuplet(tuplet) {
let noteCount;
let notesOccupied;
if (tuplet) {
const i = this.tupletStack.indexOf(tuplet);
if (i !== -1) {
this.tupletStack.splice(i, 1);
noteCount = tuplet.getNoteCount();
notesOccupied = tuplet.getNotesOccupied();
this.applyTickMultiplier(noteCount, notesOccupied);
}
return this;
}
while (this.tupletStack.length) {
tuplet = this.tupletStack.pop();
noteCount = tuplet.getNoteCount();
notesOccupied = tuplet.getNotesOccupied();
this.applyTickMultiplier(noteCount, notesOccupied);
}
return this;
}
setTuplet(tuplet) {
if (tuplet) {
this.tupletStack.push(tuplet);
const noteCount = tuplet.getNoteCount();
const notesOccupied = tuplet.getNotesOccupied();
this.applyTickMultiplier(notesOccupied, noteCount);
}
this.tuplet = tuplet;
return this;
}
addToModifierContext(mc) {
this.modifierContext = mc;
for (let i = 0; i < this.modifiers.length; ++i) {
this.modifierContext.addMember(this.modifiers[i]);
}
this.modifierContext.addMember(this);
this._preFormatted = false;
return this;
}
addModifier(modifier, index = 0) {
this.modifiers.push(modifier);
this._preFormatted = false;
return this;
}
getModifiers() {
return this.modifiers;
}
setTickContext(tc) {
this.tickContext = tc;
this._preFormatted = false;
}
checkTickContext(message = 'Tickable has no tick context.') {
return defined(this.tickContext, 'NoTickContext', message);
}
preFormat() {
if (this._preFormatted)
return;
this.width = 0;
if (this.modifierContext) {
this.modifierContext.preFormat();
this.width += this.modifierContext.getWidth();
}
}
set preFormatted(value) {
this._preFormatted = value;
}
get preFormatted() {
return this._preFormatted;
}
postFormat() {
if (this._postFormatted)
return this;
this._postFormatted = true;
return this;
}
set postFormatted(value) {
this._postFormatted = value;
}
get postFormatted() {
return this._postFormatted;
}
getIntrinsicTicks() {
return this.intrinsicTicks;
}
setIntrinsicTicks(intrinsicTicks) {
this.intrinsicTicks = intrinsicTicks;
this.ticks = this.tickMultiplier.clone().multiply(this.intrinsicTicks);
}
getTickMultiplier() {
return this.tickMultiplier;
}
applyTickMultiplier(numerator, denominator) {
this.tickMultiplier.multiply(numerator, denominator);
this.ticks = this.tickMultiplier.clone().multiply(this.intrinsicTicks);
}
setDuration(duration) {
const ticks = duration.numerator * (Tables.RESOLUTION / duration.denominator);
this.ticks = this.tickMultiplier.clone().multiply(ticks);
this.intrinsicTicks = this.ticks.value();
}
getAbsoluteX() {
const tickContext = this.checkTickContext(`Can't getAbsoluteX() without a TickContext.`);
return tickContext.getX();
}
setModifierContext(mc) {
this.modifierContext = mc;
return this;
}
getModifierContext() {
return this.modifierContext;
}
checkModifierContext() {
return defined(this.modifierContext, 'NoModifierContext', 'No modifier context attached to this tickable.');
}
}