Skip to content

Commit

Permalink
Merge pull request #1002 from ronyeh/modifier-index
Browse files Browse the repository at this point in the history
Introduce Modifier.checkAttachedNote() to check that this.note and this.index are valid.
  • Loading branch information
0xfe authored Jun 7, 2021
2 parents 268cd9a + bc08be9 commit 2c77ad2
Show file tree
Hide file tree
Showing 26 changed files with 168 additions and 218 deletions.
21 changes: 8 additions & 13 deletions src/accidental.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { Flow } from './tables';
import { Music } from './music';
import { Modifier } from './modifier';
import { Glyph } from './glyph';
import { GraceNoteGroup } from './gracenotegroup';
import { GraceNote } from './gracenote';

// To enable logging for this class. Set `Vex.Flow.Accidental.DEBUG` to `true`.
function L(...args) {
Expand Down Expand Up @@ -48,7 +50,8 @@ export class Accidental extends Modifier {
const acc = accidentals[i];
const note = acc.getNote();
const stave = note.getStave();
const props = note.getKeyProps()[acc.getIndex()];
const index = acc.checkIndex();
const props = note.getKeyProps()[index];
if (note !== prevNote) {
// Iterate through all notes to get the displaced pixels
for (let n = 0; n < note.keys.length; ++n) {
Expand Down Expand Up @@ -398,7 +401,7 @@ export class Accidental extends Modifier {

// process grace notes
note.getModifiers().forEach((modifier) => {
if (modifier.getCategory() === 'gracenotegroups') {
if (modifier.getCategory() === GraceNoteGroup.CATEGORY) {
modifier.getGraceNotes().forEach(processNote);
}
});
Expand All @@ -417,9 +420,6 @@ export class Accidental extends Modifier {

L('New accidental: ', type);

this.note = null;
// The `index` points to a specific note in a chord.
this.index = null;
this.type = type;
this.position = Modifier.Position.LEFT;

Expand Down Expand Up @@ -485,7 +485,7 @@ export class Accidental extends Modifier {
this.note = note;

// Accidentals attached to grace notes are rendered smaller.
if (this.note.getCategory() === 'gracenotes') {
if (note.getCategory() === GraceNote.CATEGORY) {
this.render_options.font_scale = 25;
this.reset();
}
Expand All @@ -505,7 +505,6 @@ export class Accidental extends Modifier {
context,
type,
position,
note,
index,
cautionary,
x_shift,
Expand All @@ -517,10 +516,8 @@ export class Accidental extends Modifier {
} = this;

this.checkContext();

if (!(note && index != null)) {
throw new RuntimeError('NoAttachedNote', "Can't draw accidental without a note and index.");
}
const note = this.checkAttachedNote();
this.setRendered();

// Figure out the start `x` and `y` coordinates for note and index.
const start = note.getModifierStartXY(position, index);
Expand All @@ -541,7 +538,5 @@ export class Accidental extends Modifier {
accX -= parenLeftPadding;
parenLeft.render(context, accX, accY);
}

this.setRendered();
}
}
25 changes: 11 additions & 14 deletions src/annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,10 @@ export class Annotation extends Modifier {
// Render text beside the note.
draw(): void {
const ctx = this.checkContext();

if (!this.note) {
throw new RuntimeError('NoNoteForAnnotation', "Can't draw text annotation without an attached note.");
}

const note = this.checkAttachedNote();
this.setRendered();
const start = this.note.getModifierStartXY(Modifier.Position.ABOVE, this.index);

const start = note.getModifierStartXY(Modifier.Position.ABOVE, this.index);

// We're changing context parameters. Save current state.
ctx.save();
Expand All @@ -183,18 +180,18 @@ export class Annotation extends Modifier {
} else if (this.justification === Annotation.Justify.CENTER) {
x = start.x - text_width / 2;
} /* CENTER_STEM */ else {
x = this.note.getStemX() - text_width / 2;
x = (note as StemmableNote).getStemX() - text_width / 2;
}

let stem_ext: Record<string, number> = {};
let spacing = 0;
const has_stem = this.note.hasStem();
const stave = this.note.checkStave();
const has_stem = note.hasStem();
const stave = note.checkStave();

// The position of the text varies based on whether or not the note
// has a stem.
if (has_stem) {
stem_ext = this.note.checkStem().getExtents();
stem_ext = (note as StemmableNote).checkStem().getExtents();
spacing = stave.getSpacingBetweenLines();
}

Expand All @@ -203,20 +200,20 @@ export class Annotation extends Modifier {
// is bottom-right.
y = stave.getYForBottomText(this.text_line + Flow.TEXT_HEIGHT_OFFSET_HACK);
if (has_stem) {
const stem_base = this.note.getStemDirection() === 1 ? stem_ext.baseY : stem_ext.topY;
const stem_base = note.getStemDirection() === 1 ? stem_ext.baseY : stem_ext.topY;
y = Math.max(y, stem_base + spacing * (this.text_line + 2));
}
} else if (this.vert_justification === Annotation.VerticalJustify.CENTER) {
const yt = this.note.getYForTopText(this.text_line) - 1;
const yt = note.getYForTopText(this.text_line) - 1;
const yb = stave.getYForBottomText(this.text_line);
y = yt + (yb - yt) / 2 + text_height / 2;
} else if (this.vert_justification === Annotation.VerticalJustify.TOP) {
y = Math.min(stave.getYForTopText(this.text_line), this.note.getYs()[0] - 10);
y = Math.min(stave.getYForTopText(this.text_line), note.getYs()[0] - 10);
if (has_stem) {
y = Math.min(y, stem_ext.topY - 5 - spacing * this.text_line);
}
} /* CENTER_STEM */ else {
const extents = this.note.getStemExtents();
const extents = note.getStemExtents();
y = extents.topY + (extents.baseY - extents.topY) / 2 + text_height / 2;
}

Expand Down
22 changes: 10 additions & 12 deletions src/articulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ModifierContextState } from './modifiercontext';
import { check } from './common';
import { Builder } from './easyscore';
import { TabNote } from './tabnote';
import { GraceNote } from './gracenote';

export interface ArticulationStruct {
code: string;
Expand Down Expand Up @@ -74,7 +75,7 @@ function snapLineToStaff(canSitBetweenLines: boolean, line: number, position: nu

function isStaveNote(note: Note): boolean {
const noteCategory = note.getCategory();
return noteCategory === 'stavenotes' || noteCategory === 'gracenotes';
return noteCategory === StaveNote.CATEGORY || noteCategory === GraceNote.CATEGORY;
}

function getTopY(note: Note, textLine: number): number {
Expand All @@ -91,7 +92,7 @@ function getTopY(note: Note, textLine: number): number {
} else {
return Math.min(...note.getYs());
}
} else if (note.getCategory() === 'tabnotes') {
} else if (note.getCategory() === TabNote.CATEGORY) {
if (note.hasStem()) {
if (stemDirection === Stem.UP) {
return stemTipY;
Expand Down Expand Up @@ -120,7 +121,7 @@ function getBottomY(note: Note, textLine: number): number {
} else {
return Math.max(...note.getYs());
}
} else if (note.getCategory() === 'tabnotes') {
} else if (note.getCategory() === TabNote.CATEGORY) {
if (note.hasStem()) {
if (stemDirection === Stem.UP) {
return note.checkStave().getYForBottomText(textLine);
Expand Down Expand Up @@ -279,20 +280,17 @@ export class Articulation extends Modifier {

// Render articulation in position next to note.
draw(): void {
const { note, index, position, glyph, text_line: textLine } = this;
const canSitBetweenLines = this.articulation?.between_lines ?? false;

const ctx = this.checkContext();

if (!note || index == null) {
throw new RuntimeError('NoAttachedNote', "Can't draw Articulation without a note and index.");
}

const note = this.checkAttachedNote();
this.setRendered();

const index = this.checkIndex();
const { position, glyph, text_line: textLine } = this;
const canSitBetweenLines = this.articulation?.between_lines ?? false;

const stave = note.checkStave();
const staffSpace = stave.getSpacingBetweenLines();
const isTab = note.getCategory() === 'tabnotes';
const isTab = note.getCategory() === TabNote.CATEGORY;

// Articulations are centered over/under the note head.
const { x } = note.getModifierStartXY(position, index);
Expand Down
8 changes: 5 additions & 3 deletions src/beam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { Note } from './note';
import { StemmableNote } from './stemmablenote';
import { Voice } from './voice';
import { RenderContext } from './types/common';
import { TabNote } from './tabnote';
import { StaveNote } from './stavenote';

function calculateStemDirection(notes: StemmableNote[]) {
let lineSum = 0;
Expand Down Expand Up @@ -464,9 +466,9 @@ export class Beam extends Element {

let stem_direction = this.stem_direction;
// Figure out optimal stem direction based on given notes
if (auto_stem && notes[0].getCategory() === 'stavenotes') {
if (auto_stem && notes[0].getCategory() === StaveNote.CATEGORY) {
stem_direction = calculateStemDirection(notes);
} else if (auto_stem && notes[0].getCategory() === 'tabnotes') {
} else if (auto_stem && notes[0].getCategory() === TabNote.CATEGORY) {
// Auto Stem TabNotes
const stem_weight = notes.reduce((memo, note) => memo + note.getStemDirection(), 0);

Expand Down Expand Up @@ -898,7 +900,7 @@ export class Beam extends Element {
if (this.postFormatted) return;

// Calculate a smart slope if we're not forcing the beams to be flat.
if (this.notes[0].getCategory() === 'tabnotes' || this.render_options.flat_beams) {
if (this.notes[0].getCategory() === TabNote.CATEGORY || this.render_options.flat_beams) {
this.calculateFlatSlope();
} else {
this.calculateSlope();
Expand Down
9 changes: 3 additions & 6 deletions src/bend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,18 +182,15 @@ export class Bend extends Modifier {

draw(): void {
const ctx = this.checkContext();
if (!(this.note && this.index != null)) {
throw new RuntimeError('NoNoteForBend', "Can't draw bend without a note or index.");
}

const note = this.checkAttachedNote();
this.setRendered();

const start = this.note.getModifierStartXY(Modifier.Position.RIGHT, this.index);
const start = note.getModifierStartXY(Modifier.Position.RIGHT, this.index);
start.x += 3;
start.y += 0.5;
const x_shift = this.x_shift;

const stave = this.note.checkStave();
const stave = note.checkStave();
const bend_height = stave.getYForTopText(this.text_line) + 3;
const annotation_y = stave.getYForTopText(this.text_line) - 1;
// eslint-disable-next-line
Expand Down
57 changes: 26 additions & 31 deletions src/chordsymbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//
// See `tests/chordsymbol_tests.js` for usage examples.

import { RuntimeError, log } from './util';
import { log } from './util';
import { DefaultFontStack } from './font';
import { Flow } from './tables';
import { Glyph } from './glyph';
Expand Down Expand Up @@ -350,8 +350,6 @@ export class ChordSymbol extends Modifier {
constructor() {
super();
this.setAttribute('type', 'ChordSymbol');
this.note = null;
this.index = null;
this.symbolBlocks = [];
this.horizontal = ChordSymbol.horizontalJustify.LEFT;
this.vertical = ChordSymbol.verticalJustify.TOP;
Expand Down Expand Up @@ -666,32 +664,29 @@ export class ChordSymbol extends Modifier {

// Render text and glyphs above/below the note
draw() {
this.checkContext();
const ctx = this.checkContext();
const note = this.checkAttachedNote();
this.setRendered();

if (!this.note) {
throw new RuntimeError('NoNoteForAnnotation', "Can't draw text annotation without an attached note.");
}

// We're changing context parameters. Save current state.
this.context.save();
ctx.save();
const classString = Object.keys(this.getAttribute('classes')).join(' ');
this.context.openGroup(classString, this.getAttribute('id'));
ctx.openGroup(classString, this.getAttribute('id'));

const start = this.note.getModifierStartXY(Modifier.Position.ABOVE, this.index);
this.context.setFont(this.font.family, this.font.size, this.font.weight);
const start = note.getModifierStartXY(Modifier.Position.ABOVE, this.index);
ctx.setFont(this.font.family, this.font.size, this.font.weight);

let y;

let stem_ext;
let spacing;
const has_stem = this.note.hasStem();
const stave = this.note.getStave();
const has_stem = note.hasStem();
const stave = note.getStave();

// The position of the text varies based on whether or not the note
// has a stem.
if (has_stem) {
stem_ext = this.note.getStem().getExtents();
stem_ext = note.getStem().getExtents();
spacing = stave.getSpacingBetweenLines();
}

Expand All @@ -700,12 +695,12 @@ export class ChordSymbol extends Modifier {
// is bottom-right.
y = stave.getYForBottomText(this.text_line + Flow.TEXT_HEIGHT_OFFSET_HACK);
if (has_stem) {
const stem_base = this.note.getStemDirection() === 1 ? stem_ext.baseY : stem_ext.topY;
const stem_base = note.getStemDirection() === 1 ? stem_ext.baseY : stem_ext.topY;
y = Math.max(y, stem_base + spacing * (this.text_line + 2));
}
} else {
// (this.vertical === ChordSymbol.verticalJustify.TOP)
y = Math.min(stave.getYForTopText(this.text_line), this.note.getYs()[0] - 10);
y = Math.min(stave.getYForTopText(this.text_line), note.getYs()[0] - 10);
if (has_stem) {
y = Math.min(y, stem_ext.topY - 5 - spacing * this.text_line);
}
Expand All @@ -719,7 +714,7 @@ export class ChordSymbol extends Modifier {
} else if (this.horizontal === ChordSymbol.horizontalJustify.CENTER) {
x = start.x - this.getWidth() / 2;
} /* CENTER_STEM */ else {
x = this.note.getStemX() - this.getWidth() / 2;
x = note.getStemX() - this.getWidth() / 2;
}
L('Rendering ChordSymbol: ', this.text, x, y);

Expand All @@ -739,38 +734,38 @@ export class ChordSymbol extends Modifier {

if (symbol.symbolType === ChordSymbol.symbolTypes.TEXT) {
if (sp || sub) {
this.context.save();
this.context.setFont(this.font.family, this.font.size * ChordSymbol.superSubRatio, this.font.weight);
ctx.save();
ctx.setFont(this.font.family, this.font.size * ChordSymbol.superSubRatio, this.font.weight);
}
// We estimate the text width, fill it in with the empirical value so the
// formatting is even.
/* const textDim = this.context.measureText(symbol.text);
/* const textDim = ctx.measureText(symbol.text);
symbol.width = textDim.width; */
L('Rendering Text: ', symbol.text, x + symbol.xShift, curY + symbol.yShift);

this.context.fillText(symbol.text, x + symbol.xShift, curY + symbol.yShift);
ctx.fillText(symbol.text, x + symbol.xShift, curY + symbol.yShift);
if (sp || sub) {
this.context.restore();
ctx.restore();
}
} else if (symbol.symbolType === ChordSymbol.symbolTypes.GLYPH) {
curY += symbol.yShift;
L('Rendering Glyph: ', symbol.glyph.code, x + symbol.xShift, curY);
symbol.glyph.render(this.context, x + symbol.xShift, curY);
symbol.glyph.render(ctx, x + symbol.xShift, curY);
} else if (symbol.symbolType === ChordSymbol.symbolTypes.LINE) {
L('Rendering Line : ', symbol.width, x, curY);
this.context.beginPath();
this.context.setLineWidth(1); // ?
this.context.moveTo(x, y);
this.context.lineTo(x + symbol.width, curY);
this.context.stroke();
ctx.beginPath();
ctx.setLineWidth(1); // ?
ctx.moveTo(x, y);
ctx.lineTo(x + symbol.width, curY);
ctx.stroke();
}

x += symbol.width;
if (symbol.vAlign) {
x += symbol.xShift;
}
});
this.context.closeGroup();
this.context.restore();
ctx.closeGroup();
ctx.restore();
}
}
Loading

0 comments on commit 2c77ad2

Please sign in to comment.