|
@@ -1,317 +1,367 @@
|
|
|
-// [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
|
|
|
-//
|
|
|
-// ## Description
|
|
|
-//
|
|
|
-// This file implements different types of pedal markings. These notation
|
|
|
-// elements indicate to the performer when to depress and release the a pedal.
|
|
|
-//
|
|
|
-// In order to create "Sostenuto", and "una corda" markings, you must set
|
|
|
-// custom text for the release/depress pedal markings.
|
|
|
-
|
|
|
-import { Vex } from './vex';
|
|
|
-import { Element } from './element';
|
|
|
-import { Glyph } from './glyph';
|
|
|
-
|
|
|
-// To enable logging for this class. Set `Vex.Flow.PedalMarking.DEBUG` to `true`.
|
|
|
-function L(...args) { if (PedalMarking.DEBUG) Vex.L('Vex.Flow.PedalMarking', args); }
|
|
|
-
|
|
|
-// Draws a pedal glyph with the provided `name` on a rendering `context`
|
|
|
-// at the coordinates `x` and `y. Takes into account the glyph data
|
|
|
-// coordinate shifts.
|
|
|
-function drawPedalGlyph(name, context, x, y, point) {
|
|
|
- const glyph_data = PedalMarking.GLYPHS[name];
|
|
|
- const glyph = new Glyph(glyph_data.code, point);
|
|
|
- glyph.render(context, x + glyph_data.x_shift, y + glyph_data.y_shift);
|
|
|
-}
|
|
|
-
|
|
|
-export class PedalMarking extends Element {
|
|
|
- // Glyph data
|
|
|
- static get GLYPHS() {
|
|
|
- return {
|
|
|
- 'pedal_depress': {
|
|
|
- code: 'v36',
|
|
|
- x_shift: -10,
|
|
|
- y_shift: 0,
|
|
|
- },
|
|
|
- 'pedal_release': {
|
|
|
- code: 'v5d',
|
|
|
- x_shift: -2,
|
|
|
- y_shift: 3,
|
|
|
- },
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- static get Styles() {
|
|
|
- return {
|
|
|
- TEXT: 1,
|
|
|
- BRACKET: 2,
|
|
|
- MIXED: 3,
|
|
|
- MIXED_OPEN_END: 4,
|
|
|
- BRACKET_OPEN_BEGIN: 5,
|
|
|
- BRACKET_OPEN_END: 6,
|
|
|
- BRACKET_OPEN_BOTH: 7
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- static get StylesString() {
|
|
|
- return {
|
|
|
- text: PedalMarking.Styles.TEXT,
|
|
|
- bracket: PedalMarking.Styles.BRACKET,
|
|
|
- mixed: PedalMarking.Styles.MIXED,
|
|
|
- mixed_open_end: PedalMarking.Styles.MIXED_OPEN_END,
|
|
|
- bracket_open_begin: PedalMarking.Styles.BRACKET_OPEN_BEGIN,
|
|
|
- bracket_open_end: PedalMarking.Styles.BRACKET_OPEN_END,
|
|
|
- bracket_open_both: PedalMarking.Styles.BRACKET_OPEN_BOTH
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- // Create a sustain pedal marking. Returns the defaults PedalMarking.
|
|
|
- // Which uses the traditional "Ped" and "*"" markings.
|
|
|
- static createSustain(notes) {
|
|
|
- const pedal = new PedalMarking(notes);
|
|
|
- return pedal;
|
|
|
- }
|
|
|
-
|
|
|
- // Create a sostenuto pedal marking
|
|
|
- static createSostenuto(notes) {
|
|
|
- const pedal = new PedalMarking(notes);
|
|
|
- pedal.setStyle(PedalMarking.Styles.MIXED);
|
|
|
- pedal.setCustomText('Sost. Ped.');
|
|
|
- return pedal;
|
|
|
- }
|
|
|
-
|
|
|
- // Create an una corda pedal marking
|
|
|
- static createUnaCorda(notes) {
|
|
|
- const pedal = new PedalMarking(notes);
|
|
|
- pedal.setStyle(PedalMarking.Styles.TEXT);
|
|
|
- pedal.setCustomText('una corda', 'tre corda');
|
|
|
- return pedal;
|
|
|
- }
|
|
|
-
|
|
|
- // ## Prototype Methods
|
|
|
- constructor(notes) {
|
|
|
- super();
|
|
|
- this.setAttribute('type', 'PedalMarking');
|
|
|
-
|
|
|
- this.notes = notes;
|
|
|
- this.style = PedalMarking.TEXT;
|
|
|
- this.line = 0;
|
|
|
-
|
|
|
- // Custom text for the release/depress markings
|
|
|
- this.custom_depress_text = '';
|
|
|
- this.custom_release_text = '';
|
|
|
-
|
|
|
- this.font = {
|
|
|
- family: 'Times New Roman',
|
|
|
- size: 12,
|
|
|
- weight: 'italic bold',
|
|
|
- };
|
|
|
-
|
|
|
- this.render_options = {
|
|
|
- bracket_height: 10,
|
|
|
- text_margin_right: 6,
|
|
|
- bracket_line_width: 1,
|
|
|
- glyph_point_size: 40,
|
|
|
- color: 'black',
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- setEndStave(stave) {
|
|
|
- this.endStave = stave;
|
|
|
- }
|
|
|
-
|
|
|
- // Set custom text for the `depress`/`release` pedal markings. No text is
|
|
|
- // set if the parameter is falsy.
|
|
|
- setCustomText(depress, release) {
|
|
|
- this.custom_depress_text = depress || '';
|
|
|
- this.custom_release_text = release || '';
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- // Set the pedal marking style
|
|
|
- setStyle(style) {
|
|
|
- if (style < 1 && style > 3) {
|
|
|
- throw new Vex.RERR('InvalidParameter', 'The style must be one found in PedalMarking.Styles');
|
|
|
- }
|
|
|
-
|
|
|
- this.style = style;
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- // Set the staff line to render the markings on
|
|
|
- setLine(line) { this.line = line; return this; }
|
|
|
-
|
|
|
- // Draw the bracket based pedal markings
|
|
|
- drawBracketed() {
|
|
|
- const ctx = this.context;
|
|
|
- let is_pedal_depressed = false;
|
|
|
- let prev_x;
|
|
|
- let prev_y;
|
|
|
- const pedal = this;
|
|
|
-
|
|
|
- // Iterate through each note
|
|
|
- this.notes.forEach((note, index, notes) => {
|
|
|
- // Each note triggers the opposite pedal action
|
|
|
- is_pedal_depressed = !is_pedal_depressed;
|
|
|
- // Get the initial coordinates for the note
|
|
|
- let x = 0;
|
|
|
- if (note) {
|
|
|
- x = note.getNoteHeadBeginX();
|
|
|
- }
|
|
|
- if (!note) {
|
|
|
- x = this.endStave.end_x;
|
|
|
- } else if (!is_pedal_depressed) {
|
|
|
- switch(pedal.style) {
|
|
|
- case PedalMarking.Styles.BRACKET_OPEN_END:
|
|
|
- case PedalMarking.Styles.BRACKET_OPEN_BOTH:
|
|
|
- case PedalMarking.Styles.MIXED_OPEN_END:
|
|
|
- x = note.getNoteHeadEndX();
|
|
|
- break;
|
|
|
- default:
|
|
|
- x -= pedal.render_options.text_margin_right;
|
|
|
- break;
|
|
|
- }
|
|
|
- } else {
|
|
|
- switch(pedal.style) {
|
|
|
- case PedalMarking.Styles.BRACKET_OPEN_BEGIN:
|
|
|
- case PedalMarking.Styles.BRACKET_OPEN_BOTH:
|
|
|
- x -= pedal.render_options.text_margin_right;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- let stave = this.endStave; // if !note
|
|
|
- if (note) {
|
|
|
- stave = note.getStave();
|
|
|
- }
|
|
|
- let y = stave.getYForBottomText(pedal.line + 3);
|
|
|
- if (prev_y) { // compiler complains if we shorten this
|
|
|
- if (prev_y > y) { // don't slope pedal marking upwards (nonstandard)
|
|
|
- y = prev_y;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Throw if current note is positioned before the previous note
|
|
|
- if (x < prev_x) {
|
|
|
- // TODO this unnecessarily throws for missing endNote fix
|
|
|
- // throw new Vex.RERR(
|
|
|
- // 'InvalidConfiguration', 'The notes provided must be in order of ascending x positions'
|
|
|
- // );
|
|
|
- }
|
|
|
-
|
|
|
- // Determine if the previous or next note are the same
|
|
|
- // as the current note. We need to keep track of this for
|
|
|
- // when adjustments are made for the release+depress action
|
|
|
- const next_is_same = notes[index + 1] === note;
|
|
|
- const prev_is_same = notes[index - 1] === note;
|
|
|
-
|
|
|
- let x_shift = 0;
|
|
|
- if (is_pedal_depressed) {
|
|
|
- // Adjustment for release+depress
|
|
|
- x_shift = prev_is_same ? 5 : 0;
|
|
|
-
|
|
|
- if ((pedal.style === PedalMarking.Styles.MIXED || pedal.style === PedalMarking.Styles.MIXED_OPEN_END) && !prev_is_same) {
|
|
|
- // For MIXED style, start with text instead of bracket
|
|
|
- if (pedal.custom_depress_text) {
|
|
|
- // If we have custom text, use instead of the default "Ped" glyph
|
|
|
- const text_width = ctx.measureText(pedal.custom_depress_text).width;
|
|
|
- ctx.fillText(pedal.custom_depress_text, x - (text_width / 2), y);
|
|
|
- x_shift = (text_width / 2) + pedal.render_options.text_margin_right;
|
|
|
- } else {
|
|
|
- // Render the Ped glyph in position
|
|
|
- drawPedalGlyph('pedal_depress', ctx, x, y, pedal.render_options.glyph_point_size);
|
|
|
- x_shift = 20 + pedal.render_options.text_margin_right;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Draw start bracket
|
|
|
- ctx.beginPath();
|
|
|
- if (pedal.style === PedalMarking.Styles.BRACKET_OPEN_BEGIN || pedal.style === PedalMarking.Styles.BRACKET_OPEN_BOTH) {
|
|
|
- ctx.moveTo(x + x_shift, y);
|
|
|
- } else {
|
|
|
- ctx.moveTo(x, y - pedal.render_options.bracket_height);
|
|
|
- ctx.lineTo(x + x_shift, y);
|
|
|
- }
|
|
|
- ctx.stroke();
|
|
|
- ctx.closePath();
|
|
|
- }
|
|
|
- } else {
|
|
|
- // Adjustment for release+depress
|
|
|
- x_shift = next_is_same ? -5 : 0;
|
|
|
-
|
|
|
- // Draw end bracket
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(prev_x, prev_y);
|
|
|
- ctx.lineTo(x + x_shift, y);
|
|
|
- if (pedal.style !== PedalMarking.Styles.BRACKET_OPEN_END && pedal.style !== PedalMarking.Styles.MIXED_OPEN_END &&
|
|
|
- pedal.style !== PedalMarking.Styles.BRACKET_OPEN_BOTH) {
|
|
|
- ctx.lineTo(x, y - pedal.render_options.bracket_height);
|
|
|
- }
|
|
|
- ctx.stroke();
|
|
|
- ctx.closePath();
|
|
|
- }
|
|
|
-
|
|
|
- // Store previous coordinates
|
|
|
- prev_x = x + x_shift;
|
|
|
- prev_y = y;
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- // Draw the text based pedal markings. This defaults to the traditional
|
|
|
- // "Ped" and "*"" symbols if no custom text has been provided.
|
|
|
- drawText() {
|
|
|
- const ctx = this.context;
|
|
|
- let is_pedal_depressed = false;
|
|
|
- const pedal = this;
|
|
|
-
|
|
|
- // The glyph point size
|
|
|
- const point = pedal.render_options.glyph_point_size;
|
|
|
-
|
|
|
- // Iterate through each note, placing glyphs or custom text accordingly
|
|
|
- this.notes.forEach(note => {
|
|
|
- is_pedal_depressed = !is_pedal_depressed;
|
|
|
- const stave = note.getStave();
|
|
|
- const x = note.getAbsoluteX();
|
|
|
- const y = stave.getYForBottomText(pedal.line + 3);
|
|
|
-
|
|
|
- let text_width = 0;
|
|
|
- if (is_pedal_depressed) {
|
|
|
- if (pedal.custom_depress_text) {
|
|
|
- text_width = ctx.measureText(pedal.custom_depress_text).width;
|
|
|
- ctx.fillText(pedal.custom_depress_text, x - (text_width / 2), y);
|
|
|
- } else {
|
|
|
- drawPedalGlyph('pedal_depress', ctx, x, y, point);
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (pedal.custom_release_text) {
|
|
|
- text_width = ctx.measureText(pedal.custom_release_text).width;
|
|
|
- ctx.fillText(pedal.custom_release_text, x - (text_width / 2), y);
|
|
|
- } else {
|
|
|
- drawPedalGlyph('pedal_release', ctx, x, y, point);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- // Render the pedal marking in position on the rendering context
|
|
|
- draw() {
|
|
|
- const ctx = this.checkContext();
|
|
|
- this.setRendered();
|
|
|
-
|
|
|
- ctx.save();
|
|
|
- ctx.setStrokeStyle(this.render_options.color);
|
|
|
- ctx.setFillStyle(this.render_options.color);
|
|
|
- ctx.setFont(this.font.family, this.font.size, this.font.weight);
|
|
|
-
|
|
|
- L('Rendering Pedal Marking');
|
|
|
-
|
|
|
- if (this.style === PedalMarking.Styles.BRACKET || this.style === PedalMarking.Styles.MIXED || this.style === PedalMarking.Styles.MIXED_OPEN_END ||
|
|
|
- this.style === PedalMarking.Styles.BRACKET_OPEN_BEGIN || this.style === PedalMarking.Styles.BRACKET_OPEN_END || this.style === PedalMarking.Styles.BRACKET_OPEN_BOTH) {
|
|
|
- ctx.setLineWidth(this.render_options.bracket_line_width);
|
|
|
- this.drawBracketed();
|
|
|
- } else if (this.style === PedalMarking.Styles.TEXT) {
|
|
|
- this.drawText();
|
|
|
- }
|
|
|
-
|
|
|
- ctx.restore();
|
|
|
- }
|
|
|
+// [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
|
|
|
+//
|
|
|
+// ## Description
|
|
|
+//
|
|
|
+// This file implements different types of pedal markings. These notation
|
|
|
+// elements indicate to the performer when to depress and release the a pedal.
|
|
|
+//
|
|
|
+// In order to create "Sostenuto", and "una corda" markings, you must set
|
|
|
+// custom text for the release/depress pedal markings.
|
|
|
+
|
|
|
+import { Vex } from './vex';
|
|
|
+import { Element } from './element';
|
|
|
+import { Glyph } from './glyph';
|
|
|
+import { StaveModifier } from './stavemodifier';
|
|
|
+
|
|
|
+// To enable logging for this class. Set `Vex.Flow.PedalMarking.DEBUG` to `true`.
|
|
|
+function L(...args) { if (PedalMarking.DEBUG) Vex.L('Vex.Flow.PedalMarking', args); }
|
|
|
+
|
|
|
+// Draws a pedal glyph with the provided `name` on a rendering `context`
|
|
|
+// at the coordinates `x` and `y. Takes into account the glyph data
|
|
|
+// coordinate shifts.
|
|
|
+function drawPedalGlyph(name, context, x, y, point) {
|
|
|
+ const glyph_data = PedalMarking.GLYPHS[name];
|
|
|
+ const glyph = new Glyph(glyph_data.code, point);
|
|
|
+ glyph.render(context, x + glyph_data.x_shift, y + glyph_data.y_shift);
|
|
|
+}
|
|
|
+
|
|
|
+export class PedalMarking extends Element {
|
|
|
+ // Glyph data
|
|
|
+ static get GLYPHS() {
|
|
|
+ return {
|
|
|
+ 'pedal_depress': {
|
|
|
+ code: 'v36',
|
|
|
+ x_shift: -10,
|
|
|
+ y_shift: 0,
|
|
|
+ },
|
|
|
+ 'pedal_release': {
|
|
|
+ code: 'v5d',
|
|
|
+ x_shift: -2,
|
|
|
+ y_shift: 3,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ static get Styles() {
|
|
|
+ return {
|
|
|
+ TEXT: 1,
|
|
|
+ BRACKET: 2,
|
|
|
+ MIXED: 3,
|
|
|
+ MIXED_OPEN_END: 4,
|
|
|
+ BRACKET_OPEN_BEGIN: 5,
|
|
|
+ BRACKET_OPEN_END: 6,
|
|
|
+ BRACKET_OPEN_BOTH: 7
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ static get StylesString() {
|
|
|
+ return {
|
|
|
+ text: PedalMarking.Styles.TEXT,
|
|
|
+ bracket: PedalMarking.Styles.BRACKET,
|
|
|
+ mixed: PedalMarking.Styles.MIXED,
|
|
|
+ mixed_open_end: PedalMarking.Styles.MIXED_OPEN_END,
|
|
|
+ bracket_open_begin: PedalMarking.Styles.BRACKET_OPEN_BEGIN,
|
|
|
+ bracket_open_end: PedalMarking.Styles.BRACKET_OPEN_END,
|
|
|
+ bracket_open_both: PedalMarking.Styles.BRACKET_OPEN_BOTH
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create a sustain pedal marking. Returns the defaults PedalMarking.
|
|
|
+ // Which uses the traditional "Ped" and "*"" markings.
|
|
|
+ static createSustain(notes) {
|
|
|
+ const pedal = new PedalMarking(notes);
|
|
|
+ return pedal;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create a sostenuto pedal marking
|
|
|
+ static createSostenuto(notes) {
|
|
|
+ const pedal = new PedalMarking(notes);
|
|
|
+ pedal.setStyle(PedalMarking.Styles.MIXED);
|
|
|
+ pedal.setCustomText('Sost. Ped.');
|
|
|
+ return pedal;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create an una corda pedal marking
|
|
|
+ static createUnaCorda(notes) {
|
|
|
+ const pedal = new PedalMarking(notes);
|
|
|
+ pedal.setStyle(PedalMarking.Styles.TEXT);
|
|
|
+ pedal.setCustomText('una corda', 'tre corda');
|
|
|
+ return pedal;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ## Prototype Methods
|
|
|
+ constructor(notes) {
|
|
|
+ super();
|
|
|
+ this.setAttribute('type', 'PedalMarking');
|
|
|
+ this.EndsStave = false;
|
|
|
+ this.ChangeBegin = false;
|
|
|
+ this.ChangeEnd = false;
|
|
|
+ this.notes = notes;
|
|
|
+ this.style = PedalMarking.TEXT;
|
|
|
+ this.line = 0;
|
|
|
+
|
|
|
+ // Custom text for the release/depress markings
|
|
|
+ this.custom_depress_text = '';
|
|
|
+ this.custom_release_text = '';
|
|
|
+
|
|
|
+ this.font = {
|
|
|
+ family: 'Times New Roman',
|
|
|
+ size: 12,
|
|
|
+ weight: 'italic bold',
|
|
|
+ };
|
|
|
+
|
|
|
+ this.render_options = {
|
|
|
+ bracket_height: 10,
|
|
|
+ text_margin_right: 6,
|
|
|
+ bracket_line_width: 1,
|
|
|
+ glyph_point_size: 40,
|
|
|
+ color: 'black',
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ setEndStave(stave) {
|
|
|
+ this.endStave = stave;
|
|
|
+ this.endStaveAddedWidth = 0;
|
|
|
+ this.startMargin = 0;
|
|
|
+ this.endMargin = 0;
|
|
|
+ if(Array.isArray(this.endStave.modifiers)){
|
|
|
+ for(let i = 0; i < this.endStave.modifiers.length; i++){
|
|
|
+ let nextMod = this.endStave.modifiers[i];
|
|
|
+ if(nextMod && nextMod.position === StaveModifier.Position.END && nextMod.width){
|
|
|
+ this.endStaveAddedWidth += nextMod.width;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Set custom text for the `depress`/`release` pedal markings. No text is
|
|
|
+ // set if the parameter is falsy.
|
|
|
+ setCustomText(depress, release) {
|
|
|
+ this.custom_depress_text = depress || '';
|
|
|
+ this.custom_release_text = release || '';
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Set the pedal marking style
|
|
|
+ setStyle(style) {
|
|
|
+ if (style < 1 && style > 3) {
|
|
|
+ throw new Vex.RERR('InvalidParameter', 'The style must be one found in PedalMarking.Styles');
|
|
|
+ }
|
|
|
+
|
|
|
+ this.style = style;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Set the staff line to render the markings on
|
|
|
+ setLine(line) { this.line = line; return this; }
|
|
|
+
|
|
|
+ // Draw the bracket based pedal markings
|
|
|
+ drawBracketed() {
|
|
|
+ const ctx = this.context;
|
|
|
+ let is_pedal_depressed = false;
|
|
|
+ let prev_x;
|
|
|
+ let prev_y;
|
|
|
+ const pedal = this;
|
|
|
+ // Iterate through each note
|
|
|
+ this.notes.forEach((note, index, notes) => {
|
|
|
+ // Each note triggers the opposite pedal action
|
|
|
+ is_pedal_depressed = !is_pedal_depressed;
|
|
|
+ // Get the initial coordinates for the note
|
|
|
+ let x = 0;
|
|
|
+ if (note) {
|
|
|
+ //default to note head begin
|
|
|
+ x = note.getNoteHeadBeginX();
|
|
|
+ } else {
|
|
|
+ x = this.endStave.end_x + this.endStaveAddedWidth;
|
|
|
+ }
|
|
|
+
|
|
|
+ //If this pedal doesn't end a stave...
|
|
|
+ if(!this.EndsStave){
|
|
|
+ if(note){
|
|
|
+ //pedal across a single note or just the end note
|
|
|
+ if(!is_pedal_depressed){
|
|
|
+ switch(pedal.style) {
|
|
|
+ case PedalMarking.Styles.BRACKET_OPEN_END:
|
|
|
+ case PedalMarking.Styles.BRACKET_OPEN_BOTH:
|
|
|
+ case PedalMarking.Styles.MIXED_OPEN_END:
|
|
|
+ x = note.getNoteHeadEndX();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if(this.ChangeEnd){
|
|
|
+ //Start in the middle of the note
|
|
|
+ x = note.getAbsoluteX();
|
|
|
+ } else {
|
|
|
+ x = note.getNoteHeadBeginX() - pedal.render_options.text_margin_right;
|
|
|
+ this.startMargin = -pedal.render_options.text_margin_right;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else if(this.ChangeBegin){
|
|
|
+ x = note.getAbsoluteX();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //Ends stave and we are at the end...
|
|
|
+ if(!is_pedal_depressed){
|
|
|
+ //IF we are the end, set the end to the stave end
|
|
|
+ if(note){
|
|
|
+ if(this.ChangeEnd){
|
|
|
+ //Start in the middle of the note
|
|
|
+ x = note.getAbsoluteX();
|
|
|
+ } else {
|
|
|
+ x = note.getStave().end_x + this.endStaveAddedWidth - pedal.render_options.text_margin_right;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ x = this.endStave.end_x + this.endStaveAddedWidth - pedal.render_options.text_margin_right;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.endMargin = -pedal.render_options.text_margin_right;
|
|
|
+ } else if (this.ChangeBegin){
|
|
|
+ x = note.getAbsoluteX();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let stave = this.endStave; // if !note
|
|
|
+ if (note) {
|
|
|
+ stave = note.getStave();
|
|
|
+ }
|
|
|
+ let y = stave.getYForBottomText(pedal.line + 3);
|
|
|
+ if (prev_y) { // compiler complains if we shorten this
|
|
|
+ if (prev_y > y) { // don't slope pedal marking upwards (nonstandard)
|
|
|
+ y = prev_y;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Throw if current note is positioned before the previous note
|
|
|
+ if (x < prev_x) {
|
|
|
+ // TODO this unnecessarily throws for missing endNote fix
|
|
|
+ // throw new Vex.RERR(
|
|
|
+ // 'InvalidConfiguration', 'The notes provided must be in order of ascending x positions'
|
|
|
+ // );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Determine if the previous or next note are the same
|
|
|
+ // as the current note. We need to keep track of this for
|
|
|
+ // when adjustments are made for the release+depress action
|
|
|
+ const next_is_same = notes[index + 1] === note;
|
|
|
+ const prev_is_same = notes[index - 1] === note;
|
|
|
+
|
|
|
+ let x_shift = 0;
|
|
|
+ if (is_pedal_depressed) {
|
|
|
+ // Adjustment for release+depress
|
|
|
+ x_shift = prev_is_same ? 5 : 0;
|
|
|
+
|
|
|
+ if ((pedal.style === PedalMarking.Styles.MIXED || pedal.style === PedalMarking.Styles.MIXED_OPEN_END) && !prev_is_same) {
|
|
|
+ // For MIXED style, start with text instead of bracket
|
|
|
+ if (pedal.custom_depress_text) {
|
|
|
+ // If we have custom text, use instead of the default "Ped" glyph
|
|
|
+ const text_width = ctx.measureText(pedal.custom_depress_text).width;
|
|
|
+ ctx.fillText(pedal.custom_depress_text, x - (text_width / 2), y);
|
|
|
+ x_shift = (text_width / 2) + pedal.render_options.text_margin_right;
|
|
|
+ } else {
|
|
|
+ // Render the Ped glyph in position
|
|
|
+ drawPedalGlyph('pedal_depress', ctx, x, y, pedal.render_options.glyph_point_size);
|
|
|
+ x_shift = 20 + pedal.render_options.text_margin_right;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Draw start bracket
|
|
|
+ ctx.beginPath();
|
|
|
+ if (pedal.style === PedalMarking.Styles.BRACKET_OPEN_BEGIN || pedal.style === PedalMarking.Styles.BRACKET_OPEN_BOTH) {
|
|
|
+ ctx.moveTo(x + x_shift, y);
|
|
|
+ } else {
|
|
|
+ if(this.ChangeBegin){
|
|
|
+ x += 5;
|
|
|
+ }
|
|
|
+ ctx.moveTo(x, y - pedal.render_options.bracket_height);
|
|
|
+ if(this.ChangeBegin){
|
|
|
+ x += 5;
|
|
|
+ }
|
|
|
+ ctx.lineTo(x + x_shift, y);
|
|
|
+ }
|
|
|
+ ctx.stroke();
|
|
|
+ ctx.closePath();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Adjustment for release+depress
|
|
|
+ x_shift = next_is_same && !this.EndsStave ? -5 : 0;
|
|
|
+
|
|
|
+ // Draw end bracket
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(prev_x, prev_y);
|
|
|
+ ctx.lineTo(x + x_shift, y);
|
|
|
+ if (pedal.style !== PedalMarking.Styles.BRACKET_OPEN_END && pedal.style !== PedalMarking.Styles.MIXED_OPEN_END &&
|
|
|
+ pedal.style !== PedalMarking.Styles.BRACKET_OPEN_BOTH) {
|
|
|
+ if(this.ChangeEnd){
|
|
|
+ x += 5;
|
|
|
+ }
|
|
|
+ ctx.lineTo(x, y - pedal.render_options.bracket_height);
|
|
|
+ }
|
|
|
+ ctx.stroke();
|
|
|
+ ctx.closePath();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Store previous coordinates
|
|
|
+ prev_x = x + x_shift;
|
|
|
+ prev_y = y;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // Draw the text based pedal markings. This defaults to the traditional
|
|
|
+ // "Ped" and "*"" symbols if no custom text has been provided.
|
|
|
+ drawText() {
|
|
|
+ const ctx = this.context;
|
|
|
+ let is_pedal_depressed = false;
|
|
|
+ const pedal = this;
|
|
|
+
|
|
|
+ // The glyph point size
|
|
|
+ const point = pedal.render_options.glyph_point_size;
|
|
|
+
|
|
|
+ // Iterate through each note, placing glyphs or custom text accordingly
|
|
|
+ this.notes.forEach(note => {
|
|
|
+ is_pedal_depressed = !is_pedal_depressed;
|
|
|
+ const stave = note.getStave();
|
|
|
+ const x = note.getAbsoluteX();
|
|
|
+ const y = stave.getYForBottomText(pedal.line + 3);
|
|
|
+
|
|
|
+ let text_width = 0;
|
|
|
+ if (is_pedal_depressed) {
|
|
|
+ if (pedal.custom_depress_text) {
|
|
|
+ text_width = ctx.measureText(pedal.custom_depress_text).width;
|
|
|
+ ctx.fillText(pedal.custom_depress_text, x - (text_width / 2), y);
|
|
|
+ } else {
|
|
|
+ drawPedalGlyph('pedal_depress', ctx, x, y, point);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (pedal.custom_release_text) {
|
|
|
+ text_width = ctx.measureText(pedal.custom_release_text).width;
|
|
|
+ ctx.fillText(pedal.custom_release_text, x - (text_width / 2), y);
|
|
|
+ } else {
|
|
|
+ drawPedalGlyph('pedal_release', ctx, x, y, point);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // Render the pedal marking in position on the rendering context
|
|
|
+ draw() {
|
|
|
+ const ctx = this.checkContext();
|
|
|
+ this.setRendered();
|
|
|
+
|
|
|
+ ctx.save();
|
|
|
+ ctx.setStrokeStyle(this.render_options.color);
|
|
|
+ ctx.setFillStyle(this.render_options.color);
|
|
|
+ ctx.setFont(this.font.family, this.font.size, this.font.weight);
|
|
|
+
|
|
|
+ L('Rendering Pedal Marking');
|
|
|
+
|
|
|
+ if (this.style === PedalMarking.Styles.BRACKET || this.style === PedalMarking.Styles.MIXED || this.style === PedalMarking.Styles.MIXED_OPEN_END ||
|
|
|
+ this.style === PedalMarking.Styles.BRACKET_OPEN_BEGIN || this.style === PedalMarking.Styles.BRACKET_OPEN_END || this.style === PedalMarking.Styles.BRACKET_OPEN_BOTH) {
|
|
|
+ ctx.setLineWidth(this.render_options.bracket_line_width);
|
|
|
+ this.drawBracketed();
|
|
|
+ } else if (this.style === PedalMarking.Styles.TEXT) {
|
|
|
+ this.drawText();
|
|
|
+ }
|
|
|
+
|
|
|
+ ctx.restore();
|
|
|
+ }
|
|
|
}
|