VexFlowVoiceEntry.ts 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import Vex from "vexflow";
  2. import { VoiceEntry } from "../../VoiceData/VoiceEntry";
  3. import { GraphicalVoiceEntry } from "../GraphicalVoiceEntry";
  4. import { GraphicalStaffEntry } from "../GraphicalStaffEntry";
  5. import { unitInPixels } from "./VexFlowMusicSheetDrawer";
  6. import { NoteEnum } from "../../../Common/DataObjects/Pitch";
  7. import { Note } from "../../VoiceData/Note";
  8. import { ColoringModes } from "./../DrawingParameters";
  9. import { GraphicalNote } from "../GraphicalNote";
  10. export class VexFlowVoiceEntry extends GraphicalVoiceEntry {
  11. private mVexFlowStaveNote: Vex.Flow.StemmableNote;
  12. constructor(parentVoiceEntry: VoiceEntry, parentStaffEntry: GraphicalStaffEntry) {
  13. super(parentVoiceEntry, parentStaffEntry);
  14. }
  15. public applyBordersFromVexflow(): void {
  16. const staveNote: any = (this.vfStaveNote as any);
  17. if (!staveNote.getNoteHeadBeginX) {
  18. return;
  19. }
  20. const boundingBox: any = staveNote.getBoundingBox();
  21. const modifierWidth: number = staveNote.getNoteHeadBeginX() - boundingBox.x;
  22. this.PositionAndShape.RelativePosition.y = boundingBox.y / unitInPixels;
  23. this.PositionAndShape.BorderTop = 0;
  24. this.PositionAndShape.BorderBottom = boundingBox.h / unitInPixels;
  25. this.PositionAndShape.BorderLeft = -(modifierWidth + staveNote.width / 2) / unitInPixels; // Left of our X origin is the modifier
  26. this.PositionAndShape.BorderRight = (boundingBox.w - modifierWidth) / unitInPixels; // Right of x origin is the note
  27. }
  28. public set vfStaveNote(value: Vex.Flow.StemmableNote) {
  29. this.mVexFlowStaveNote = value;
  30. }
  31. public get vfStaveNote(): Vex.Flow.StemmableNote {
  32. return this.mVexFlowStaveNote;
  33. }
  34. /** (Re-)color notes and stems by setting their Vexflow styles.
  35. * Could be made redundant by a Vexflow PR, but Vexflow needs more solid and permanent color methods/variables for that
  36. * See VexFlowConverter.StaveNote()
  37. */
  38. public color(): void {
  39. const defaultColorNotehead: string = this.rules.DefaultColorNotehead;
  40. const defaultColorRest: string = this.rules.DefaultColorRest;
  41. const defaultColorStem: string = this.rules.DefaultColorStem;
  42. const transparentColor: string = "#00000000"; // transparent color in vexflow
  43. let noteheadColor: string; // if null: no noteheadcolor to set (stays black)
  44. let sourceNoteNoteheadColor: string;
  45. const vfStaveNote: any = (<VexFlowVoiceEntry>(this as any)).vfStaveNote;
  46. for (let i: number = 0; i < this.notes.length; i++) {
  47. const note: GraphicalNote = this.notes[i];
  48. sourceNoteNoteheadColor = note.sourceNote.NoteheadColor;
  49. noteheadColor = sourceNoteNoteheadColor;
  50. // Switch between XML colors and automatic coloring
  51. if (this.rules.ColoringMode === ColoringModes.AutoColoring ||
  52. this.rules.ColoringMode === ColoringModes.CustomColorSet) {
  53. if (note.sourceNote.isRest()) {
  54. noteheadColor = this.rules.ColoringSetCurrent.getValue(-1);
  55. } else {
  56. const fundamentalNote: NoteEnum = note.sourceNote.Pitch.FundamentalNote;
  57. noteheadColor = this.rules.ColoringSetCurrent.getValue(fundamentalNote);
  58. }
  59. }
  60. if (!note.sourceNote.PrintObject) {
  61. noteheadColor = transparentColor; // transparent
  62. } else if (!noteheadColor // revert transparency after PrintObject was set to false, then true again
  63. || noteheadColor === "#000000" // questionable, because you might want to set specific notes to black,
  64. // but unfortunately some programs export everything explicitly as black
  65. ) {
  66. noteheadColor = this.rules.DefaultColorNotehead;
  67. }
  68. // DEBUG runtime coloring test
  69. /*const testColor: string = "#FF0000";
  70. if (i === 2 && Math.random() < 0.1 && note.sourceNote.NoteheadColor !== testColor) {
  71. const measureNumber: number = note.parentVoiceEntry.parentStaffEntry.parentMeasure.MeasureNumber;
  72. noteheadColor = testColor;
  73. console.log("color changed to " + noteheadColor + " of this note:\n" + note.sourceNote.Pitch.ToString() +
  74. ", in measure #" + measureNumber);
  75. }*/
  76. if (!sourceNoteNoteheadColor && this.rules.ColoringMode === ColoringModes.XML && note.sourceNote.PrintObject) {
  77. if (!note.sourceNote.isRest() && defaultColorNotehead) {
  78. noteheadColor = defaultColorNotehead;
  79. } else if (note.sourceNote.isRest() && defaultColorRest) {
  80. noteheadColor = defaultColorRest;
  81. }
  82. }
  83. if (noteheadColor && note.sourceNote.PrintObject) {
  84. note.sourceNote.NoteheadColorCurrentlyRendered = noteheadColor;
  85. } else if (!noteheadColor) {
  86. continue;
  87. }
  88. // color notebeam if all noteheads have same color and stem coloring enabled
  89. if (this.rules.ColoringEnabled && note.sourceNote.NoteBeam && this.rules.ColorBeams) {
  90. const beamNotes: Note[] = note.sourceNote.NoteBeam.Notes;
  91. let colorBeam: boolean = true;
  92. for (let j: number = 0; j < beamNotes.length; j++) {
  93. if (beamNotes[j].NoteheadColorCurrentlyRendered !== noteheadColor) {
  94. colorBeam = false;
  95. }
  96. }
  97. if (colorBeam) {
  98. if (vfStaveNote?.beam?.setStyle) {
  99. vfStaveNote.beam.setStyle({ fillStyle: noteheadColor, strokeStyle: noteheadColor});
  100. }
  101. }
  102. }
  103. if (vfStaveNote) {
  104. if (vfStaveNote.note_heads) { // see VexFlowConverter, needs Vexflow PR
  105. const notehead: any = vfStaveNote.note_heads[i];
  106. if (notehead) {
  107. notehead.setStyle({ fillStyle: noteheadColor, strokeStyle: noteheadColor });
  108. }
  109. }
  110. // set ledger line color. TODO coordinate this with VexFlowConverter.StaveNote(), where there's also still code for this, maybe unnecessarily.
  111. if ((vfStaveNote as any).setLedgerLineStyle) { // setLedgerLineStyle doesn't exist on TabNote or rest, would throw error.
  112. if (noteheadColor === transparentColor) {
  113. (vfStaveNote as any).setLedgerLineStyle(
  114. { fillStyle: noteheadColor, strokeStyle: noteheadColor, lineWidth: this.rules.LedgerLineWidth });
  115. } else {
  116. (vfStaveNote as any).setLedgerLineStyle({
  117. fillStyle: this.rules.LedgerLineColorDefault,
  118. lineWidth: this.rules.LedgerLineWidth,
  119. strokeStyle: this.rules.LedgerLineColorDefault
  120. });
  121. // we could give the color (style) as noteheadColor, but then we need to figure out which note has the ledger line.
  122. // otherwise ledger lines get the color of the top note, see Function Test Color.
  123. }
  124. }
  125. }
  126. }
  127. // color stems
  128. let stemColor: string = defaultColorStem; // reset to black/default when coloring was disabled. maybe needed elsewhere too
  129. if (this.rules.ColoringEnabled) {
  130. stemColor = this.parentVoiceEntry.StemColor; // TODO: once coloringSetCustom gets stem color, respect it
  131. if (!stemColor
  132. || stemColor === "#000000") { // see above, noteheadColor === "#000000"
  133. stemColor = defaultColorStem;
  134. }
  135. if (this.rules.ColorStemsLikeNoteheads && noteheadColor) {
  136. // condition could be even more fine-grained by only recoloring if there was no custom StemColor set. will be more complex though
  137. stemColor = noteheadColor;
  138. }
  139. }
  140. let stemTransparent: boolean = true;
  141. for (const note of this.parentVoiceEntry.Notes) {
  142. if (note.PrintObject) {
  143. stemTransparent = false;
  144. break;
  145. }
  146. }
  147. if (stemTransparent) {
  148. stemColor = transparentColor;
  149. }
  150. const stemStyle: Object = { fillStyle: stemColor, strokeStyle: stemColor };
  151. if (vfStaveNote && vfStaveNote.setStemStyle) {
  152. if (!stemTransparent) {
  153. this.parentVoiceEntry.StemColor = stemColor;
  154. }
  155. vfStaveNote.setStemStyle(stemStyle);
  156. if (vfStaveNote.flag && vfStaveNote.setFlagStyle && this.rules.ColorFlags) {
  157. vfStaveNote.setFlagStyle(stemStyle);
  158. }
  159. }
  160. }
  161. }