@stringsync/vexml
Version:
MusicXML to Vexflow
76 lines (75 loc) • 2.98 kB
JavaScript
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,
};
}
}