Ver código fonte

Feature/measure numbers (#245)

* Ported calculateMeasureNumbers from .NET code instead of vexflow methods
* Implemented measure number without skyline
Benjamin Giesinger 7 anos atrás
pai
commit
2c8fad6c23

+ 28 - 12
external/vexflow/vexflow.d.ts

@@ -1,4 +1,7 @@
+
+
 declare namespace Vex {
+
     export module Flow {
         const RESOLUTION: any;
 
@@ -28,7 +31,7 @@ declare namespace Vex {
 
             public getH(): number;
 
-            public draw(ctx: Vex.Flow.RenderContext) : void;            
+            public draw(ctx: Vex.Flow.RenderContext): void;
         }
 
         export class Tickable {
@@ -73,7 +76,7 @@ declare namespace Vex {
             public setStemDirection(direction: number): StemmableNote;
         }
 
-        export class StaveNote extends StemmableNote{
+        export class StaveNote extends StemmableNote {
             constructor(note_struct: any);
 
             public getNoteHeadBounds(): any;
@@ -129,7 +132,7 @@ declare namespace Vex {
             public setWidth(width: number): Stave;
 
             public getNoteStartX(): number;
-            
+
             public getModifierXShift(): number;
 
             public getNoteEndX(): number;
@@ -138,6 +141,8 @@ declare namespace Vex {
 
             public setKeySignature(keySpec: any, cancelKeySpec: any, position: any): Stave;
 
+            public setText(text: string, position: number, options: any): void;
+
             public format(): void;
 
             public getSpacingBetweenLines(): number;
@@ -149,7 +154,7 @@ declare namespace Vex {
             public getYForLine(y: number): number;
 
             public getModifiers(pos: any, cat: any): Clef[]; // FIXME
-            
+
             public setContext(ctx: RenderContext): Stave;
 
             public addModifier(mod: any, pos: any): void;
@@ -173,10 +178,21 @@ declare namespace Vex {
             public setPosition(position: number): Modifier;
         }
 
+
         export class StaveModifier extends Modifier {
-            public static Position: any;
-            
+            public static get Position() {
+                return {
+                    LEFT: 1,
+                    RIGHT: 2,
+                    ABOVE: 3,
+                    BELOW: 4,
+                    BEGIN: 5,
+                    END: 6,
+                };
+            }
+
             public getPosition(): number;
+
         }
 
         export class Repetition extends StaveModifier {
@@ -209,7 +225,7 @@ declare namespace Vex {
 
             public resize(a: number, b: number): void;
 
-            public getContext(): CanvasContext|SVGContext;
+            public getContext(): CanvasContext | SVGContext;
         }
 
         export class TimeSignature extends StaveModifier {
@@ -230,7 +246,7 @@ declare namespace Vex {
         export class Articulation extends Modifier {
             constructor(type: string);
         }
-        
+
         export class Beam {
             constructor(notes: StaveNote[], auto_stem: boolean);
 
@@ -265,10 +281,10 @@ declare namespace Vex {
             public attributes: any;
             public state: any;
         }
-        
+
         export class StaveConnector {
             constructor(top: Stave, bottom: Stave);
-                        
+
             public static type: any;
 
             public setType(type: any): StaveConnector;
@@ -278,9 +294,9 @@ declare namespace Vex {
             public setXShift(shift: number): StaveConnector;
 
             public top_stave: Stave;
-            
+
             public bottom_stave: Stave;
-            
+
             public thickness: number;
 
             public width: number;

+ 76 - 2
src/MusicalScore/Graphical/MusicSheetCalculator.ts

@@ -331,8 +331,82 @@ export abstract class MusicSheetCalculator {
      * @param musicSystem
      */
     protected calculateMeasureNumberPlacement(musicSystem: MusicSystem): void {
-        throw new Error("abstract, not implemented");
-    }
+        const staffLine: StaffLine = musicSystem.StaffLines[0];
+        let currentMeasureNumber: number = staffLine.Measures[0].MeasureNumber;
+        for (const measure of staffLine.Measures) {
+            if (measure.MeasureNumber === 0 || measure.MeasureNumber === 1) {
+                currentMeasureNumber = measure.MeasureNumber;
+            }
+
+            if ((measure.MeasureNumber === currentMeasureNumber ||
+                measure.MeasureNumber === currentMeasureNumber + this.rules.MeasureNumberLabelOffset) &&
+                !measure.parentSourceMeasure.ImplicitMeasure) {
+                if (measure.MeasureNumber !== 1 ||
+                    (measure.MeasureNumber === 1 && measure !== staffLine.Measures[0])) {
+                        this.calculateSingleMeasureNumberPlacement(measure, staffLine, musicSystem);
+                    }
+                currentMeasureNumber = measure.MeasureNumber;
+            }
+        }
+    }
+
+        /// <summary>
+        /// This method calculates a single MeasureNumberLabel and adds it to the graphical label list of the music system
+        /// </summary>
+        /// <param name="measure"></param>
+        /// <param name="staffLine"></param>
+        /// <param name="musicSystem"></param>
+        private calculateSingleMeasureNumberPlacement(measure: StaffMeasure, staffLine: StaffLine, musicSystem: MusicSystem): void {
+            const labelNumber: string = measure.MeasureNumber.toString();
+            const graphicalLabel: GraphicalLabel = new GraphicalLabel(new Label(labelNumber), this.rules.MeasureNumberLabelHeight,
+                                                                      TextAlignment.LeftBottom);
+            // FIXME: Change if Skyline is available
+            // const skyBottomLineCalculator: SkyBottomLineCalculator = new SkyBottomLineCalculator(this.rules);
+
+            // calculate LabelBoundingBox and set PSI parent
+            graphicalLabel.setLabelPositionAndShapeBorders();
+            graphicalLabel.PositionAndShape.Parent = musicSystem.PositionAndShape;
+
+            // calculate relative Position
+            const relativeX: number = staffLine.PositionAndShape.RelativePosition.x +
+                              measure.PositionAndShape.RelativePosition.x - graphicalLabel.PositionAndShape.BorderMarginLeft;
+            let relativeY: number;
+
+            // and the corresponding SkyLine indeces
+            let start: number = relativeX;
+            let end: number = relativeX - graphicalLabel.PositionAndShape.BorderLeft + graphicalLabel.PositionAndShape.BorderMarginRight;
+
+            // take into account the InstrumentNameLabel's at the beginning of the first MusicSystem
+            if (staffLine === musicSystem.StaffLines[0] && musicSystem === musicSystem.Parent.MusicSystems[0]) {
+                start -= staffLine.PositionAndShape.RelativePosition.x;
+                end -= staffLine.PositionAndShape.RelativePosition.x;
+            }
+
+            // get the minimum corresponding SkyLine value
+            // FIXME: Change if Skyline is available
+            // const skyLineMinValue: number = skyBottomLineCalculator.getSkyLineMinInRange(staffLine, start, end);
+            const skyLineMinValue: number = 0;
+
+            if (measure === staffLine.Measures[0]) {
+                // must take into account possible MusicSystem Bracket's
+                let minBracketTopBorder: number = 0;
+                if (musicSystem.GroupBrackets.length > 0) {
+                    for (const groupBracket of musicSystem.GroupBrackets) {
+                        minBracketTopBorder = Math.min(minBracketTopBorder, groupBracket.PositionAndShape.BorderTop);
+                    }
+                }
+                relativeY = Math.min(skyLineMinValue, minBracketTopBorder);
+            } else {
+                relativeY = skyLineMinValue;
+            }
+
+            relativeY = Math.min(0, relativeY);
+
+            graphicalLabel.PositionAndShape.RelativePosition = new PointF2D(relativeX, relativeY);
+            // FIXME: Change if Skyline is available
+            // skyBottomLineCalculator.updateSkyLineInRange(staffLine, start, end, relativeY + graphicalLabel.PositionAndShape.BorderMarginTop);
+            musicSystem.MeasureNumberLabels.push(graphicalLabel);
+        }
 
     /**
      * Calculate the shape (Bézier curve) for this tie.

+ 17 - 0
src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts

@@ -192,6 +192,23 @@ export class VexFlowMeasure extends StaffMeasure {
         }
     }
 
+    /**
+     * Adds a measure number to the top left corner of the measure
+     * This method is not used currently in favor of the calculateMeasureNumberPlacement
+     * method in the MusicSheetCalculator.ts
+     */
+    public addMeasureNumber(): void {
+        const text: string = this.MeasureNumber.toString();
+        const position: number = Vex.Flow.StaveModifier.Position.ABOVE;
+        const options: any = {
+            justification: 1,
+            shift_x: 0,
+            shift_y: 0,
+          };
+
+        this.stave.setText(text, position, options);
+    }
+
     public addWordRepetition(repetitionInstruction: RepetitionInstructionEnum): void {
         let instruction: VexFlowRepetitionType = undefined;
         let position: any = Vex.Flow.Modifier.Position.END;

+ 5 - 9
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -28,11 +28,11 @@ import {Logging} from "../../../Common/Logging";
 import {unitInPixels} from "./VexFlowMusicSheetDrawer";
 import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
 import {TechnicalInstruction} from "../../VoiceData/Instructions/TechnicalInstruction";
-import { GraphicalLyricEntry } from "../GraphicalLyricEntry";
-import { GraphicalLabel } from "../GraphicalLabel";
-import { LyricsEntry } from "../../VoiceData/Lyrics/LyricsEntry";
-import { GraphicalLyricWord } from "../GraphicalLyricWord";
-import { VexFlowStaffEntry } from "./VexFlowStaffEntry";
+import {GraphicalLyricEntry} from "../GraphicalLyricEntry";
+import {GraphicalLabel} from "../GraphicalLabel";
+import {LyricsEntry} from "../../VoiceData/Lyrics/LyricsEntry";
+import {GraphicalLyricWord} from "../GraphicalLyricWord";
+import {VexFlowStaffEntry} from "./VexFlowStaffEntry";
 
 export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
   constructor() {
@@ -135,10 +135,6 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
     return;
   }
 
-  protected calculateMeasureNumberPlacement(musicSystem: MusicSystem): void {
-    return;
-  }
-
   protected staffMeasureCreatedCalculations(measure: StaffMeasure): void {
     (measure as VexFlowMeasure).staffMeasureCreatedCalculations();
   }