Browse Source

Improvement/bounding box draw (#198)

feat: added bounding boxes rectangles visualization for debug purposes
Benjamin Giesinger 7 years ago
parent
commit
55bfa9c571

+ 1 - 1
demo/index.js

@@ -135,7 +135,7 @@ import { OSMD } from '../src/OSMD/OSMD';
             var value = e.target.value;
             // clears the canvas element
             canvas.innerHTML = "";
-            osmdObj = new opensheetmusicdisplay.OSMD(canvas, false, value);
+            osmdObj = new OSMD(canvas, false, value);
             osmdObj.setLogLevel('info');
             selectOnChange();
 

+ 39 - 1
src/MusicalScore/Graphical/DrawingEnums.ts

@@ -1,3 +1,5 @@
+import * as Collections from "typescript-collections";
+
 /**
  * The supported styles to draw a rectangle on the music sheet
  */
@@ -37,13 +39,49 @@ export enum OutlineAndFillStyleEnum {
     Comment10
 }
 
+// tslint:disable-next-line:max-line-length A linebreak would be more confusing here
+export const OUTLINE_AND_FILL_STYLE_DICT: Collections.Dictionary<OutlineAndFillStyleEnum, string> = new Collections.Dictionary<OutlineAndFillStyleEnum, string>();
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.BaseWritingColor, "Thistle");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.FollowingCursor, "Aqua");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.AlternativeFollowingCursor, "Azure");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.PlaybackCursor, "Bisque");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Highlighted, "CadetBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.ErrorUnderlay, "DarkBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Selected, "DarkGoldenRod");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.SelectionSymbol, "BlanchedAlmond");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.DebugColor1, "Chartreuse");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.DebugColor2, "DarkGreen");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.DebugColor3, "DarkOrange");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.SplitScreenDivision, "FireBrick");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.GreyTransparentOverlay, "DarkSalmon");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea1, "DarkSeaGreen");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea2, "DarkOrchid");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea3, "Aquamarine");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea4, "DarkKhaki");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea5, "ForestGreen");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea6, "AliceBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea7, "DeepPink");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea8, "Coral");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea9, "DarkOliveGreen");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea10, "Chocolate");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment1, "DodgerBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment2, "Blue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment3, "Beige");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment4, "Crimson");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment5, "Fuchsia");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment6, "Brown");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment7, "BlanchedAlmond");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment8, "CornflowerBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment9, "Cornsilk");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment10, "DarkGrey");
+
 export enum StyleSets {
     MarkedArea,
     Comment
 }
 
 /**
- * The layers which one can draw on (not suppoerted)
+ * The layers which one can draw on (not supported)
  */
 export enum GraphicalLayers {
     Background,

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

@@ -201,7 +201,7 @@ export abstract class MusicSheetDrawer {
         // empty
     }
 
-    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number): void {
+    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number, alpha: number = 1): void {
         throw new Error("not implemented");
     }
 
@@ -407,6 +407,7 @@ export abstract class MusicSheetDrawer {
         if (!this.isVisible(page.PositionAndShape)) {
             return;
         }
+
         for (const system of page.MusicSystems) {
             if (this.isVisible(system.PositionAndShape)) {
                 this.drawMusicSystem(system);
@@ -417,6 +418,34 @@ export abstract class MusicSheetDrawer {
                 this.drawLabel(label, <number>GraphicalLayers.Notes);
             }
         }
+        // Draw bounding boxes for debug purposes. This has to be at the end because only
+        // then all the calculations and recalculations are done
+        if (process.env.DRAW_BOUNDING_BOX_ELEMENT) {
+            this.drawBoundingBoxes(page.PositionAndShape, 0, process.env.DRAW_BOUNDING_BOX_ELEMENT);
+        }
+
+    }
+
+    /**
+     * Draw bounding boxes aroung GraphicalObjects
+     * @param startBox Bounding Box that is used as a staring point to recursively go through all child elements
+     * @param layer Layer to draw to
+     * @param type Type of element to show bounding boxes for as string.
+     */
+    private drawBoundingBoxes(startBox: BoundingBox, layer: number = 0, type: string = "all"): void {
+        const dataObjectString: string = (startBox.DataObject.constructor as any).name;
+        if (startBox.BoundingRectangle !== undefined && (dataObjectString === type || type === "all")) {
+            const relBoundingRect: RectangleF2D = startBox.BoundingRectangle;
+            let tmpRect: RectangleF2D = new RectangleF2D(startBox.AbsolutePosition.x + startBox.BorderLeft,
+                                                         startBox.AbsolutePosition.y + startBox.BorderTop ,
+                                                         (relBoundingRect.width + 0), (relBoundingRect.height + 0));
+            tmpRect = this.applyScreenTransformationForRect(tmpRect);
+            this.renderRectangle(tmpRect, <number>GraphicalLayers.Background, layer, 0.5);
+            this.renderLabel(new GraphicalLabel(new Label(dataObjectString), 1.2, TextAlignment.CenterCenter),
+                             layer, tmpRect.width, tmpRect.height, tmpRect.height, new PointF2D(tmpRect.x, tmpRect.y + 12));
+        }
+        layer++;
+        startBox.ChildElements.forEach(bb => this.drawBoundingBoxes(bb, layer, type));
     }
 
     private drawMarkedAreas(system: MusicSystem): void {

+ 3 - 1
src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend.ts

@@ -52,11 +52,13 @@ export class CanvasVexFlowBackend extends VexFlowBackend {
         this.canvasRenderingCtx.fillText(text, screenPosition.x, screenPosition.y + heightInPixel);
         this.canvasRenderingCtx.font = old;
     }
-    public renderRectangle(rectangle: RectangleF2D, styleId: number): void {
+    public renderRectangle(rectangle: RectangleF2D, styleId: number, alpha: number = 1): void {
         const old: string | CanvasGradient | CanvasPattern = this.canvasRenderingCtx.fillStyle;
         this.canvasRenderingCtx.fillStyle = VexFlowConverter.style(styleId);
+        this.canvasRenderingCtx.globalAlpha = alpha;
         this.ctx.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
         this.canvasRenderingCtx.fillStyle = old;
+        this.canvasRenderingCtx.globalAlpha = 1;
     }
 
     private ctx: Vex.Flow.CanvasContext;

+ 6 - 1
src/MusicalScore/Graphical/VexFlow/SvgVexFlowBackend.ts

@@ -58,8 +58,13 @@ export class SvgVexFlowBackend extends VexFlowBackend {
         this.ctx.fillText(text, screenPosition.x, screenPosition.y + heightInPixel);
         this.ctx.restore();
     }
-    public renderRectangle(rectangle: RectangleF2D, styleId: number): void {
+    public renderRectangle(rectangle: RectangleF2D, styleId: number, alpha: number = 1): void {
+        this.ctx.save();
+        this.ctx.attributes.fill = VexFlowConverter.style(styleId);
+        this.ctx.attributes["fill-opacity"] = alpha;
         this.ctx.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+        this.ctx.restore();
+        this.ctx.attributes["fill-opacity"] = 1;
     }
 
     private ctx: Vex.Flow.SVGContext;

+ 9 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowBackend.ts

@@ -44,7 +44,15 @@ export abstract class VexFlowBackend {
   public abstract translate(x: number, y: number): void;
   public abstract renderText(fontHeight: number, fontStyle: FontStyles, font: Fonts, text: string,
                              heightInPixel: number, screenPosition: PointF2D): void;
-  public abstract renderRectangle(rectangle: RectangleF2D, styleId: number): void;
+  /**
+   * Renders a rectangle with the given style to the screen.
+   * It is given in screen coordinates.
+   * @param rectangle the rect in screen coordinates
+   * @param layer is the current rendering layer. There are many layers on top of each other to which can be rendered. Not needed for now.
+   * @param styleId the style id
+   * @param alpha alpha value between 0 and 1
+   */
+  public abstract renderRectangle(rectangle: RectangleF2D, styleId: number, alpha: number): void;
 
   public abstract getBackendType(): number;
 

+ 3 - 3
src/MusicalScore/Graphical/VexFlow/VexFlowConverter.ts

@@ -14,7 +14,7 @@ import {GraphicalNote} from "../GraphicalNote";
 import {SystemLinesEnum} from "../SystemLinesEnum";
 import {FontStyles} from "../../../Common/Enums/FontStyles";
 import {Fonts} from "../../../Common/Enums/Fonts";
-import {OutlineAndFillStyleEnum} from "../DrawingEnums";
+import {OutlineAndFillStyleEnum, OUTLINE_AND_FILL_STYLE_DICT} from "../DrawingEnums";
 import {Logging} from "../../../Common/Logging";
 
 /**
@@ -430,7 +430,7 @@ export class VexFlowConverter {
      * @returns {string}
      */
     public static style(styleId: OutlineAndFillStyleEnum): string {
-        // TODO To be implemented
-        return "lightgreen";
+        const ret: string = OUTLINE_AND_FILL_STYLE_DICT.getValue(styleId);
+        return ret;
     }
 }

+ 0 - 2
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -33,8 +33,6 @@ import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
 export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
     constructor() {
         super(new VexFlowGraphicalSymbolFactory());
-        let a: LyricsEntry = new LyricsEntry(undefined, undefined, undefined);
-        a = a;
         MusicSheetCalculator.TextMeasurer = new VexFlowTextMeasurer();
     }
 

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

@@ -117,9 +117,10 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
      * @param rectangle the rect in screen coordinates
      * @param layer is the current rendering layer. There are many layers on top of each other to which can be rendered. Not needed for now.
      * @param styleId the style id
+     * @param alpha alpha value between 0 and 1
      */
-    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number): void {
-       this.backend.renderRectangle(rectangle, styleId);
+    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number, alpha: number): void {
+       this.backend.renderRectangle(rectangle, styleId, alpha);
     }
 
     /**

+ 5 - 0
webpack.config.js

@@ -36,6 +36,11 @@ module.exports = {
       $: 'jquery',
       jQuery: 'jquery'
     }),
+    new webpack.EnvironmentPlugin({
+      NODE_ENV: 'development', // use 'development' unless process.env.NODE_ENV is defined
+      DEBUG: false,
+      DRAW_BOUNDING_BOX_ELEMENT: false, //  Specifies the element to draw bounding boxes for (e.g. 'GraphicalLabels'). If 'all', bounding boxes are drawn for all elements.
+    }),
     // FIXME: use environment variable to control uglify.
     // new webpack.optimize.UglifyJsPlugin({
     //     warnings: false,