Skip to content

Commit

Permalink
Introduce visual diff from master.
Browse files Browse the repository at this point in the history
Use Font.* constants to make default fonts more consistent and robust.
Fixed: Annotation line height calculation.
  • Loading branch information
ronyeh committed Nov 16, 2021
1 parent 5de2abf commit 6a9d9bf
Show file tree
Hide file tree
Showing 37 changed files with 372 additions and 265 deletions.
12 changes: 12 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,18 @@ export default Vex;`;
]
);

// `grunt watchDevelop`
// This is the fastest way to build vexflow-debug-with-tests.js.
// Open tests/flow.html to see the test output.
grunt.registerTask(
'watchDevelop',
`Watch src/ & tests/ for changes and generate a development build.`, //
[
'clean:build', //
'webpack:watchDebugPlusTests',
]
);

// `grunt test`
grunt.registerTask(
'test',
Expand Down
60 changes: 32 additions & 28 deletions src/annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@
// MIT License

import { Element } from './element';
import { FontInfo } from './font';
import { Modifier } from './modifier';
import { ModifierContextState } from './modifiercontext';
import { StemmableNote } from './stemmablenote';
import { FontInfo, log, ModifierContextState, StemmableNote, TextFormatter } from './index';
import { Modifier, ModifierPosition } from './modifier';
import { Tables } from './tables';
import { TextFormatter } from './textformatter';
import { log } from './util';

// eslint-disable-next-line
function L(...args: any[]) {
Expand Down Expand Up @@ -73,30 +69,38 @@ export class Annotation extends Modifier {

let width = 0;
for (let i = 0; i < annotations.length; ++i) {
let textWidth = 0;
const annotation = annotations[i];
const textFormatter = TextFormatter.create(annotation.textFont);

// Calculate if the vertical extent will exceed a single line and adjust accordingly.
const numLines = Math.floor(textFormatter.maxHeight / Tables.STAVE_LINE_DISTANCE) + 1;
// Get the text width from the font metrics.
textWidth = textFormatter.getWidthForTextInPx(annotation.text);
const textWidth = textFormatter.getWidthForTextInPx(annotation.text);
width = Math.max(width, textWidth);
if (annotation.getPosition() === Modifier.Position.ABOVE) {

if (annotation.getPosition() === ModifierPosition.ABOVE) {
annotation.setTextLine(state.top_text_line);
state.top_text_line += numLines;
// Like in CSS, lineHeight is multiplied by the font size.
const lineHeight = 1.4;
// This is expressed in fractional stave spaces.
const verticalSpaceNeeded = (lineHeight * textFormatter.maxHeight) / Tables.STAVE_LINE_DISTANCE;
// Each subsequent annotation is shifted downward by 1.4 lines.
state.top_text_line += verticalSpaceNeeded;
} else {
annotation.setTextLine(state.text_line);
state.text_line += numLines;
// Like in CSS, lineHeight is multiplied by the font size.
const lineHeight = 1.1;
// This is expressed in fractional stave spaces.
const verticalSpaceNeeded = (lineHeight * textFormatter.maxHeight) / Tables.STAVE_LINE_DISTANCE;
// Each subsequent annotation is shifted upward by 1.1 lines.
state.text_line += verticalSpaceNeeded;
}
}
state.left_shift += width / 2;
state.right_shift += width / 2;
return true;
}

protected justification: AnnotationHorizontalJustify;
protected vert_justification: AnnotationVerticalJustify;
protected horizontalJustification: AnnotationHorizontalJustify;
protected verticalJustification: AnnotationVerticalJustify;
protected text: string;

/**
Expand All @@ -108,8 +112,8 @@ export class Annotation extends Modifier {
super();

this.text = text;
this.justification = AnnotationHorizontalJustify.CENTER;
this.vert_justification = Annotation.VerticalJustify.TOP;
this.horizontalJustification = AnnotationHorizontalJustify.CENTER;
this.verticalJustification = AnnotationVerticalJustify.TOP;
this.resetFont();

// The default width is calculated from the text.
Expand All @@ -118,26 +122,26 @@ export class Annotation extends Modifier {

/**
* Set vertical position of text (above or below stave).
* @param just value in `Annotation.VerticalJustify`.
* @param just value in `AnnotationVerticalJustify`.
*/
setVerticalJustification(just: string | AnnotationVerticalJustify): this {
this.vert_justification = typeof just === 'string' ? Annotation.VerticalJustifyString[just] : just;
this.verticalJustification = typeof just === 'string' ? Annotation.VerticalJustifyString[just] : just;
return this;
}

/**
* Get horizontal justification.
*/
getJustification(): AnnotationHorizontalJustify {
return this.justification;
return this.horizontalJustification;
}

/**
* Set horizontal justification.
* @param justification value in `Annotation.Justify`.
*/
setJustification(just: string | AnnotationHorizontalJustify): this {
this.justification = typeof just === 'string' ? Annotation.HorizontalJustifyString[just] : just;
this.horizontalJustification = typeof just === 'string' ? Annotation.HorizontalJustifyString[just] : just;
return this;
}

Expand All @@ -147,7 +151,7 @@ export class Annotation extends Modifier {
const note = this.checkAttachedNote();
this.setRendered();

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

// We're changing context parameters. Save current state.
ctx.save();
Expand All @@ -165,11 +169,11 @@ export class Annotation extends Modifier {
let x;
let y;

if (this.justification === Annotation.HorizontalJustify.LEFT) {
if (this.horizontalJustification === AnnotationHorizontalJustify.LEFT) {
x = start.x;
} else if (this.justification === Annotation.HorizontalJustify.RIGHT) {
} else if (this.horizontalJustification === AnnotationHorizontalJustify.RIGHT) {
x = start.x - text_width;
} else if (this.justification === Annotation.HorizontalJustify.CENTER) {
} else if (this.horizontalJustification === AnnotationHorizontalJustify.CENTER) {
x = start.x - text_width / 2;
} /* CENTER_STEM */ else {
x = (note as StemmableNote).getStemX() - text_width / 2;
Expand All @@ -187,19 +191,19 @@ export class Annotation extends Modifier {
spacing = stave.getSpacingBetweenLines();
}

if (this.vert_justification === Annotation.VerticalJustify.BOTTOM) {
if (this.verticalJustification === AnnotationVerticalJustify.BOTTOM) {
// HACK: We need to compensate for the text's height since its origin
// is bottom-right.
y = stave.getYForBottomText(this.text_line + Tables.TEXT_HEIGHT_OFFSET_HACK);
if (has_stem) {
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) {
} else if (this.verticalJustification === AnnotationVerticalJustify.CENTER) {
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) {
} else if (this.verticalJustification === AnnotationVerticalJustify.TOP) {
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 Down
4 changes: 2 additions & 2 deletions src/canvascontext.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// [VexFlow](https://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
// MIT License

import { globalObject, isHTMLCanvas } from '.';
import { Font, FontInfo } from './font';
import { GroupAttributes, RenderContext, TextMeasure } from './rendercontext';
import { warn } from './util';
import { isHTMLCanvas } from './typeguard';
import { globalObject, warn } from './util';

/**
* A rendering context for the Canvas backend. This class serves as a proxy for the
Expand Down
25 changes: 11 additions & 14 deletions src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// @author Mohit Cheppudira
// MIT License

import { AnnotationHorizontalJustify, AnnotationVerticalJustify } from '.';
import { Accidental } from './accidental';
import { Annotation } from './annotation';
import { Articulation } from './articulation';
Expand All @@ -12,7 +13,7 @@ import { ClefNote } from './clefnote';
import { Curve, CurveOptions } from './curve';
import { EasyScore, EasyScoreOptions } from './easyscore';
import { Element } from './element';
import { FontInfo, FontStyle, FontWeight } from './font';
import { FontInfo } from './font';
import { Formatter, FormatterOptions } from './formatter';
import { FretHandFinger } from './frethandfinger';
import { GhostNote } from './ghostnote';
Expand Down Expand Up @@ -335,27 +336,23 @@ export class Factory {
return accid;
}

Annotation(params?: { text?: string; vJustify?: string; hJustify?: string; font?: FontInfo }): Annotation {
Annotation(params?: {
text?: string;
hJustify?: string | AnnotationHorizontalJustify;
vJustify?: string | AnnotationVerticalJustify;
font?: FontInfo;
}): Annotation {
const p = {
text: 'p',
vJustify: 'below',
hJustify: 'center',
options: {},
hJustify: AnnotationHorizontalJustify.CENTER,
vJustify: AnnotationVerticalJustify.BOTTOM,
...params,
};

// RONYEH: Factory.Annotation has a different default font from new Annotation()...
const font = {
family: 'Times' /* RONYEH: Font.SERIF */,
size: 14,
weight: FontWeight.BOLD,
style: FontStyle.ITALIC,
...p.font,
};
const annotation = new Annotation(p.text);
annotation.setJustification(p.hJustify);
annotation.setVerticalJustification(p.vJustify);
annotation.setFont(font);
annotation.setFont(p.font);
annotation.setContext(this.context);
return annotation;
}
Expand Down
11 changes: 5 additions & 6 deletions src/fonts/textfonts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ export function loadTextFonts() {
const fontData = RobotoSlabFont;
const { fontFamily, resolution, glyphs } = fontData;
Font.load(fontFamily, fontData);
// H isn't actually the tallest or the widest.
// Interestingly, the lowercase b is the tallest.
const maxSizeGlyph = 'H'; // Two lines of lyrics touch each other because we don't allow enough vertical space.
// const maxSizeGlyph = 'b'; // RONYEH: introduces a visual diff, but the spacing is better.
// Previously we used 'H', but it isn't actually the tallest or the widest.
// Interestingly, the lowercase 'b' is the tallest glyph.
const maxSizeGlyph = 'b';
TextFormatter.registerInfo({
family: fontFamily,
resolution,
Expand All @@ -36,9 +35,9 @@ export function loadTextFonts() {
const fontData = PetalumaScriptFont;
const { fontFamily, resolution, glyphs } = fontData;
Font.load(fontFamily, fontData);
// M is wider, but H is taller. :-) We continue to use H for consistency / legacy reasons.
// M is wider, but H is taller. :-)
// Lowercase b is also taller in this font.
const maxSizeGlyph = 'H';
const maxSizeGlyph = 'b';
TextFormatter.registerInfo({
family: fontFamily,
resolution,
Expand Down
4 changes: 2 additions & 2 deletions src/frethandfinger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Class to draws string numbers into the notation.

import { Builder } from './easyscore';
import { FontInfo, FontStyle, FontWeight } from './font';
import { Font, FontInfo, FontStyle, FontWeight } from './font';
import { Modifier } from './modifier';
import { ModifierContextState } from './modifiercontext';
import { StaveNote } from './stavenote';
Expand All @@ -16,7 +16,7 @@ export class FretHandFinger extends Modifier {
}

static TEXT_FONT: Required<FontInfo> = {
family: 'sans-serif' /* RONYEH: Font.SANS_SERIF */,
family: Font.SANS_SERIF,
size: 9,
weight: FontWeight.BOLD,
style: FontStyle.NORMAL,
Expand Down
5 changes: 2 additions & 3 deletions src/gracetabnote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//
// See `tests/gracetabnote_tests.ts` for usage examples.

// import { Font } from './font'; // RONYEH
import { Font } from './font';
import { TabNote, TabNoteStruct } from './tabnote';

export class GraceTabNote extends TabNote {
Expand All @@ -26,8 +26,7 @@ export class GraceTabNote extends TabNote {
// grace glyph scale
scale: 0.6,
// grace tablature font
font: `7.5pt Arial`,
// font: `7.5pt ${Font.SANS_SERIF}`, // RONYEH
font: `7.5pt ${Font.SANS_SERIF}`,
};

this.updateWidth();
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export * from './stringnumber';
export * from './strokes';
export * from './svgcontext';
export * from './system';
// Do not export './tables'.
// Do not export './tables' because it is internal.
export * from './tabnote';
export * from './tabslide';
export * from './tabstave';
Expand Down
4 changes: 2 additions & 2 deletions src/stave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { BoundingBox, Bounds } from './boundingbox';
import { Clef } from './clef';
import { Element, ElementStyle } from './element';
import { FontInfo, FontStyle, FontWeight } from './font';
import { Font, FontInfo, FontStyle, FontWeight } from './font';
import { KeySignature } from './keysignature';
import { Barline, BarlineType } from './stavebarline';
import { StaveModifier, StaveModifierPosition } from './stavemodifier';
Expand Down Expand Up @@ -65,7 +65,7 @@ export class Stave extends Element {
}

static TEXT_FONT: Required<FontInfo> = {
family: 'sans-serif' /* RONYEH: Font.SANS_SERIF*/,
family: Font.SANS_SERIF,
size: 8,
weight: FontWeight.NORMAL,
style: FontStyle.NORMAL,
Expand Down
4 changes: 2 additions & 2 deletions src/staveconnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// MIT License

import { Element } from './element';
import { FontInfo, FontStyle, FontWeight } from './font';
import { Font, FontInfo, FontStyle, FontWeight } from './font';
import { Glyph } from './glyph';
import { RenderContext } from './rendercontext';
import { Stave } from './stave';
Expand Down Expand Up @@ -36,7 +36,7 @@ export class StaveConnector extends Element {
}

static TEXT_FONT: Required<FontInfo> = {
family: 'Times' /* RONYEH: Font.SERIF */,
family: Font.SERIF,
size: 16,
weight: FontWeight.NORMAL,
style: FontStyle.NORMAL,
Expand Down
4 changes: 2 additions & 2 deletions src/staverepetition.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// [VexFlow](https://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
// Author Larry Kuhns 2011

import { FontInfo, FontStyle, FontWeight } from './font';
import { Font, FontInfo, FontStyle, FontWeight } from './font';
import { Glyph } from './glyph';
import { Stave } from './stave';
import { StaveModifier } from './stavemodifier';
Expand All @@ -12,7 +12,7 @@ export class Repetition extends StaveModifier {
}

static TEXT_FONT: Required<FontInfo> = {
family: 'Times' /* RONYEH: Font.SERIF */,
family: Font.SERIF,
size: 12,
weight: FontWeight.BOLD,
style: FontStyle.NORMAL,
Expand Down
4 changes: 2 additions & 2 deletions src/stavesection.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// [VexFlow](https://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
// Author Larry Kuhns 2011

import { FontInfo, FontStyle, FontWeight } from './font';
import { Font, FontInfo, FontStyle, FontWeight } from './font';
import { Stave } from './stave';
import { StaveModifier } from './stavemodifier';

Expand All @@ -11,7 +11,7 @@ export class StaveSection extends StaveModifier {
}

static TEXT_FONT: Required<FontInfo> = {
family: 'sans-serif' /* RONYEH: Font.SANS_SERIF */,
family: Font.SANS_SERIF,
size: 12,
weight: FontWeight.BOLD,
style: FontStyle.NORMAL,
Expand Down
Loading

0 comments on commit 6a9d9bf

Please sign in to comment.