UNPKG

@stringsync/vexml

Version:

MusicXML to Vexflow

64 lines (63 loc) 2.42 kB
import * as util from '../util'; import { Point, Rect } from '../spatial'; import { TextMeasurer } from './textmeasurer'; import { Label } from './label'; export class GapOverlay { config; log; label; fragmentRender; style; ctx = null; constructor(config, log, label, fragmentRender, style) { this.config = config; this.log = log; this.label = label; this.fragmentRender = fragmentRender; this.style = style; util.assert(fragmentRender.rectSrc !== 'none'); // This means we can trust the rects. } setContext(ctx) { this.ctx = ctx; return this; } draw() { const ctx = this.ctx; util.assertNotNull(ctx); const topRect = this.fragmentRender.partRenders.at(0)?.staveRenders.at(0)?.playableRect; util.assertDefined(topRect); const bottomRect = this.fragmentRender.partRenders.at(-1)?.staveRenders.at(-1)?.playableRect; util.assertDefined(bottomRect); const rect = Rect.merge([topRect, bottomRect]); ctx.save(); const fontSize = this.style?.fontSize ?? this.config.DEFAULT_GAP_OVERLAY_FONT_SIZE; const fontFamily = this.style?.fontFamily ?? this.config.DEFAULT_GAP_OVERLAY_FONT_FAMILY; const fontColor = this.style?.fontColor ?? this.config.DEFAULT_GAP_OVERLAY_FONT_COLOR; this.drawRect(rect); // Draw the label in the center of the overlay. if (this.label) { const textMeasurer = new TextMeasurer({ size: fontSize, family: fontFamily, }); const measurement = textMeasurer.measure(this.label); const x = rect.center().x - measurement.width / 2; const y = rect.center().y + measurement.approximateHeight / 2; const position = new Point(x, y); Label.singleLine(this.config, this.log, this.label, position, {}, { size: fontSize, family: fontFamily, color: fontColor }) .setContext(ctx) .draw(); } ctx.restore(); return this; } drawRect(rect) { const ctx = this.ctx; util.assertNotNull(ctx); ctx.save(); const fill = this.style?.fill ?? this.config.DEFAULT_GAP_OVERLAY_FILL_COLOR; ctx.setFillStyle(fill); ctx.fillRect(rect.x, rect.y, rect.w, rect.h); ctx.restore(); } }