VexFlowVoiceEntry.ts 8.9 KB

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