UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature.

468 lines (467 loc) 17.4 kB
import { Accidental } from './accidental.js'; import { Annotation, AnnotationHorizontalJustify, AnnotationVerticalJustify } from './annotation.js'; import { Articulation } from './articulation.js'; import { BarNote } from './barnote.js'; import { Beam } from './beam.js'; import { ChordSymbol } from './chordsymbol.js'; import { ClefNote } from './clefnote.js'; import { Curve } from './curve.js'; import { EasyScore } from './easyscore.js'; import { Element } from './element.js'; import { Formatter } from './formatter.js'; import { FretHandFinger } from './frethandfinger.js'; import { GhostNote } from './ghostnote.js'; import { GlyphNote } from './glyphnote.js'; import { GraceNote } from './gracenote.js'; import { GraceNoteGroup } from './gracenotegroup.js'; import { KeySigNote } from './keysignote.js'; import { ModifierContext } from './modifiercontext.js'; import { MultiMeasureRest } from './multimeasurerest.js'; import { NoteSubGroup } from './notesubgroup.js'; import { Ornament } from './ornament.js'; import { PedalMarking } from './pedalmarking.js'; import { Renderer } from './renderer.js'; import { RepeatNote } from './repeatnote.js'; import { Stave } from './stave.js'; import { StaveConnector } from './staveconnector.js'; import { StaveLine } from './staveline.js'; import { StaveNote } from './stavenote.js'; import { StaveTie } from './stavetie.js'; import { StringNumber } from './stringnumber.js'; import { System } from './system.js'; import { TabNote } from './tabnote.js'; import { TabStave } from './tabstave.js'; import { TextBracket } from './textbracket.js'; import { TextDynamics } from './textdynamics.js'; import { TextNote } from './textnote.js'; import { TickContext } from './tickcontext.js'; import { TimeSigNote } from './timesignote.js'; import { Tuplet } from './tuplet.js'; import { defined, log, RuntimeError } from './util.js'; import { VibratoBracket } from './vibratobracket.js'; import { Voice } from './voice.js'; import { isHTMLCanvas } from './web.js'; function L(...args) { if (Factory.DEBUG) log('Vex.Flow.Factory', args); } class Factory { static newFromElementId(elementId, width = 500, height = 200) { return new Factory({ renderer: { elementId, width, height } }); } constructor(options = {}) { L('New factory: ', options); this.options = { stave: { space: 10, }, renderer: { elementId: '', width: 500, height: 200, background: '#FFF', }, font: Factory.TEXT_FONT, }; this.setOptions(options); } reset() { this.renderQ = []; this.systems = []; this.staves = []; this.voices = []; this.stave = undefined; } setOptions(options) { this.options = Object.assign(Object.assign({}, this.options), options); this.initRenderer(); this.reset(); } initRenderer() { const { elementId, width, height, background } = this.options.renderer; if (elementId == null) { return; } if (elementId == '') { L(this); throw new RuntimeError('renderer.elementId not set in FactoryOptions'); } let backend = this.options.renderer.backend; if (backend === undefined) { const elem = document.getElementById(elementId); if (isHTMLCanvas(elem)) { backend = Renderer.Backends.CANVAS; } else { backend = Renderer.Backends.SVG; } } this.context = Renderer.buildContext(elementId, backend, width, height, background); } getContext() { return this.context; } setContext(context) { this.context = context; return this; } getStave() { return this.stave; } getVoices() { return this.voices; } Stave(params) { const staveSpace = this.options.stave.space; const p = Object.assign({ x: 0, y: 0, width: this.options.renderer.width - staveSpace * 1.0, options: { spacing_between_lines_px: staveSpace * 1.0 } }, params); const stave = new Stave(p.x, p.y, p.width, p.options); this.staves.push(stave); stave.setContext(this.context); this.stave = stave; return stave; } TabStave(params) { const staveSpace = this.options.stave.space; const p = Object.assign({ x: 0, y: 0, width: this.options.renderer.width - staveSpace * 1.0, options: { spacing_between_lines_px: staveSpace * 1.3 } }, params); const stave = new TabStave(p.x, p.y, p.width, p.options); this.staves.push(stave); stave.setContext(this.context); this.stave = stave; return stave; } StaveNote(noteStruct) { const note = new StaveNote(noteStruct); if (this.stave) note.setStave(this.stave); note.setContext(this.context); this.renderQ.push(note); return note; } GlyphNote(glyph, noteStruct, options) { const note = new GlyphNote(glyph, noteStruct, options); if (this.stave) note.setStave(this.stave); note.setContext(this.context); this.renderQ.push(note); return note; } RepeatNote(type, noteStruct, options) { const note = new RepeatNote(type, noteStruct, options); if (this.stave) note.setStave(this.stave); note.setContext(this.context); this.renderQ.push(note); return note; } GhostNote(noteStruct) { const ghostNote = new GhostNote(noteStruct); if (this.stave) ghostNote.setStave(this.stave); ghostNote.setContext(this.context); this.renderQ.push(ghostNote); return ghostNote; } TextNote(noteStruct) { const textNote = new TextNote(noteStruct); if (this.stave) textNote.setStave(this.stave); textNote.setContext(this.context); this.renderQ.push(textNote); return textNote; } BarNote(params = {}) { const barNote = new BarNote(params.type); if (this.stave) barNote.setStave(this.stave); barNote.setContext(this.context); this.renderQ.push(barNote); return barNote; } ClefNote(params) { const p = Object.assign({ type: 'treble', options: { size: 'default', annotation: undefined, } }, params); const clefNote = new ClefNote(p.type, p.options.size, p.options.annotation); if (this.stave) clefNote.setStave(this.stave); clefNote.setContext(this.context); this.renderQ.push(clefNote); return clefNote; } TimeSigNote(params) { const p = Object.assign({ time: '4/4' }, params); const timeSigNote = new TimeSigNote(p.time); if (this.stave) timeSigNote.setStave(this.stave); timeSigNote.setContext(this.context); this.renderQ.push(timeSigNote); return timeSigNote; } KeySigNote(params) { const keySigNote = new KeySigNote(params.key, params.cancelKey, params.alterKey); if (this.stave) keySigNote.setStave(this.stave); keySigNote.setContext(this.context); this.renderQ.push(keySigNote); return keySigNote; } TabNote(noteStruct) { const note = new TabNote(noteStruct); if (this.stave) note.setStave(this.stave); note.setContext(this.context); this.renderQ.push(note); return note; } GraceNote(noteStruct) { const note = new GraceNote(noteStruct); if (this.stave) note.setStave(this.stave); note.setContext(this.context); return note; } GraceNoteGroup(params) { const group = new GraceNoteGroup(params.notes, params.slur); group.setContext(this.context); return group; } Accidental(params) { const accid = new Accidental(params.type); accid.setContext(this.context); return accid; } Annotation(params) { const p = Object.assign({ text: 'p', hJustify: AnnotationHorizontalJustify.CENTER, vJustify: AnnotationVerticalJustify.BOTTOM }, params); const annotation = new Annotation(p.text); annotation.setJustification(p.hJustify); annotation.setVerticalJustification(p.vJustify); annotation.setFont(p.font); annotation.setContext(this.context); return annotation; } ChordSymbol(params) { const p = Object.assign({ vJustify: 'top', hJustify: 'center', kerning: true, reportWidth: true }, params); const chordSymbol = new ChordSymbol(); chordSymbol.setHorizontal(p.hJustify); chordSymbol.setVertical(p.vJustify); chordSymbol.setEnableKerning(p.kerning); chordSymbol.setReportWidth(p.reportWidth); if (typeof p.fontFamily === 'string' && typeof p.fontSize === 'number') { if (typeof p.fontWeight === 'string') chordSymbol.setFont(p.fontFamily, p.fontSize, p.fontWeight); else chordSymbol.setFont(p.fontFamily, p.fontSize, ''); } else if (typeof p.fontSize === 'number') { chordSymbol.setFontSize(p.fontSize); } chordSymbol.setContext(this.context); return chordSymbol; } Articulation(params) { var _a; const articulation = new Articulation((_a = params === null || params === void 0 ? void 0 : params.type) !== null && _a !== void 0 ? _a : 'a.'); if ((params === null || params === void 0 ? void 0 : params.position) != undefined) articulation.setPosition(params.position); if ((params === null || params === void 0 ? void 0 : params.betweenLines) != undefined) articulation.setBetweenLines(params.betweenLines); articulation.setContext(this.context); return articulation; } Ornament(type, params) { const options = Object.assign({ type, position: 0, accidental: '' }, params); const ornament = new Ornament(type); ornament.setPosition(options.position); if (options.upperAccidental) { ornament.setUpperAccidental(options.upperAccidental); } if (options.lowerAccidental) { ornament.setLowerAccidental(options.lowerAccidental); } if (typeof options.delayed !== 'undefined') { ornament.setDelayed(options.delayed); } ornament.setContext(this.context); return ornament; } TextDynamics(params) { const p = Object.assign({ text: 'p', duration: 'q', dots: 0, line: 0 }, params); const text = new TextDynamics({ text: p.text, line: p.line, duration: p.duration, dots: p.dots, }); if (this.stave) text.setStave(this.stave); text.setContext(this.context); this.renderQ.push(text); return text; } Fingering(params) { const p = Object.assign({ number: '0', position: 'left' }, params); const fingering = new FretHandFinger(p.number); fingering.setPosition(p.position); fingering.setContext(this.context); return fingering; } StringNumber(params, drawCircle = true) { const stringNumber = new StringNumber(params.number); stringNumber.setPosition(params.position); stringNumber.setContext(this.context); stringNumber.setDrawCircle(drawCircle); return stringNumber; } TickContext() { return new TickContext(); } ModifierContext() { return new ModifierContext(); } MultiMeasureRest(params) { const numMeasures = defined(params.number_of_measures, 'NoNumberOfMeasures'); const multiMeasureRest = new MultiMeasureRest(numMeasures, params); multiMeasureRest.setContext(this.context); this.renderQ.push(multiMeasureRest); return multiMeasureRest; } Voice(params) { const p = Object.assign({ time: '4/4' }, params); const voice = new Voice(p.time); this.voices.push(voice); return voice; } StaveConnector(params) { const connector = new StaveConnector(params.top_stave, params.bottom_stave); connector.setType(params.type).setContext(this.context); this.renderQ.push(connector); return connector; } Formatter(options) { return new Formatter(options); } Tuplet(params) { const p = Object.assign({ notes: [], options: {} }, params); const tuplet = new Tuplet(p.notes, p.options).setContext(this.context); this.renderQ.push(tuplet); return tuplet; } Beam(params) { var _a, _b, _c, _d, _e; const beam = new Beam(params.notes, (_a = params.options) === null || _a === void 0 ? void 0 : _a.autoStem).setContext(this.context); beam.breakSecondaryAt((_c = (_b = params.options) === null || _b === void 0 ? void 0 : _b.secondaryBeamBreaks) !== null && _c !== void 0 ? _c : []); if ((_d = params.options) === null || _d === void 0 ? void 0 : _d.partialBeamDirections) { Object.entries((_e = params.options) === null || _e === void 0 ? void 0 : _e.partialBeamDirections).forEach(([noteIndex, direction]) => { beam.setPartialBeamSideAt(Number(noteIndex), direction); }); } this.renderQ.push(beam); return beam; } Curve(params) { const curve = new Curve(params.from, params.to, params.options).setContext(this.context); this.renderQ.push(curve); return curve; } StaveTie(params) { var _a; const tie = new StaveTie({ first_note: params.from, last_note: params.to, first_indices: params.first_indices, last_indices: params.last_indices, }, params.text); if ((_a = params.options) === null || _a === void 0 ? void 0 : _a.direction) tie.setDirection(params.options.direction); tie.setContext(this.context); this.renderQ.push(tie); return tie; } StaveLine(params) { var _a, _b; const line = new StaveLine({ first_note: params.from, last_note: params.to, first_indices: params.first_indices, last_indices: params.last_indices, }); if ((_a = params.options) === null || _a === void 0 ? void 0 : _a.text) line.setText(params.options.text); if ((_b = params.options) === null || _b === void 0 ? void 0 : _b.font) line.setFont(params.options.font); line.setContext(this.context); this.renderQ.push(line); return line; } VibratoBracket(params) { const vibratoBracket = new VibratoBracket({ start: params.from, stop: params.to, }); if (params.options.line) vibratoBracket.setLine(params.options.line); if (params.options.harsh) vibratoBracket.setHarsh(params.options.harsh); vibratoBracket.setContext(this.context); this.renderQ.push(vibratoBracket); return vibratoBracket; } TextBracket(params) { const textBracket = new TextBracket({ start: params.from, stop: params.to, text: params.text, superscript: params.options.superscript, position: params.options.position, }); if (params.options.line) textBracket.setLine(params.options.line); if (params.options.font) textBracket.setFont(params.options.font); textBracket.setContext(this.context); this.renderQ.push(textBracket); return textBracket; } System(params = {}) { params.factory = this; const system = new System(params).setContext(this.context); this.systems.push(system); return system; } EasyScore(options = {}) { options.factory = this; return new EasyScore(options); } PedalMarking(params) { const p = Object.assign({ notes: [], options: { style: 'mixed', } }, params); const pedal = new PedalMarking(p.notes); pedal.setType(PedalMarking.typeString[p.options.style]); pedal.setContext(this.context); this.renderQ.push(pedal); return pedal; } NoteSubGroup(params) { const p = Object.assign({ notes: [] }, params); const group = new NoteSubGroup(p.notes); group.setContext(this.context); return group; } draw() { const ctx = this.context; this.systems.forEach((s) => s.setContext(ctx).format()); this.staves.forEach((s) => s.setContext(ctx).draw()); this.voices.forEach((v) => v.setContext(ctx).draw()); this.renderQ.forEach((e) => { if (!e.isRendered()) e.setContext(ctx).draw(); }); this.systems.forEach((s) => s.setContext(ctx).draw()); this.reset(); } } Factory.DEBUG = false; Factory.TEXT_FONT = Object.assign({}, Element.TEXT_FONT); export { Factory };