Browse Source

feat(Options): add options interface for osmd constructor (#368)

changes OpenSheetMusicDisplay constructor to accept options object instead of individual parameters

* add Enum to DrawingParameters class, setter method that changes parameters depending on Enum

* refactor(tests): move createOSMD() to TestUtils

* refactor: DrawingParametersEnum with string values, docstrings

* fix(resize): fix OSMD.autoResize(), handleResize(), fix tests

fix render being called via autoResize() in OSMD constructor before sample loaded

fix load MXL from string test failing because it called autoResize()
which calls render(), despite options.autoResize set to false for all tests

* refactor(OSMD doc): OSMD docstrings more technical, add compact mode options

* refactor(DrawingParameters): add setForDefault method, drawHiddenNotes parameter

* OSMDOptions: add options for default notehead & stem color, drawHiddenNotes (not yet supported)

* add note color options (unsupported), refactor(OSMD): add enableOrDisableCursor(), setDrawingParameters()

* add options for credits (unsupported)
Simon 6 years ago
parent
commit
9da9cb4207

+ 12 - 4
demo/index.js

@@ -113,12 +113,17 @@ import { OpenSheetMusicDisplay } from '../src/OpenSheetMusicDisplay/OpenSheetMus
             openSheetMusicDisplay.DrawSkyLine = !openSheetMusicDisplay.DrawSkyLine;
             openSheetMusicDisplay.DrawSkyLine = !openSheetMusicDisplay.DrawSkyLine;
         }
         }
 
 
-        bottomlineDebug .onclick = function() {
+        bottomlineDebug.onclick = function() {
             openSheetMusicDisplay.DrawBottomLine = !openSheetMusicDisplay.DrawBottomLine;
             openSheetMusicDisplay.DrawBottomLine = !openSheetMusicDisplay.DrawBottomLine;
         }
         }
 
 
         // Create OSMD object and canvas
         // Create OSMD object and canvas
-        openSheetMusicDisplay = new OpenSheetMusicDisplay(canvas, false, backendSelect.value);
+        openSheetMusicDisplay = new OpenSheetMusicDisplay(canvas, {
+            autoResize: true,
+            backend: backendSelect.value,
+            drawingParameters: "default",
+            disableCursor: false,
+        });
         openSheetMusicDisplay.setLogLevel('info');
         openSheetMusicDisplay.setLogLevel('info');
         document.body.appendChild(canvas);
         document.body.appendChild(canvas);
 
 
@@ -163,7 +168,11 @@ import { OpenSheetMusicDisplay } from '../src/OpenSheetMusicDisplay/OpenSheetMus
             openSheetMusicDisplay.cursor.hide();
             openSheetMusicDisplay.cursor.hide();
         });
         });
         showCursorBtn.addEventListener("click", function() {
         showCursorBtn.addEventListener("click", function() {
-            openSheetMusicDisplay.cursor.show();
+            if (openSheetMusicDisplay.cursor) {
+                openSheetMusicDisplay.cursor.show();
+            } else {
+                console.info("Can't show cursor, as it was disabled (e.g. by drawingParameters).");
+            }
         });
         });
 
 
         backendSelect.addEventListener("change", function(e) {
         backendSelect.addEventListener("change", function(e) {
@@ -178,7 +187,6 @@ import { OpenSheetMusicDisplay } from '../src/OpenSheetMusicDisplay/OpenSheetMus
     }
     }
 
 
     function Resize(startCallback, endCallback) {
     function Resize(startCallback, endCallback) {
-
       var rtime;
       var rtime;
       var timeout = false;
       var timeout = false;
       var delta = 200;
       var delta = 200;

+ 1 - 1
karma.conf.js

@@ -81,7 +81,7 @@ module.exports = function (config) {
         client: {
         client: {
             captureConsole: true,
             captureConsole: true,
             mocha: {
             mocha: {
-                timeout: process.env.timeout || 2000
+                timeout: process.env.timeout || 6000
             }
             }
         },
         },
 
 

+ 65 - 0
src/MusicalScore/Graphical/DrawingParameters.ts

@@ -1,4 +1,15 @@
+export enum DrawingParametersEnum {
+    AllOn = "allon",
+    Compact = "compact",
+    Default = "default",
+    Leadsheet = "leadsheet",
+    Preview = "preview",
+    Thumbnail = "thumbnail",
+}
+
 export class DrawingParameters {
 export class DrawingParameters {
+    /** will set other settings if changed with set method */
+    private drawingParametersEnum: DrawingParametersEnum;
     public drawHighlights: boolean;
     public drawHighlights: boolean;
     public drawErrors: boolean;
     public drawErrors: boolean;
     public drawSelectionStartSymbol: boolean;
     public drawSelectionStartSymbol: boolean;
@@ -8,6 +19,43 @@ export class DrawingParameters {
     public drawScrollIndicator: boolean;
     public drawScrollIndicator: boolean;
     public drawComments: boolean;
     public drawComments: boolean;
     public drawMarkedAreas: boolean;
     public drawMarkedAreas: boolean;
+    public drawTitle: boolean = true;
+    public drawCredits: boolean = true;
+    public drawPartName: boolean = true;
+    /** Draw notes set to be invisible (print-object="no" in XML). */
+    public drawHiddenNotes: boolean = false;
+    public defaultColorNoteHead: string; // TODO not yet supported
+    public defaultColorStem: string; // TODO not yet supported
+
+    constructor(drawingParameters: DrawingParametersEnum = DrawingParametersEnum.Default) {
+        this.DrawingParametersEnum = drawingParameters;
+    }
+
+    /** Sets drawing parameters enum and changes settings flags accordingly. */
+    public set DrawingParametersEnum(drawingParametersEnum: DrawingParametersEnum) {
+        this.drawingParametersEnum = drawingParametersEnum;
+        switch (drawingParametersEnum) {
+            case DrawingParametersEnum.AllOn:
+                this.setForAllOn();
+                break;
+            case DrawingParametersEnum.Thumbnail:
+                this.setForThumbnail();
+                break;
+            case DrawingParametersEnum.Leadsheet:
+                this.setForLeadsheet();
+                break;
+            case DrawingParametersEnum.Compact:
+                this.setForCompactMode();
+                break;
+            case DrawingParametersEnum.Default:
+            default:
+                this.setForDefault();
+        }
+    }
+
+    public get DrawingParametersEnum(): DrawingParametersEnum {
+        return this.drawingParametersEnum;
+    }
 
 
     public setForAllOn(): void {
     public setForAllOn(): void {
         this.drawHighlights = true;
         this.drawHighlights = true;
@@ -19,6 +67,15 @@ export class DrawingParameters {
         this.drawScrollIndicator = true;
         this.drawScrollIndicator = true;
         this.drawComments = true;
         this.drawComments = true;
         this.drawMarkedAreas = true;
         this.drawMarkedAreas = true;
+        this.drawTitle = true;
+        this.drawCredits = true;
+        this.drawPartName = true;
+        this.drawHiddenNotes = true;
+    }
+
+    public setForDefault(): void {
+        this.setForAllOn();
+        this.drawHiddenNotes = false;
     }
     }
 
 
     public setForThumbnail(): void {
     public setForThumbnail(): void {
@@ -31,6 +88,14 @@ export class DrawingParameters {
         this.drawScrollIndicator = false;
         this.drawScrollIndicator = false;
         this.drawComments = true;
         this.drawComments = true;
         this.drawMarkedAreas = true;
         this.drawMarkedAreas = true;
+        this.drawHiddenNotes = false;
+    }
+
+    public setForCompactMode(): void {
+        this.drawTitle = false;
+        this.drawCredits = false;
+        this.drawPartName = false;
+        this.drawHiddenNotes = false;
     }
     }
 
 
     public setForLeadsheet(): void {
     public setForLeadsheet(): void {

+ 2 - 6
src/MusicalScore/Graphical/MusicSheetDrawer.ts

@@ -52,14 +52,10 @@ export abstract class MusicSheetDrawer {
     private phonicScoreMode: PhonicScoreModes = PhonicScoreModes.Manual;
     private phonicScoreMode: PhonicScoreModes = PhonicScoreModes.Manual;
 
 
     constructor(textMeasurer: ITextMeasurer,
     constructor(textMeasurer: ITextMeasurer,
-                isPreviewImageDrawer: boolean = false) {
+                drawingParameters: DrawingParameters) {
         this.textMeasurer = textMeasurer;
         this.textMeasurer = textMeasurer;
         this.splitScreenLineColor = -1;
         this.splitScreenLineColor = -1;
-        if (isPreviewImageDrawer) {
-            this.drawingParameters.setForThumbnail();
-        } else {
-            this.drawingParameters.setForAllOn();
-        }
+        this.drawingParameters = drawingParameters;
     }
     }
 
 
     public set Mode(value: PhonicScoreModes) {
     public set Mode(value: PhonicScoreModes) {

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

@@ -23,6 +23,7 @@ import { PlacementEnum } from "../../VoiceData/Expressions/AbstractExpression";
 import {GraphicalInstantaneousTempoExpression} from "../GraphicalInstantaneousTempoExpression";
 import {GraphicalInstantaneousTempoExpression} from "../GraphicalInstantaneousTempoExpression";
 import {GraphicalInstantaneousDynamicExpression} from "../GraphicalInstantaneousDynamicExpression";
 import {GraphicalInstantaneousDynamicExpression} from "../GraphicalInstantaneousDynamicExpression";
 import log = require("loglevel");
 import log = require("loglevel");
+import {DrawingParameters} from "../DrawingParameters";
 
 
 /**
 /**
  * This is a global constant which denotes the height in pixels of the space between two lines of the stave
  * This is a global constant which denotes the height in pixels of the space between two lines of the stave
@@ -37,8 +38,8 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
 
 
     constructor(element: HTMLElement,
     constructor(element: HTMLElement,
                 backend: VexFlowBackend,
                 backend: VexFlowBackend,
-                isPreviewImageDrawer: boolean = false) {
-        super(new VexFlowTextMeasurer(), isPreviewImageDrawer);
+                drawingParameters: DrawingParameters = new DrawingParameters()) {
+        super(new VexFlowTextMeasurer(), drawingParameters);
         this.backend = backend;
         this.backend = backend;
     }
     }
 
 

+ 1 - 3
src/OpenSheetMusicDisplay/Cursor.ts

@@ -28,6 +28,7 @@ export class Cursor {
   private hidden: boolean = true;
   private hidden: boolean = true;
   private cursorElement: HTMLImageElement;
   private cursorElement: HTMLImageElement;
 
 
+  /** Initialize the cursor. Necessary before using functions like show() and next(). */
   public init(manager: MusicPartManager, graphic: GraphicalMusicSheet): void {
   public init(manager: MusicPartManager, graphic: GraphicalMusicSheet): void {
     this.manager = manager;
     this.manager = manager;
     this.reset();
     this.reset();
@@ -42,9 +43,6 @@ export class Cursor {
   public show(): void {
   public show(): void {
     this.hidden = false;
     this.hidden = false;
     this.update();
     this.update();
-    // Forcing the sheet to re-render is not necessary anymore,
-    // since the cursor is an HTML element.
-    // this.openSheetMusicDisplay.render();
   }
   }
 
 
   private getStaffEntriesFromVoiceEntry(voiceEntry: VoiceEntry): VexFlowStaffEntry {
   private getStaffEntriesFromVoiceEntry(voiceEntry: VoiceEntry): VexFlowStaffEntry {

+ 43 - 0
src/OpenSheetMusicDisplay/OSMDOptions.ts

@@ -0,0 +1,43 @@
+import { DrawingParametersEnum } from "../MusicalScore/Graphical/DrawingParameters";
+
+/** Possible options for the OpenSheetMusicDisplay constructor, none are mandatory. */
+export interface IOSMDOptions {
+    /** Not yet supported. Will always beam automatically. */ // TODO
+    autoBeam?: boolean;
+    /** Automatically resize score with canvas size. Default is true. */
+    autoResize?: boolean;
+    /** Not yet supported. Will always place stems automatically. */ // TODO
+    autoStem?: boolean;
+    /** Render Backend, will be SVG if given undefined, SVG or svg, otherwise Canvas. */
+    backend?: string;
+    /** Don't show/load cursor. Will override disableCursor in drawingParameters. */
+    disableCursor?: boolean;
+    /** Parameters like drawing a Leadsheet or (Thumbnail) Preview, disabling Cursor. */
+    drawingParameters?: string | DrawingParametersEnum;
+    /** Whether to draw hidden/invisible notes (print-object="no" in XML). Default false. Not yet supported. */ // TODO
+    drawHiddenNotes?: boolean;
+    /** Default color for a note head (without stem). Default black. Not yet supported. */ // TODO
+    defaultColorNoteHead?: string;
+    /** Default color for a note stem. Default black. Not yet supported. */ // TODO
+    defaultColorStem?: string;
+    /** Whether to draw the title of the piece. Not yet supported. */ // TODO
+    drawTitle?: boolean;
+    /** Whether to draw credits (title, composer, arranger, copyright etc., see <credit>. Not yet supported. */ // TODO
+    drawCredits?: boolean;
+    /** Whether to draw part (instrument) names. Not yet supported. */ // TODO
+    drawPartName?: boolean;
+}
+
+/** Handles [[IOSMDOptions]], e.g. returning default options with OSMDOptionsStandard() */
+export class OSMDOptions {
+    /** Returns the default options for OSMD.
+     * These are e.g. used if no options are given in the [[OpenSheetMusicDisplay]] constructor.
+     */
+    public static OSMDOptionsStandard(): IOSMDOptions {
+        return {
+            autoResize: true,
+            backend: "svg",
+            drawingParameters: DrawingParametersEnum.Default,
+        };
+    }
+}

+ 97 - 24
src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts

@@ -13,14 +13,26 @@ import {MXLHelper} from "../Common/FileIO/Mxl";
 import {Promise} from "es6-promise";
 import {Promise} from "es6-promise";
 import {AJAX} from "./AJAX";
 import {AJAX} from "./AJAX";
 import * as log from "loglevel";
 import * as log from "loglevel";
+import {DrawingParametersEnum, DrawingParameters} from "../MusicalScore/Graphical/DrawingParameters";
+import {IOSMDOptions, OSMDOptions} from "./OSMDOptions";
 
 
+/**
+ * The main class and control point of OpenSheetMusicDisplay.<br>
+ * It can display MusicXML sheet music files in an HTML element container.<br>
+ * After the constructor, use load() and render() to load and render a MusicXML file.
+ */
 export class OpenSheetMusicDisplay {
 export class OpenSheetMusicDisplay {
     /**
     /**
-     * The easy way of displaying a MusicXML sheet music file
-     * @param container is either the ID, or the actual "div" element which will host the music sheet
-     * @autoResize automatically resize the sheet to full page width on window resize
+     * Creates and attaches an OpenSheetMusicDisplay object to an HTML element container.<br>
+     * After the constructor, use load() and render() to load and render a MusicXML file.
+     * @param container The container element OSMD will be rendered into.<br>
+     *                  Either a string specifying the ID of an HTML container element,<br>
+     *                  or a reference to the HTML element itself (e.g. div)
+     * @param options An object for rendering options like the backend (svg/canvas) or autoResize.<br>
+     *                For defaults see the OSMDOptionsStandard method in the [[OSMDOptions]] class.
      */
      */
-    constructor(container: string|HTMLElement, autoResize: boolean = false, backend: string = "svg") {
+    constructor(container: string|HTMLElement,
+                options: IOSMDOptions = OSMDOptions.OSMDOptionsStandard()) {
         // Store container element
         // Store container element
         if (typeof container === "string") {
         if (typeof container === "string") {
             // ID passed
             // ID passed
@@ -33,22 +45,23 @@ export class OpenSheetMusicDisplay {
             throw new Error("Please pass a valid div container to OpenSheetMusicDisplay");
             throw new Error("Please pass a valid div container to OpenSheetMusicDisplay");
         }
         }
 
 
-        if (backend === "svg") {
+        if (options.backend === undefined || options.backend.toLowerCase() === "svg") {
             this.backend = new SvgVexFlowBackend();
             this.backend = new SvgVexFlowBackend();
         } else {
         } else {
             this.backend = new CanvasVexFlowBackend();
             this.backend = new CanvasVexFlowBackend();
         }
         }
 
 
+        this.setDrawingParameters(options);
+
         this.backend.initialize(this.container);
         this.backend.initialize(this.container);
         this.canvas = this.backend.getCanvas();
         this.canvas = this.backend.getCanvas();
-        const inner: HTMLElement = this.backend.getInnerElement();
+        this.innerElement = this.backend.getInnerElement();
+        this.enableOrDisableCursor(this.drawingParameters.drawCursors);
 
 
         // Create the drawer
         // Create the drawer
-        this.drawer = new VexFlowMusicSheetDrawer(this.canvas, this.backend, false);
-        // Create the cursor
-        this.cursor = new Cursor(inner, this);
+        this.drawer = new VexFlowMusicSheetDrawer(this.canvas, this.backend, this.drawingParameters);
 
 
-        if (autoResize) {
+        if (options.autoResize) {
             this.autoResize();
             this.autoResize();
         }
         }
     }
     }
@@ -59,9 +72,11 @@ export class OpenSheetMusicDisplay {
     private container: HTMLElement;
     private container: HTMLElement;
     private canvas: HTMLElement;
     private canvas: HTMLElement;
     private backend: VexFlowBackend;
     private backend: VexFlowBackend;
+    private innerElement: HTMLElement;
     private sheet: MusicSheet;
     private sheet: MusicSheet;
     private drawer: VexFlowMusicSheetDrawer;
     private drawer: VexFlowMusicSheetDrawer;
     private graphic: GraphicalMusicSheet;
     private graphic: GraphicalMusicSheet;
+    private drawingParameters: DrawingParameters;
 
 
     /**
     /**
      * Load a MusicXML file
      * Load a MusicXML file
@@ -124,7 +139,9 @@ export class OpenSheetMusicDisplay {
         const reader: MusicSheetReader = new MusicSheetReader();
         const reader: MusicSheetReader = new MusicSheetReader();
         this.sheet = reader.createMusicSheet(score, "Unknown path");
         this.sheet = reader.createMusicSheet(score, "Unknown path");
         this.graphic = new GraphicalMusicSheet(this.sheet, calc);
         this.graphic = new GraphicalMusicSheet(this.sheet, calc);
-        this.cursor.init(this.sheet.MusicPartManager, this.graphic);
+        if (this.drawingParameters.drawCursors) {
+            this.cursor.init(this.sheet.MusicPartManager, this.graphic);
+        }
         log.info(`Loaded sheet ${this.sheet.TitleString} successfully.`);
         log.info(`Loaded sheet ${this.sheet.TitleString} successfully.`);
         return Promise.resolve({});
         return Promise.resolve({});
     }
     }
@@ -147,15 +164,9 @@ export class OpenSheetMusicDisplay {
         this.sheet.pageWidth = width / this.zoom / 10.0;
         this.sheet.pageWidth = width / this.zoom / 10.0;
         // Calculate again
         // Calculate again
         this.graphic.reCalculate();
         this.graphic.reCalculate();
-        this.graphic.Cursors.length = 0;
-        /*this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(0, 4), OutlineAndFillStyleEnum.PlaybackCursor));
-        this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(1, 4), OutlineAndFillStyleEnum.PlaybackCursor));
-        this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(2, 4), OutlineAndFillStyleEnum.PlaybackCursor));
-        this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(3, 4), OutlineAndFillStyleEnum.PlaybackCursor));
-        this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(4, 4), OutlineAndFillStyleEnum.PlaybackCursor));
-        this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(5, 4), OutlineAndFillStyleEnum.PlaybackCursor));
-        this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(6, 4), OutlineAndFillStyleEnum.PlaybackCursor));
-        this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(7, 4), OutlineAndFillStyleEnum.PlaybackCursor));*/
+        if (this.drawingParameters.drawCursors) {
+            this.graphic.Cursors.length = 0;
+        }
         // Update Sheet Page
         // Update Sheet Page
         const height: number = this.graphic.MusicPages[0].PositionAndShape.BorderBottom * 10.0 * this.zoom;
         const height: number = this.graphic.MusicPages[0].PositionAndShape.BorderBottom * 10.0 * this.zoom;
         this.drawer.clear();
         this.drawer.clear();
@@ -163,8 +174,10 @@ export class OpenSheetMusicDisplay {
         this.drawer.scale(this.zoom);
         this.drawer.scale(this.zoom);
         // Finally, draw
         // Finally, draw
         this.drawer.drawSheet(this.graphic);
         this.drawer.drawSheet(this.graphic);
-        // Update the cursor position
-        this.cursor.update();
+        if (this.drawingParameters.drawCursors) {
+            // Update the cursor position
+            this.cursor.update();
+        }
     }
     }
 
 
     /**
     /**
@@ -201,7 +214,9 @@ export class OpenSheetMusicDisplay {
      * FIXME: Probably unnecessary
      * FIXME: Probably unnecessary
      */
      */
     private reset(): void {
     private reset(): void {
-        this.cursor.hide();
+        if (this.drawingParameters.drawCursors) {
+            this.cursor.hide();
+        }
         this.sheet = undefined;
         this.sheet = undefined;
         this.graphic = undefined;
         this.graphic = undefined;
         this.zoom = 1.0;
         this.zoom = 1.0;
@@ -213,6 +228,7 @@ export class OpenSheetMusicDisplay {
      * Attach the appropriate handler to the window.onResize event
      * Attach the appropriate handler to the window.onResize event
      */
      */
     private autoResize(): void {
     private autoResize(): void {
+
         const self: OpenSheetMusicDisplay = this;
         const self: OpenSheetMusicDisplay = this;
         this.handleResize(
         this.handleResize(
             () => {
             () => {
@@ -229,7 +245,9 @@ export class OpenSheetMusicDisplay {
                 //    document.documentElement.offsetWidth
                 //    document.documentElement.offsetWidth
                 //);
                 //);
                 //self.container.style.width = width + "px";
                 //self.container.style.width = width + "px";
-                self.render();
+                if (this.graphic !== undefined) {
+                    self.render();
+                }
             }
             }
         );
         );
     }
     }
@@ -240,6 +258,9 @@ export class OpenSheetMusicDisplay {
      * @param endCallback is the function called when resizing (kind-of) ends
      * @param endCallback is the function called when resizing (kind-of) ends
      */
      */
     private handleResize(startCallback: () => void, endCallback: () => void): void {
     private handleResize(startCallback: () => void, endCallback: () => void): void {
+        if (this.graphic === undefined) {
+            return;
+        }
         let rtime: number;
         let rtime: number;
         let timeout: number = undefined;
         let timeout: number = undefined;
         const delta: number = 200;
         const delta: number = 200;
@@ -274,7 +295,59 @@ export class OpenSheetMusicDisplay {
         window.setTimeout(endCallback, 1);
         window.setTimeout(endCallback, 1);
     }
     }
 
 
+    /** Enable or disable (hide) the cursor.
+     * @param enable whether to enable (true) or disable (false) the cursor
+     */
+    public enableOrDisableCursor(enable: boolean): void {
+        this.drawingParameters.drawCursors = enable;
+        if (enable) {
+            if (!this.cursor) {
+                this.cursor = new Cursor(this.innerElement, this);
+                if (this.sheet && this.graphic) { // else init is called in load()
+                    this.cursor.init(this.sheet.MusicPartManager, this.graphic);
+                }
+            }
+        } else { // disable cursor
+            if (!this.cursor) {
+                return;
+            }
+            this.cursor.hide();
+            // this.cursor = undefined;
+            // TODO cursor should be disabled, not just hidden. otherwise user can just call osmd.cursor.hide().
+            // however, this could cause null calls (cursor.next() etc), maybe that needs some solution.
+        }
+    }
+
     //#region GETTER / SETTER
     //#region GETTER / SETTER
+    private setDrawingParameters(options: IOSMDOptions): void {
+        this.drawingParameters = new DrawingParameters();
+        if (options.drawingParameters) {
+            this.drawingParameters.DrawingParametersEnum = DrawingParametersEnum[options.drawingParameters];
+        }
+        // individual drawing parameters options
+        if (options.disableCursor) {
+            this.drawingParameters.drawCursors = false;
+        }
+        if (options.drawHiddenNotes) {
+            this.drawingParameters.drawHiddenNotes = true;
+        }
+        if (options.drawTitle !== undefined) {
+            this.drawingParameters.drawTitle = options.drawTitle;
+        }
+        if (options.drawPartName !== undefined) {
+            this.drawingParameters.drawPartName = options.drawPartName;
+        }
+        if (options.drawCredits !== undefined) {
+            this.drawingParameters.drawCredits = options.drawCredits;
+        }
+        if (options.defaultColorNoteHead) {
+            this.drawingParameters.defaultColorNoteHead = options.defaultColorNoteHead;
+        }
+        if (options.defaultColorStem) {
+            this.drawingParameters.defaultColorStem = options.defaultColorStem;
+        }
+    }
+
     public set DrawSkyLine(value: boolean) {
     public set DrawSkyLine(value: boolean) {
         if (this.drawer) {
         if (this.drawer) {
             this.drawer.skyLineVisible = value;
             this.drawer.skyLineVisible = value;

+ 2 - 1
test/Common/FileIO/Xml_Test.ts

@@ -48,7 +48,8 @@ describe("XML interface", () => {
             // Load the xml file content
             // Load the xml file content
             const score: Document = TestUtils.getScore(scoreName);
             const score: Document = TestUtils.getScore(scoreName);
             const div: HTMLElement = document.createElement("div");
             const div: HTMLElement = document.createElement("div");
-            const openSheetMusicDisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+            const openSheetMusicDisplay: OpenSheetMusicDisplay =
+                TestUtils.createOpenSheetMusicDisplay(div);
             openSheetMusicDisplay.load(score);
             openSheetMusicDisplay.load(score);
             done();
             done();
         }).timeout(3000);
         }).timeout(3000);

+ 11 - 12
test/Common/OSMD/OSMD_Test.ts

@@ -2,7 +2,6 @@ import chai = require("chai");
 import {OpenSheetMusicDisplay} from "../../../src/OpenSheetMusicDisplay/OpenSheetMusicDisplay";
 import {OpenSheetMusicDisplay} from "../../../src/OpenSheetMusicDisplay/OpenSheetMusicDisplay";
 import {TestUtils} from "../../Util/TestUtils";
 import {TestUtils} from "../../Util/TestUtils";
 
 
-
 describe("OpenSheetMusicDisplay Main Export", () => {
 describe("OpenSheetMusicDisplay Main Export", () => {
     let container1: HTMLElement;
     let container1: HTMLElement;
 
 
@@ -24,7 +23,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
     it("load MXL from string", (done: MochaDone) => {
     it("load MXL from string", (done: MochaDone) => {
         const mxl: string = TestUtils.getMXL("Mozart_Clarinet_Quintet_Excerpt.mxl");
         const mxl: string = TestUtils.getMXL("Mozart_Clarinet_Quintet_Excerpt.mxl");
         const div: HTMLElement = TestUtils.getDivElement(document);
         const div: HTMLElement = TestUtils.getDivElement(document);
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         opensheetmusicdisplay.load(mxl).then(
         opensheetmusicdisplay.load(mxl).then(
             (_: {}) => {
             (_: {}) => {
                 opensheetmusicdisplay.render();
                 opensheetmusicdisplay.render();
@@ -37,7 +36,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
     it("load invalid MXL from string", (done: MochaDone) => {
     it("load invalid MXL from string", (done: MochaDone) => {
         const mxl: string = "\x50\x4b\x03\x04";
         const mxl: string = "\x50\x4b\x03\x04";
         const div: HTMLElement = TestUtils.getDivElement(document);
         const div: HTMLElement = TestUtils.getDivElement(document);
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         opensheetmusicdisplay.load(mxl).then(
         opensheetmusicdisplay.load(mxl).then(
             (_: {}) => {
             (_: {}) => {
                 done(new Error("Corrupted MXL appears to be loaded correctly"));
                 done(new Error("Corrupted MXL appears to be loaded correctly"));
@@ -56,7 +55,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
         const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         const xml: string = new XMLSerializer().serializeToString(score);
         const xml: string = new XMLSerializer().serializeToString(score);
         const div: HTMLElement = TestUtils.getDivElement(document);
         const div: HTMLElement = TestUtils.getDivElement(document);
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         opensheetmusicdisplay.load(xml).then(
         opensheetmusicdisplay.load(xml).then(
             (_: {}) => {
             (_: {}) => {
                 opensheetmusicdisplay.render();
                 opensheetmusicdisplay.render();
@@ -69,7 +68,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
     it("load XML Document", (done: MochaDone) => {
     it("load XML Document", (done: MochaDone) => {
         const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         const div: HTMLElement = TestUtils.getDivElement(document);
         const div: HTMLElement = TestUtils.getDivElement(document);
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         opensheetmusicdisplay.load(score).then(
         opensheetmusicdisplay.load(score).then(
             (_: {}) => {
             (_: {}) => {
                 opensheetmusicdisplay.render();
                 opensheetmusicdisplay.render();
@@ -82,7 +81,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
     it("load MXL Document by URL", (done: MochaDone) => {
     it("load MXL Document by URL", (done: MochaDone) => {
         const url: string = "base/test/data/Mozart_Clarinet_Quintet_Excerpt.mxl";
         const url: string = "base/test/data/Mozart_Clarinet_Quintet_Excerpt.mxl";
         const div: HTMLElement = TestUtils.getDivElement(document);
         const div: HTMLElement = TestUtils.getDivElement(document);
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         opensheetmusicdisplay.load(url).then(
         opensheetmusicdisplay.load(url).then(
             (_: {}) => {
             (_: {}) => {
                 opensheetmusicdisplay.render();
                 opensheetmusicdisplay.render();
@@ -95,7 +94,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
     it("load something invalid by URL", (done: MochaDone) => {
     it("load something invalid by URL", (done: MochaDone) => {
         const url: string = "https://www.google.com";
         const url: string = "https://www.google.com";
         const div: HTMLElement = TestUtils.getDivElement(document);
         const div: HTMLElement = TestUtils.getDivElement(document);
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         opensheetmusicdisplay.load(url).then(
         opensheetmusicdisplay.load(url).then(
             (_: {}) => {
             (_: {}) => {
                 done(new Error("Invalid URL appears to be loaded correctly"));
                 done(new Error("Invalid URL appears to be loaded correctly"));
@@ -113,7 +112,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
     it("load invalid URL", (done: MochaDone) => {
     it("load invalid URL", (done: MochaDone) => {
         const url: string = "https://www.afjkhfjkauu2ui3z2uiu.com";
         const url: string = "https://www.afjkhfjkauu2ui3z2uiu.com";
         const div: HTMLElement = TestUtils.getDivElement(document);
         const div: HTMLElement = TestUtils.getDivElement(document);
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         opensheetmusicdisplay.load(url).then(
         opensheetmusicdisplay.load(url).then(
             (_: {}) => {
             (_: {}) => {
                 done(new Error("Invalid URL appears to be loaded correctly"));
                 done(new Error("Invalid URL appears to be loaded correctly"));
@@ -131,7 +130,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
     it("load invalid XML string", (done: MochaDone) => {
     it("load invalid XML string", (done: MochaDone) => {
         const xml: string = "<?xml";
         const xml: string = "<?xml";
         const div: HTMLElement = TestUtils.getDivElement(document);
         const div: HTMLElement = TestUtils.getDivElement(document);
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         opensheetmusicdisplay.load(xml).then(
         opensheetmusicdisplay.load(xml).then(
             (_: {}) => {
             (_: {}) => {
                 done(new Error("Corrupted XML appears to be loaded correctly"));
                 done(new Error("Corrupted XML appears to be loaded correctly"));
@@ -148,7 +147,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
 
 
     it("render without loading", (done: MochaDone) => {
     it("render without loading", (done: MochaDone) => {
         const div: HTMLElement = TestUtils.getDivElement(document);
         const div: HTMLElement = TestUtils.getDivElement(document);
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         chai.expect(() => {
         chai.expect(() => {
             return opensheetmusicdisplay.render();
             return opensheetmusicdisplay.render();
         }).to.throw(/load/);
         }).to.throw(/load/);
@@ -167,7 +166,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
     it("test width 500", (done: MochaDone) => {
     it("test width 500", (done: MochaDone) => {
         const div: HTMLElement = container1;
         const div: HTMLElement = container1;
         div.style.width = "500px";
         div.style.width = "500px";
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         opensheetmusicdisplay.load(score).then(
         opensheetmusicdisplay.load(score).then(
             (_: {}) => {
             (_: {}) => {
@@ -182,7 +181,7 @@ describe("OpenSheetMusicDisplay Main Export", () => {
     it("test width 200", (done: MochaDone) => {
     it("test width 200", (done: MochaDone) => {
         const div: HTMLElement = container1;
         const div: HTMLElement = container1;
         div.style.width = "200px";
         div.style.width = "200px";
-        const opensheetmusicdisplay: OpenSheetMusicDisplay = new OpenSheetMusicDisplay(div);
+        const opensheetmusicdisplay: OpenSheetMusicDisplay = TestUtils.createOpenSheetMusicDisplay(div);
         const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         opensheetmusicdisplay.load(score).then(
         opensheetmusicdisplay.load(score).then(
             (_: {}) => {
             (_: {}) => {

+ 2 - 1
test/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer_Test.ts

@@ -9,6 +9,7 @@ import {IXmlElement} from "../../../../src/Common/FileIO/Xml";
 import {Fraction} from "../../../../src/Common/DataObjects/Fraction";
 import {Fraction} from "../../../../src/Common/DataObjects/Fraction";
 import {VexFlowBackend} from "../../../../src/MusicalScore/Graphical/VexFlow/VexFlowBackend";
 import {VexFlowBackend} from "../../../../src/MusicalScore/Graphical/VexFlow/VexFlowBackend";
 import {CanvasVexFlowBackend} from "../../../../src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend";
 import {CanvasVexFlowBackend} from "../../../../src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend";
+import {DrawingParameters} from "../../../../src/MusicalScore/Graphical/DrawingParameters";
 
 
 /* tslint:disable:no-unused-expression */
 /* tslint:disable:no-unused-expression */
 describe("VexFlow Music Sheet Drawer", () => {
 describe("VexFlow Music Sheet Drawer", () => {
@@ -47,7 +48,7 @@ describe("VexFlow Music Sheet Drawer", () => {
         const canvas: HTMLCanvasElement = document.createElement("canvas");
         const canvas: HTMLCanvasElement = document.createElement("canvas");
         const backend: VexFlowBackend = new CanvasVexFlowBackend();
         const backend: VexFlowBackend = new CanvasVexFlowBackend();
         backend.initialize(canvas);
         backend.initialize(canvas);
-        const drawer: VexFlowMusicSheetDrawer = new VexFlowMusicSheetDrawer(canvas, backend);
+        const drawer: VexFlowMusicSheetDrawer = new VexFlowMusicSheetDrawer(canvas, backend, new DrawingParameters());
         drawer.drawSheet(gms);
         drawer.drawSheet(gms);
         done();
         done();
     });
     });

+ 5 - 0
test/Util/TestUtils.ts

@@ -1,3 +1,5 @@
+import { OpenSheetMusicDisplay } from "../../src/OpenSheetMusicDisplay/OpenSheetMusicDisplay";
+
 /**
 /**
  * This class collects useful methods to interact with test data.
  * This class collects useful methods to interact with test data.
  * During tests, XML and MXL documents are preprocessed by karma,
  * During tests, XML and MXL documents are preprocessed by karma,
@@ -37,4 +39,7 @@ export class TestUtils {
         }
         }
     }
     }
 
 
+    public static createOpenSheetMusicDisplay(div: HTMLElement): OpenSheetMusicDisplay {
+        return new OpenSheetMusicDisplay(div);
+    }
 }
 }

+ 1 - 1
webpack.prod.js

@@ -35,6 +35,6 @@ module.exports = merge(common, {
             path: path.resolve(__dirname, 'build'),
             path: path.resolve(__dirname, 'build'),
             filename: './statistics.html'
             filename: './statistics.html'
         }),
         }),
-        new Cleaner(pathsToClean, {verbose: true, dry: false})
+        new Cleaner(pathsToClean, { verbose: true, dry: false })
     ]
     ]
 })
 })