UNPKG

@stringsync/vexml

Version:

MusicXML to Vexflow

76 lines (75 loc) 2.98 kB
import { Point, Rect } from '../spatial'; import { Label } from './label'; import { TextMeasurer } from './textmeasurer'; export class PartLabelGroup { config; log; document; key; position; partRenders; constructor(config, log, document, key, position, partRenders) { this.config = config; this.log = log; this.document = document; this.key = key; this.position = position; this.partRenders = partRenders; } render() { const partLabelRenders = this.renderPartLabels(); const rect = Rect.merge(partLabelRenders.map((partLabel) => partLabel.rect)); return { type: 'partlabelgroup', rect, partLabelRenders, }; } renderPartLabels() { const partLabelRenders = new Array(); const partCount = this.document.getPartCount(this.key); const positions = this.getPartLabelPositions(); const padding = this.getPartLabelPadding(); const font = this.getPartLabelFont(); for (let partIndex = 0; partIndex < partCount; partIndex++) { const key = { ...this.key, partIndex }; const text = this.document.getPartLabel(key); const position = positions.at(partIndex) ?? this.position; const label = Label.singleLine(this.config, this.log, text, position, padding, font); partLabelRenders.push({ type: 'partLabel', key, rect: label.rect, label }); } return partLabelRenders; } getPartLabelPositions() { const positions = new Array(); const partCount = this.document.getPartCount(this.key); const textMeasurer = new TextMeasurer(this.getPartLabelFont()); for (let partIndex = 0; partIndex < partCount; partIndex++) { const partLabel = this.document.getPartLabel({ ...this.key, partIndex }); const staveRenders = this.partRenders?.at(partIndex)?.staveRenders; const staveCount = staveRenders?.length ?? 0; if (staveCount > 0) { const top = staveRenders.at(0).intrinsicRect.top(); const bottom = staveRenders.at(-1).intrinsicRect.bottom(); const middle = (top + bottom) / 2; const height = textMeasurer.measure(partLabel).approximateHeight; positions.push(new Point(this.position.x, middle + height / 2)); } else { // If there's no part render to use, just use the position of the part label group. We'll correct it later. positions.push(this.position); } } return positions; } getPartLabelPadding() { return { right: this.config.PART_LABEL_PADDING_RIGHT }; } getPartLabelFont() { return { color: 'black', family: this.config.PART_LABEL_FONT_FAMILY, size: this.config.PART_LABEL_FONT_SIZE, }; } }