Explorar o código

feat(rendering): add osmd.Drawer.DrawOverlayLine, which allows the user to render colored lines on any MusicPage (#651)

fix #651
sschmid %!s(int64=5) %!d(string=hai) anos
pai
achega
6d8b9fc03e

+ 9 - 0
src/MusicalScore/Graphical/GraphicalMusicPage.ts

@@ -10,6 +10,7 @@ export class GraphicalMusicPage extends GraphicalObject {
     private musicSystems: MusicSystem[] = [];
     private labels: GraphicalLabel[] = [];
     private parent: GraphicalMusicSheet;
+    private pageNumber: number;
 
     constructor(parent: GraphicalMusicSheet) {
         super();
@@ -41,6 +42,14 @@ export class GraphicalMusicPage extends GraphicalObject {
         this.parent = value;
     }
 
+    public get PageNumber(): number {
+        return this.pageNumber;
+    }
+
+    public set PageNumber(value: number) {
+        this.pageNumber = value;
+    }
+
     /**
      * This method calculates the absolute Position of each GraphicalMusicPage according to a given placement
      * @param pageIndex

+ 5 - 0
src/MusicalScore/Graphical/GraphicalNote.ts

@@ -8,6 +8,7 @@ import {GraphicalObject} from "./GraphicalObject";
 import {MusicSheetCalculator} from "./MusicSheetCalculator";
 import {BoundingBox} from "./BoundingBox";
 import {GraphicalVoiceEntry} from "./GraphicalVoiceEntry";
+import {GraphicalMusicPage} from "./GraphicalMusicPage";
 
 /**
  * The graphical counterpart of a [[Note]]
@@ -57,4 +58,8 @@ export class GraphicalNote extends GraphicalObject {
       }
       return Math.min(3, num - 1);
     }
+
+    public get ParentMusicPage(): GraphicalMusicPage {
+      return this.parentVoiceEntry.parentStaffEntry.parentMeasure.parentMusicSystem.Parent;
+    }
 }

+ 1 - 1
src/MusicalScore/Graphical/MusicSheetDrawer.ts

@@ -396,7 +396,7 @@ export abstract class MusicSheetDrawer {
         this.drawLine(graphicalLine.Start, graphicalLine.End, colorOrStyle, lineWidth);
     }
 
-    public drawLine(start: PointF2D, stop: PointF2D, color: string = "#FF0000FF", lineWidth: number): void {
+    protected drawLine(start: PointF2D, stop: PointF2D, color: string = "#FF0000FF", lineWidth: number): void {
         // implemented by subclass (VexFlowMusicSheetDrawer)
     }
 

+ 1 - 0
src/MusicalScore/Graphical/MusicSystemBuilder.ts

@@ -950,6 +950,7 @@ export class MusicSystemBuilder {
     private createMusicPage(): GraphicalMusicPage {
         const page: GraphicalMusicPage = new GraphicalMusicPage(this.graphicalMusicSheet);
         this.graphicalMusicSheet.MusicPages.push(page);
+        page.PageNumber = this.graphicalMusicSheet.MusicPages.length; // caution: page number = page index + 1
         page.PositionAndShape.BorderLeft = 0.0;
         page.PositionAndShape.BorderRight = this.graphicalMusicSheet.ParentMusicSheet.pageWidth;
         page.PositionAndShape.BorderTop = 0.0;

+ 4 - 0
src/MusicalScore/Graphical/VexFlow/VexFlowBackend.ts

@@ -3,6 +3,7 @@ import {FontStyles} from "../../../Common/Enums/FontStyles";
 import {Fonts} from "../../../Common/Enums/Fonts";
 import {RectangleF2D} from "../../../Common/DataObjects/RectangleF2D";
 import {PointF2D} from "../../../Common/DataObjects/PointF2D";
+import {GraphicalMusicPage} from "..";
 
 export class VexFlowBackends {
   public static CANVAS: 0;
@@ -14,6 +15,9 @@ export class VexFlowBackends {
 
 export abstract class VexFlowBackend {
 
+  /** The GraphicalMusicPage the backend is drawing from. Each backend only renders one GraphicalMusicPage, to which the coordinates are relative. */
+  public graphicalMusicPage: GraphicalMusicPage;
+
   public abstract initialize(container: HTMLElement): void;
 
   public getInnerElement(): HTMLElement {

+ 29 - 2
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts

@@ -52,8 +52,9 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
 
     public drawSheet(graphicalMusicSheet: GraphicalMusicSheet): void {
         this.pageIdx = 0;
-        for (const {} of graphicalMusicSheet.MusicPages) {
+        for (const graphicalMusicPage of graphicalMusicSheet.MusicPages) {
             const backend: VexFlowBackend = this.backends[this.pageIdx];
+            backend.graphicalMusicPage = graphicalMusicPage;
             backend.scale(this.zoom);
             //backend.resize(graphicalMusicSheet.ParentMusicSheet.pageWidth * unitInPixels * this.zoom,
             //               EngravingRules.Rules.PageHeight * unitInPixels * this.zoom);
@@ -165,12 +166,38 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
     //     ctx.fillStyle = oldStyle;
     // }
 
-    public drawLine(start: PointF2D, stop: PointF2D, color: string = "#FF0000FF", lineWidth: number = 0.2): void {
+    /** Draws a line in the current backend. Only usable while pages are drawn sequentially, because backend reference is updated in that process.
+     *  To add your own lines after rendering, use DrawOverlayLine.
+     */
+    protected drawLine(start: PointF2D, stop: PointF2D, color: string = "#FF0000FF", lineWidth: number = 0.2): void {
+        // TODO maybe the backend should be given as an argument here as well, otherwise this can't be used after rendering of multiple pages is done.
         start = this.applyScreenTransformation(start);
         stop = this.applyScreenTransformation(stop);
+        /*if (!this.backend) {
+            this.backend = this.backends[0];
+        }*/
         this.backend.renderLine(start, stop, color, lineWidth * unitInPixels);
     }
 
+    /** Lets a user/developer draw an overlay line on the score. Use this instead of drawLine, which is for OSMD internally only.
+     *  The MusicPage has to be specified, because each page and Vexflow backend has its own relative coordinates.
+     *  (the AbsolutePosition of a GraphicalNote is relative to its backend)
+     *  To get a MusicPage, use GraphicalNote.ParentMusicPage.
+     */
+    public DrawOverlayLine(start: PointF2D, stop: PointF2D, musicPage: GraphicalMusicPage,
+                           color: string = "#FF0000FF", lineWidth: number = 0.2): void {
+        if (!musicPage.PageNumber || musicPage.PageNumber > this.backends.length || musicPage.PageNumber < 1) {
+            console.log("VexFlowMusicSheetDrawer.drawOverlayLine: invalid page number / music page number doesn't correspond to an existing backend.");
+            return;
+        }
+        const musicPageIndex: number = musicPage.PageNumber - 1;
+        const backendToUse: VexFlowBackend = this.backends[musicPageIndex];
+
+        start = this.applyScreenTransformation(start);
+        stop = this.applyScreenTransformation(stop);
+        backendToUse.renderLine(start, stop, color, lineWidth * unitInPixels);
+    }
+
     protected drawSkyLine(staffline: StaffLine): void {
         const startPosition: PointF2D = staffline.PositionAndShape.AbsolutePosition;
         const width: number = staffline.PositionAndShape.Size.width;