UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature.

148 lines (147 loc) 5.62 kB
import { Element } from './element.js'; import { RuntimeError } from './util.js'; class StaveTie extends Element { static get CATEGORY() { return "StaveTie"; } constructor(notes, text) { super(); this.setNotes(notes); this.text = text; this.render_options = { cp1: 8, cp2: 12, text_shift_x: 0, first_x_shift: 0, last_x_shift: 0, y_shift: 7, tie_spacing: 0, }; this.resetFont(); } setDirection(direction) { this.direction = direction; return this; } setNotes(notes) { if (!notes.first_note && !notes.last_note) { throw new RuntimeError('BadArguments', 'Tie needs to have either first_note or last_note set.'); } if (!notes.first_indices) { notes.first_indices = [0]; } if (!notes.last_indices) { notes.last_indices = [0]; } if (notes.first_indices.length !== notes.last_indices.length) { throw new RuntimeError('BadArguments', 'Tied notes must have same number of indices.'); } this.notes = notes; return this; } isPartial() { return !this.notes.first_note || !this.notes.last_note; } renderTie(params) { if (params.first_ys.length === 0 || params.last_ys.length === 0) { throw new RuntimeError('BadArguments', 'No Y-values to render'); } const ctx = this.checkContext(); let cp1 = this.render_options.cp1; let cp2 = this.render_options.cp2; if (Math.abs(params.last_x_px - params.first_x_px) < 10) { cp1 = 2; cp2 = 8; } const first_x_shift = this.render_options.first_x_shift; const last_x_shift = this.render_options.last_x_shift; const y_shift = this.render_options.y_shift * params.direction; const first_indices = this.notes.first_indices; const last_indices = this.notes.last_indices; this.applyStyle(); ctx.openGroup('stavetie', this.getAttribute('id')); for (let i = 0; i < first_indices.length; ++i) { const cp_x = (params.last_x_px + last_x_shift + (params.first_x_px + first_x_shift)) / 2; const first_y_px = params.first_ys[first_indices[i]] + y_shift; const last_y_px = params.last_ys[last_indices[i]] + y_shift; if (isNaN(first_y_px) || isNaN(last_y_px)) { throw new RuntimeError('BadArguments', 'Bad indices for tie rendering.'); } const top_cp_y = (first_y_px + last_y_px) / 2 + cp1 * params.direction; const bottom_cp_y = (first_y_px + last_y_px) / 2 + cp2 * params.direction; ctx.beginPath(); ctx.moveTo(params.first_x_px + first_x_shift, first_y_px); ctx.quadraticCurveTo(cp_x, top_cp_y, params.last_x_px + last_x_shift, last_y_px); ctx.quadraticCurveTo(cp_x, bottom_cp_y, params.first_x_px + first_x_shift, first_y_px); ctx.closePath(); ctx.fill(); } ctx.closeGroup(); this.restoreStyle(); } renderText(first_x_px, last_x_px) { var _a, _b, _c; if (!this.text) return; const ctx = this.checkContext(); let center_x = (first_x_px + last_x_px) / 2; center_x -= ctx.measureText(this.text).width / 2; const stave = (_b = (_a = this.notes.first_note) === null || _a === void 0 ? void 0 : _a.checkStave()) !== null && _b !== void 0 ? _b : (_c = this.notes.last_note) === null || _c === void 0 ? void 0 : _c.checkStave(); if (stave) { ctx.save(); ctx.setFont(this.textFont); ctx.fillText(this.text, center_x + this.render_options.text_shift_x, stave.getYForTopText() - 1); ctx.restore(); } } getNotes() { return this.notes; } draw() { this.checkContext(); this.setRendered(); const first_note = this.notes.first_note; const last_note = this.notes.last_note; let first_x_px = 0; let last_x_px = 0; let first_ys = [0]; let last_ys = [0]; let stem_direction = 0; if (first_note) { first_x_px = first_note.getTieRightX() + this.render_options.tie_spacing; stem_direction = first_note.getStemDirection(); first_ys = first_note.getYs(); } else if (last_note) { const stave = last_note.checkStave(); first_x_px = stave.getTieStartX(); first_ys = last_note.getYs(); this.notes.first_indices = this.notes.last_indices; } if (last_note) { last_x_px = last_note.getTieLeftX() + this.render_options.tie_spacing; stem_direction = last_note.getStemDirection(); last_ys = last_note.getYs(); } else if (first_note) { const stave = first_note.checkStave(); last_x_px = stave.getTieEndX(); last_ys = first_note.getYs(); this.notes.last_indices = this.notes.first_indices; } if (this.direction) { stem_direction = this.direction; } this.renderTie({ first_x_px, last_x_px, first_ys, last_ys, direction: stem_direction, }); this.renderText(first_x_px, last_x_px); return true; } } StaveTie.TEXT_FONT = Object.assign({}, Element.TEXT_FONT); export { StaveTie };