UNPKG

@stringsync/vexml

Version:

MusicXML to Vexflow

167 lines (166 loc) 6.73 kB
import * as util from '../util'; import { System } from './system'; import { Label } from './label'; import { Rect } from '../spatial'; import { Pen } from './pen'; import { SystemRenderMover } from './systemrendermover'; import { Curve } from './curve'; import { Wedge } from './wedge'; import { Pedal } from './pedal'; import { OctaveShift } from './octaveshift'; import { RenderRegistry } from './renderregistry'; import { Vibrato } from './vibrato'; /** * Score is the top-level rendering object that is directly responsible for arranging systems. */ export class Score { config; log; document; width; constructor(config, log, document, width) { this.config = config; this.log = log; this.document = document; this.width = width; } render() { const pen = new Pen(); pen.moveBy({ dy: this.config.SCORE_PADDING_TOP }); const titleRender = this.renderTitle(pen); const systemRenders = this.renderSystems(pen); const registry = RenderRegistry.create(systemRenders); const curveRenders = this.renderCurves(registry); const wedgeRenders = this.renderWedges(registry); const pedalRenders = this.renderPedals(registry); const octaveShiftRenders = this.renderOctaveShifts(registry); const vibratoRenders = this.renderVibratos(registry); pen.moveBy({ dy: this.config.SCORE_PADDING_BOTTOM }); const width = this.width ?? util.max(systemRenders.map((system) => system.rect.w)); const rect = new Rect(0, 0, width, pen.position().y); return { type: 'score', rect, titleRender, systemRenders, curveRenders, wedgeRenders, pedalRenders, octaveShiftRenders, vibratoRenders, }; } renderTitle(pen) { const title = this.document.getTitle(); if (!title) { return null; } const position = pen.position(); const padding = this.getTitlePadding(); const font = this.getTitleFont(); let label; if (this.width) { label = Label.centerAligned(this.config, this.log, this.width, title, position, padding, font); } else { label = Label.singleLine(this.config, this.log, title, position, padding, font); } const rect = label.rect; pen.moveBy({ dy: rect.h }); return { type: 'title', rect, label, }; } renderCurves(registry) { const curves = this.document.getCurves(); const curveRenders = new Array(); for (let curveIndex = 0; curveIndex < curves.length; curveIndex++) { const key = { curveIndex }; const noteRenderCount = registry.get(curves[curveIndex].id)?.length ?? 0; if (noteRenderCount >= 1) { const curveRender = new Curve(this.config, this.log, this.document, key, registry).render(); curveRenders.push(curveRender); } } return curveRenders; } renderWedges(registry) { const wedges = this.document.getWedges(); const wedgeRenders = new Array(); for (let wedgeIndex = 0; wedgeIndex < wedges.length; wedgeIndex++) { const key = { wedgeIndex }; const noteRenderCount = registry.get(wedges[wedgeIndex].id)?.length ?? 0; if (noteRenderCount >= 1) { const wedgeRender = new Wedge(this.config, this.log, this.document, key, registry).render(); wedgeRenders.push(wedgeRender); } } return wedgeRenders; } renderPedals(registry) { const pedals = this.document.getPedals(); const pedalRenders = new Array(); for (let pedalIndex = 0; pedalIndex < pedals.length; pedalIndex++) { const key = { pedalIndex }; const noteRenderCount = registry.get(pedals[pedalIndex].id)?.length ?? 0; if (noteRenderCount >= 1) { const pedalRender = new Pedal(this.config, this.log, this.document, key, registry).render(); pedalRenders.push(pedalRender); } } return pedalRenders; } renderOctaveShifts(registry) { const octaveShifts = this.document.getOctaveShifts(); const octaveShiftRenders = new Array(); for (let octaveShiftIndex = 0; octaveShiftIndex < octaveShifts.length; octaveShiftIndex++) { const key = { octaveShiftIndex }; const noteRenderCount = registry.get(octaveShifts[octaveShiftIndex].id)?.length ?? 0; if (noteRenderCount >= 1) { const octaveShiftRender = new OctaveShift(this.config, this.log, this.document, key, registry).render(); octaveShiftRenders.push(octaveShiftRender); } } return octaveShiftRenders; } renderVibratos(registry) { const vibratos = this.document.getVibratos(); const vibratoRenders = new Array(); for (let vibratoIndex = 0; vibratoIndex < vibratos.length; vibratoIndex++) { const key = { vibratoIndex }; const noteRenderCount = registry.get(vibratos[vibratoIndex].id)?.length ?? 0; if (noteRenderCount >= 1) { const vibratoRender = new Vibrato(this.config, this.log, this.document, key, registry).render(); vibratoRenders.push(vibratoRender); } } return vibratoRenders; } getTitlePadding() { return { bottom: this.config.TITLE_PADDING_BOTTOM }; } getTitleFont() { return { color: 'black', family: this.config.TITLE_FONT_FAMILY, size: this.config.TITLE_FONT_SIZE, lineHeight: this.config.TITLE_FONT_LINE_HEIGHT_PX, }; } renderSystems(pen) { const systemRenders = new Array(); const systemCount = this.document.getSystemCount(); for (let systemIndex = 0; systemIndex < systemCount; systemIndex++) { const key = { systemIndex }; const systemRender = new System(this.config, this.log, this.document, key, this.width, pen.position()).render(); systemRenders.push(systemRender); const excessHeight = util.max(systemRender.measureRenders.flatMap((m) => m.fragmentRenders).flatMap((e) => e.excessHeight)); new SystemRenderMover().moveBy(systemRender, excessHeight); pen.moveTo(systemRender.rect.bottomLeft()); pen.moveBy({ dy: this.config.SYSTEM_MARGIN_BOTTOM }); } return systemRenders; } }