Bläddra i källkod

Resize & Zoom (but problems with reRender)

Andrea Condoluci 9 år sedan
förälder
incheckning
64de97b9e9

+ 1 - 1
external/vexflow/vexflow.d.ts

@@ -119,7 +119,7 @@ declare namespace Vex {
     }
 
     export class CanvasContext {
-
+      public scale(x: number, y: number): CanvasContext;
     }
 
     export class StaveConnector {

+ 32 - 11
src/MusicSheetAPI.ts

@@ -1,4 +1,4 @@
-import {MusicSheetDrawer} from "./MusicalScore/Graphical/MusicSheetDrawer";
+import Vex = require("vexflow");
 import {IXmlElement} from "./Common/FileIO/Xml";
 import {VexFlowMusicSheetCalculator} from "./MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator";
 import {MusicSheetReader} from "./MusicalScore/ScoreIO/MusicSheetReader";
@@ -6,6 +6,7 @@ import {GraphicalMusicSheet} from "./MusicalScore/Graphical/GraphicalMusicSheet"
 import {MusicSheetCalculator} from "./MusicalScore/Graphical/MusicSheetCalculator";
 import {VexFlowMusicSheetDrawer} from "./MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer";
 import {MusicSheet} from "./MusicalScore/MusicSheet";
+import {VexFlowTextMeasurer} from "./MusicalScore/Graphical/VexFlow/VexFlowTextMeasurer";
 
 export class MusicSheetAPI {
     constructor() {
@@ -14,39 +15,59 @@ export class MusicSheetAPI {
 
     private canvas: HTMLCanvasElement;
     private sheet: MusicSheet;
-    private drawer: MusicSheetDrawer;
-    private calc: MusicSheetCalculator;
+    private drawer: VexFlowMusicSheetDrawer;
+    private graphic: GraphicalMusicSheet;
     private width: number;
+    private zoom: number = 1.0;
+    private unit: number = 10;
 
     public load(sheet: Element): void {
         let score: IXmlElement = new IXmlElement(sheet.getElementsByTagName("score-partwise")[0]);
-        this.calc = new VexFlowMusicSheetCalculator();
+        let calc: MusicSheetCalculator = new VexFlowMusicSheetCalculator();
         let reader: MusicSheetReader = new MusicSheetReader();
         this.sheet = reader.createMusicSheet(score, "path missing");
-        if (this.width) {
-            this.display();
-        }
+        this.graphic = new GraphicalMusicSheet(this.sheet, calc);
+        this.display();
     }
 
     public setCanvas(canvas: HTMLCanvasElement): void {
         this.canvas = canvas;
-        this.drawer = new VexFlowMusicSheetDrawer(canvas);
+        this.drawer = new VexFlowMusicSheetDrawer(canvas, new VexFlowTextMeasurer());
     }
 
     public setWidth(width: number): void {
+        if (width === this.width) {
+            return;
+        }
         this.width = width;
         this.display();
     }
 
+    public scale(k: number): void {
+        this.zoom = k;
+        this.display();
+    }
+
     public display(): void {
+        if (this.width === undefined) {
+            return;
+        }
         if (this.canvas === undefined) {
-            throw new Error("Call .setCanvas first");
+            return;
         }
         if (this.sheet === undefined) {
             return;
         }
-        let gms: GraphicalMusicSheet = new GraphicalMusicSheet(this.sheet, this.calc);
-        this.drawer.drawSheet(gms);
+        this.sheet.pageWidth = this.width / this.zoom / this.unit;
+        this.graphic.reCalculate();
+        // Update Sheet Page
+        let height: number = this.graphic.MusicPages[0].PositionAndShape.BorderBottom * this.unit * this.zoom;
+        this.drawer.resize(
+            this.width,
+            height
+        );
+        this.drawer.scale(this.zoom);
+        this.drawer.drawSheet(this.graphic);
     }
 
     public free(): void {

+ 26 - 0
src/MusicalScore/Graphical/DrawingMode.ts

@@ -0,0 +1,26 @@
+export enum DrawingMode {
+    All,
+    NoOverlays,
+    Leadsheet
+}
+
+export enum MusicSymbolDrawingStyle {
+    Normal,
+    Disabled,
+    Selected,
+    Clickable,
+    PlaybackSymbols,
+    FollowSymbols,
+    QFeedbackNotFound,
+    QFeedbackOk,
+    QFeedbackPerfect,
+    Debug1,
+    Debug2,
+    Debug3
+}
+
+export enum PhonicScoreModes {
+    Following,
+    Midi,
+    Manual
+}

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

@@ -0,0 +1,47 @@
+export class DrawingParameters {
+    public drawHighlights: boolean;
+    public drawErrors: boolean;
+    public drawSelectionStartSymbol: boolean;
+    public drawSelectionEndSymbol: boolean;
+    public drawCursors: boolean;
+    public drawActivitySymbols: boolean;
+    public drawScrollIndicator: boolean;
+    public drawComments: boolean;
+    public drawMarkedAreas: boolean;
+
+    public setForAllOn(): void {
+        this.drawHighlights = true;
+        this.drawErrors = true;
+        this.drawSelectionStartSymbol = true;
+        this.drawSelectionEndSymbol = true;
+        this.drawCursors = true;
+        this.drawActivitySymbols = true;
+        this.drawScrollIndicator = true;
+        this.drawComments = true;
+        this.drawMarkedAreas = true;
+    }
+
+    public setForThumbmail(): void {
+        this.drawHighlights = false;
+        this.drawErrors = false;
+        this.drawSelectionStartSymbol = false;
+        this.drawSelectionStartSymbol = false;
+        this.drawCursors = false;
+        this.drawActivitySymbols = false;
+        this.drawScrollIndicator = false;
+        this.drawComments = true;
+        this.drawMarkedAreas = true;
+    }
+
+    public setForLeadsheet(): void {
+        this.drawHighlights = false;
+        this.drawErrors = false;
+        this.drawSelectionStartSymbol = true;
+        this.drawSelectionEndSymbol = true;
+        this.drawCursors = true;
+        this.drawActivitySymbols = false;
+        this.drawScrollIndicator = true;
+        this.drawComments = true;
+        this.drawMarkedAreas = true;
+    }
+}

+ 30 - 5
src/MusicalScore/Graphical/GraphicalMusicSheet.ts

@@ -21,6 +21,9 @@ import {MusicSheetCalculator} from "./MusicSheetCalculator";
 import {Logging} from "../../Common/logging";
 import Dictionary from "typescript-collections/dist/lib/Dictionary";
 import {CollectionUtil} from "../../Util/collectionUtil";
+import {SelectionStartSymbol} from "./SelectionStartSymbol";
+import {SelectionEndSymbol} from "./SelectionEndSymbol";
+import {OutlineAndFillStyleEnum} from "./DrawingEnums";
 
 export class GraphicalMusicSheet {
     constructor(musicSheet: MusicSheet, calculator: MusicSheetCalculator) {
@@ -44,6 +47,8 @@ export class GraphicalMusicSheet {
     private composer: GraphicalLabel;
     private lyricist: GraphicalLabel;
     private cursors: GraphicalLine[] = [];
+    private selectionStartSymbol: SelectionStartSymbol;
+    private selectionEndSymbol: SelectionEndSymbol;
     private minAllowedSystemWidth: number;
     //private systemImages: Dictionary<MusicSystem, SystemImageProperties> = new Dictionary<MusicSystem, SystemImageProperties>();
     private numberOfStaves: number;
@@ -121,6 +126,14 @@ export class GraphicalMusicSheet {
         return this.cursors;
     }
 
+    public get SelectionStartSymbol(): SelectionStartSymbol {
+        return this.selectionStartSymbol;
+    }
+
+    public get SelectionEndSymbol(): SelectionEndSymbol {
+        return this.selectionEndSymbol;
+    }
+
     public get MinAllowedSystemWidth(): number {
         return this.minAllowedSystemWidth;
     }
@@ -658,14 +671,26 @@ export class GraphicalMusicSheet {
         return undefined;
     }
 
-    public calculateXPositionFromTimestamp(timeStamp: Fraction, currentMusicSystem: MusicSystem): number {
+    public calculateCursorLineAtTimestamp(musicTimestamp: Fraction, styleEnum: OutlineAndFillStyleEnum): GraphicalLine {
+        let result: [number, MusicSystem] = this.calculateXPositionFromTimestamp(musicTimestamp);
+        let xPos: number = result[0];
+        let correspondingMusicSystem: MusicSystem = result[1];
+        if (correspondingMusicSystem === undefined || correspondingMusicSystem.StaffLines.length === 0) {
+            return undefined;
+        }
+        let yCoordinate: number = correspondingMusicSystem.PositionAndShape.AbsolutePosition.y;
+        let height: number = CollectionUtil.last(correspondingMusicSystem.StaffLines).PositionAndShape.RelativePosition.y + 4;
+        return new GraphicalLine(new PointF2D(xPos, yCoordinate), new PointF2D(xPos, yCoordinate + height), 3, styleEnum);
+    }
+
+    public calculateXPositionFromTimestamp(timeStamp: Fraction): [number, MusicSystem] {
+        let currentMusicSystem: MusicSystem = undefined;
         let fractionalIndex: number = this.GetInterpolatedIndexInVerticalContainers(timeStamp);
         let previousStaffEntry: GraphicalStaffEntry = this.findClosestLeftStaffEntry(fractionalIndex, true);
         let nextStaffEntry: GraphicalStaffEntry = this.findClosestRightStaffEntry(fractionalIndex, true);
         let currentTimeStamp: number = timeStamp.RealValue;
         if (previousStaffEntry === undefined && nextStaffEntry === undefined) {
-            currentMusicSystem = undefined;
-            return 0;
+            return [0, undefined];
         }
         let previousStaffEntryMusicSystem: MusicSystem = undefined;
         if (previousStaffEntry !== undefined) {
@@ -705,7 +730,7 @@ export class GraphicalMusicSheet {
             }
             fraction = Math.min(1, Math.max(0, fraction));
             let interpolatedXPosition: number = previousStaffEntryPositionX + fraction * (nextStaffEntryPositionX - previousStaffEntryPositionX);
-            return interpolatedXPosition;
+            return [interpolatedXPosition, currentMusicSystem];
         } else {
             let nextSystemLeftBorderTimeStamp: number = nextStaffEntry.parentMeasure.parentSourceMeasure.AbsoluteTimestamp.RealValue;
             let fraction: number;
@@ -727,7 +752,7 @@ export class GraphicalMusicSheet {
                 fraction = Math.min(1, Math.max(0, fraction));
                 interpolatedXPosition = nextSystemLeftBorderX + fraction * (nextStaffEntryPositionX - nextSystemLeftBorderX);
             }
-            return interpolatedXPosition;
+            return [interpolatedXPosition, currentMusicSystem];
         }
     }
 

+ 43 - 0
src/MusicalScore/Graphical/GraphicalOctaveShift.ts

@@ -0,0 +1,43 @@
+import {GraphicalObject} from "./GraphicalObject";
+import {OctaveShift, OctaveEnum} from "../VoiceData/Expressions/ContinuousExpressions/octaveShift";
+import {BoundingBox} from "./BoundingBox";
+import {MusicSymbol} from "./MusicSymbol";
+import {ArgumentOutOfRangeException} from "../Exceptions";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+export class GraphicalOctaveShift extends GraphicalObject {
+    constructor(octaveShift: OctaveShift, parent: BoundingBox) {
+        super();
+        this.getOctaveShift = octaveShift;
+        this.setSymbol();
+        // ToDo: set the size again due to the given symbol...
+        //this.PositionAndShape = new BoundingBox(parent, this.octaveSymbol, this);
+        this.PositionAndShape = new BoundingBox(this, parent);
+    }
+
+    public getOctaveShift: OctaveShift;
+    public octaveSymbol: MusicSymbol;
+    public dashesStart: PointF2D;
+    public dashesEnd: PointF2D;
+    public endsOnDifferentStaffLine: boolean;
+    public isFirstPart: boolean;
+    public isSecondPart: boolean;
+
+    private setSymbol(): void {
+        switch (this.getOctaveShift.Type) {
+            case OctaveEnum.VA8:
+                this.octaveSymbol = MusicSymbol.VA8;
+                break;
+            case OctaveEnum.VB8:
+                this.octaveSymbol = MusicSymbol.VB8;
+                break;
+            case OctaveEnum.MA15:
+                this.octaveSymbol = MusicSymbol.MA15;
+                break;
+            case OctaveEnum.MB15:
+                this.octaveSymbol = MusicSymbol.MB15;
+                break;
+            default:
+                throw new ArgumentOutOfRangeException("");
+        }
+    }
+}

+ 470 - 18
src/MusicalScore/Graphical/MusicSheetDrawer.ts

@@ -1,47 +1,499 @@
-import {GraphicalMusicSheet} from "./GraphicalMusicSheet";
-import {StaffMeasure} from "./StaffMeasure";
-import {StaffLine} from "./StaffLine";
+import {EngravingRules} from "./EngravingRules";
+import {ITextMeasurer} from "../Interfaces/ITextMeasurer";
+import {GraphicalMusicSheet} from "./GraphicalMusicSheet";
+import {BoundingBox} from "./BoundingBox";
+import {GraphicalLayers, OutlineAndFillStyleEnum} from "./DrawingEnums";
+import {DrawingParameters} from "./DrawingParameters";
+import {GraphicalLine} from "./GraphicalLine";
 import {RectangleF2D} from "../../Common/DataObjects/RectangleF2D";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+import {GraphicalRectangle} from "./GraphicalRectangle";
+import {GraphicalLabel} from "./GraphicalLabel";
+import {Label} from "../Label";
+import {TextAlignment} from "../../Common/Enums/TextAlignment";
+import {ArgumentOutOfRangeException} from "../Exceptions";
+import {SelectionStartSymbol} from "./SelectionStartSymbol";
+import {SelectionEndSymbol} from "./SelectionEndSymbol";
 import {MusicSystem} from "./MusicSystem";
+import {StaffMeasure} from "./StaffMeasure";
+import {StaffLine} from "./StaffLine";
+import {SystemLine} from "./SystemLine";
+import {MusicSymbol} from "./MusicSymbol";
 import {GraphicalMusicPage} from "./GraphicalMusicPage";
+import {Instrument} from "../Instrument";
+import {MusicSymbolDrawingStyle, PhonicScoreModes} from "./DrawingMode";
+import {GraphicalOctaveShift} from "./GraphicalOctaveShift";
+import {GraphicalObject} from "./GraphicalObject";
 
-export class MusicSheetDrawer {
+export abstract class MusicSheetDrawer {
+    public drawingParameters: DrawingParameters = new DrawingParameters();
+    public splitScreenLineColor: number;
+    public midiPlaybackAvailable: boolean;
+
+    protected rules: EngravingRules;
     protected graphicalMusicSheet: GraphicalMusicSheet;
+    protected textMeasurer: ITextMeasurer;
+    private phonicScoreMode: PhonicScoreModes = PhonicScoreModes.Manual;
+
+    constructor(textMeasurer: ITextMeasurer,
+                isPreviewImageDrawer: boolean = false) {
+        this.textMeasurer = textMeasurer;
+        this.splitScreenLineColor = -1;
+        if (isPreviewImageDrawer) {
+            this.drawingParameters.setForThumbmail();
+        } else {
+            this.drawingParameters.setForAllOn();
+        }
+    }
+
+    public set Mode(value: PhonicScoreModes) {
+        this.phonicScoreMode = value;
+    }
 
     public drawSheet(graphicalMusicSheet: GraphicalMusicSheet): void {
         this.graphicalMusicSheet = graphicalMusicSheet;
-        for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) {
-            let page: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx];
+        this.rules = graphicalMusicSheet.ParentMusicSheet.Rules;
+        this.drawSplitScreenLine();
+        if (this.drawingParameters.drawCursors) {
+            for (let line of graphicalMusicSheet.Cursors) {
+                let psi: BoundingBox = new BoundingBox(line);
+                psi.AbsolutePosition = line.Start;
+                psi.BorderBottom = line.End.y - line.Start.y;
+                psi.BorderRight = line.Width / 2.0;
+                psi.BorderLeft = -line.Width / 2.0;
+                if (this.isVisible(psi)) {
+                    this.drawLineAsVerticalRectangle(line, <number>GraphicalLayers.Cursor);
+                }
+            }
+        }
+        if (this.drawingParameters.drawScrollIndicator) {
+            this.drawScrollIndicator();
+        }
+        for (let page of this.graphicalMusicSheet.MusicPages) {
             this.drawPage(page);
         }
     }
 
-    protected drawMeasure(measure: StaffMeasure): void {
+    public drawLineAsHorizontalRectangle(line: GraphicalLine, layer: number): void {
+        let rectangle: RectangleF2D = new RectangleF2D(line.Start.x, line.End.y - line.Width / 2, line.End.x - line.Start.x, line.Width);
+        rectangle = this.applyScreenTransformationForRect(rectangle);
+        this.renderRectangle(rectangle, layer, line.styleId);
+    }
+
+    public drawLineAsVerticalRectangle(line: GraphicalLine, layer: number): void {
+        let lineStart: PointF2D = line.Start;
+        let lineWidth: number = line.Width;
+        let rectangle: RectangleF2D = new RectangleF2D(lineStart.x - lineWidth / 2, lineStart.y, lineWidth, line.End.y - lineStart.y);
+        rectangle = this.applyScreenTransformationForRect(rectangle);
+        this.renderRectangle(rectangle, layer, line.styleId);
+    }
+
+    public drawLineAsHorizontalRectangleWithOffset(line: GraphicalLine, offset: PointF2D, layer: number): void {
+        let start: PointF2D = new PointF2D(line.Start.x + offset.x, line.Start.y + offset.y);
+        let end: PointF2D = new PointF2D(line.End.x + offset.x, line.End.y + offset.y);
+        let width: number = line.Width;
+        let rectangle: RectangleF2D = new RectangleF2D(start.x, end.y - width / 2, end.x - start.x, width);
+        rectangle = this.applyScreenTransformationForRect(rectangle);
+        this.renderRectangle(rectangle, layer, line.styleId);
+    }
+
+    public drawLineAsVerticalRectangleWithOffset(line: GraphicalLine, offset: PointF2D, layer: number): void {
+        let start: PointF2D = new PointF2D(line.Start.x + offset.x, line.Start.y + offset.y);
+        let end: PointF2D = new PointF2D(line.End.x + offset.x, line.End.y + offset.y);
+        let width: number = line.Width;
+        let rectangle: RectangleF2D = new RectangleF2D(start.x, start.y, width, end.y - start.y);
+        rectangle = this.applyScreenTransformationForRect(rectangle);
+        this.renderRectangle(rectangle, layer, line.styleId);
+    }
+
+    public drawRectangle(rect: GraphicalRectangle, layer: number): void {
+        let psi: BoundingBox = rect.PositionAndShape;
+        let rectangle: RectangleF2D = new RectangleF2D(psi.AbsolutePosition.x, psi.AbsolutePosition.y, psi.BorderRight, psi.BorderBottom);
+        rectangle = this.applyScreenTransformationForRect(rectangle);
+        this.renderRectangle(rectangle, layer, <number>rect.style);
+    }
+
+    public calculatePixelDistance(unitDistance: number): number {
         throw new Error("not implemented");
     }
 
-    protected applyScreenTransformation(rectangle: RectangleF2D): RectangleF2D {
+    public drawLabel(graphicalLabel: GraphicalLabel, layer: number): void {
+        if (!this.isVisible(graphicalLabel.PositionAndShape)) {
+            return;
+        }
+        let label: Label = graphicalLabel.Label;
+        if (label.text.trim() === "") {
+            return;
+        }
+        let screenPosition: PointF2D = this.applyScreenTransformation(graphicalLabel.PositionAndShape.AbsolutePosition);
+        let heightInPixel: number = this.calculatePixelDistance(label.fontHeight);
+        let widthInPixel: number = heightInPixel * this.textMeasurer.computeTextWidthToHeightRatio(label.text, label.font, label.fontStyle);
+        let bitmapWidth: number = <number>Math.ceil(widthInPixel);
+        let bitmapHeight: number = <number>Math.ceil(heightInPixel * 1.2);
+        switch (label.textAlignment) {
+            case TextAlignment.LeftTop:
+                break;
+            case TextAlignment.LeftCenter:
+                screenPosition.y -= <number>bitmapHeight / 2;
+                break;
+            case TextAlignment.LeftBottom:
+                screenPosition.y -= bitmapHeight;
+                break;
+            case TextAlignment.CenterTop:
+                screenPosition.x -= <number>bitmapWidth / 2;
+                break;
+            case TextAlignment.CenterCenter:
+                screenPosition.x -= <number>bitmapWidth / 2;
+                screenPosition.y -= <number>bitmapHeight / 2;
+                break;
+            case TextAlignment.CenterBottom:
+                screenPosition.x -= <number>bitmapWidth / 2;
+                screenPosition.y -= bitmapHeight;
+                break;
+            case TextAlignment.RightTop:
+                screenPosition.x -= bitmapWidth;
+                break;
+            case TextAlignment.RightCenter:
+                screenPosition.x -= bitmapWidth;
+                screenPosition.y -= <number>bitmapHeight / 2;
+                break;
+            case TextAlignment.RightBottom:
+                screenPosition.x -= bitmapWidth;
+                screenPosition.y -= bitmapHeight;
+                break;
+            default:
+                throw new ArgumentOutOfRangeException("");
+        }
+        this.renderLabel(graphicalLabel, layer, bitmapWidth, bitmapHeight, heightInPixel, screenPosition);
+    }
+
+    protected applyScreenTransformation(point: PointF2D): PointF2D {
         throw new Error("not implemented");
     }
 
-    private drawPage(page: GraphicalMusicPage): void {
-        for (let idx: number = 0, len: number = page.MusicSystems.length; idx < len; ++idx) {
-            let system: MusicSystem = page.MusicSystems[idx];
-            this.drawMusicSystem(system);
+    protected applyScreenTransformations(points: PointF2D[]): PointF2D[] {
+        let transformedPoints: PointF2D[] = [];
+        for (let point of points) {
+            transformedPoints.push(this.applyScreenTransformation(point));
         }
+        return transformedPoints;
+    }
+
+    protected applyScreenTransformationForRect(rectangle: RectangleF2D): RectangleF2D {
+        throw new Error("not implemented");
+    }
+
+    protected drawSplitScreenLine(): void {
+        // empty
+    }
+
+    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number): void {
+        throw new Error("not implemented");
+    }
+
+    protected drawScrollIndicator(): void {
+        // empty
+    }
+
+    protected drawSelectionStartSymbol(symbol: SelectionStartSymbol): void {
+        // empty
+    }
+
+    protected drawSelectionEndSymbol(symbol: SelectionEndSymbol): void {
+        // empty
+    }
+
+    protected renderLabel(graphicalLabel: GraphicalLabel, layer: number, bitmapWidth: number,
+                          bitmapHeight: number, heightInPixel: number, screenPosition: PointF2D): void {
+        throw new Error("not implemented");
+    }
+
+    protected renderSystemToScreen(system: MusicSystem, systemBoundingBoxInPixels: RectangleF2D,
+                                   absBoundingRectWithMargin: RectangleF2D): void {
+        // empty
+    }
+
+    protected drawMeasure(measure: StaffMeasure): void {
+        throw new Error("not implemented");
+    }
+
+    protected drawSkyLine(staffLine: StaffLine): void {
+        // empty
+    }
+
+    protected drawBottomLine(staffLine: StaffLine): void {
+        // empty
+    }
+
+    protected drawInstrumentBracket(bracket: GraphicalObject, system: MusicSystem): void {
+        // empty
+    }
+
+    protected drawGroupBracket(bracket: GraphicalObject, system: MusicSystem): void {
+        // empty
+    }
+
+    protected isVisible(psi: BoundingBox): boolean {
+        return true;
+    }
+
+    protected drawMusicSystem(system: MusicSystem): void {
+        let absBoundingRectWithMargin: RectangleF2D = this.getSystemAbsBoundingRect(system);
+        let systemBoundingBoxInPixels: RectangleF2D = this.getSytemBoundingBoxInPixels(absBoundingRectWithMargin);
+        this.drawMusicSystemComponents(system, systemBoundingBoxInPixels, absBoundingRectWithMargin);
     }
 
-    private drawMusicSystem(musicSystem: MusicSystem): void {
-        for (let idx: number = 0, len: number = musicSystem.StaffLines.length; idx < len; ++idx) {
-            let staffLine: StaffLine = musicSystem.StaffLines[idx];
+    protected getSytemBoundingBoxInPixels(absBoundingRectWithMargin: RectangleF2D): RectangleF2D {
+        let systemBoundingBoxInPixels: RectangleF2D = this.applyScreenTransformationForRect(absBoundingRectWithMargin);
+        systemBoundingBoxInPixels.x = Math.round(systemBoundingBoxInPixels.x);
+        systemBoundingBoxInPixels.y = Math.round(systemBoundingBoxInPixels.y);
+        return systemBoundingBoxInPixels;
+    }
+
+    protected getSystemAbsBoundingRect(system: MusicSystem): RectangleF2D {
+        let relBoundingRect: RectangleF2D = system.PositionAndShape.BoundingRectangle;
+        let absBoundingRectWithMargin: RectangleF2D = new RectangleF2D(
+            system.PositionAndShape.AbsolutePosition.x + system.PositionAndShape.BorderLeft - 1,
+            system.PositionAndShape.AbsolutePosition.y + system.PositionAndShape.BorderTop - 1,
+            (relBoundingRect.width + 6), (relBoundingRect.height + 2)
+        );
+        return absBoundingRectWithMargin;
+    }
+
+    protected drawMusicSystemComponents(musicSystem: MusicSystem, systemBoundingBoxInPixels: RectangleF2D,
+                                        absBoundingRectWithMargin: RectangleF2D): void {
+        let selectStartSymb: SelectionStartSymbol = this.graphicalMusicSheet.SelectionStartSymbol;
+        let selectEndSymb: SelectionEndSymbol = this.graphicalMusicSheet.SelectionEndSymbol;
+        if (this.drawingParameters.drawSelectionStartSymbol) {
+            if (selectStartSymb !== undefined && this.isVisible(selectStartSymb.PositionAndShape)) {
+                this.drawSelectionStartSymbol(selectStartSymb);
+            }
+        }
+        if (this.drawingParameters.drawSelectionEndSymbol) {
+            if (selectEndSymb !== undefined && this.isVisible(selectEndSymb.PositionAndShape)) {
+                this.drawSelectionEndSymbol(selectEndSymb);
+            }
+        }
+        for (let staffLine of musicSystem.StaffLines) {
             this.drawStaffLine(staffLine);
         }
+        for (let systemLine of musicSystem.SystemLines) {
+            this.drawSystemLineObject(systemLine);
+        }
+        if (musicSystem === musicSystem.Parent.MusicSystems[0] && musicSystem.Parent === musicSystem.Parent.Parent.MusicPages[0]) {
+            for (let label of musicSystem.Labels) {
+                this.drawLabel(label, <number>GraphicalLayers.Notes);
+            }
+        }
+        for (let bracket of musicSystem.InstrumentBrackets) {
+            this.drawInstrumentBracket(bracket, musicSystem);
+        }
+        for (let bracket of musicSystem.GroupBrackets) {
+            this.drawGroupBracket(bracket, musicSystem);
+        }
+        if (!this.leadSheet) {
+            for (let measureNumberLabel of musicSystem.MeasureNumberLabels) {
+                this.drawLabel(measureNumberLabel, <number>GraphicalLayers.Notes);
+            }
+        }
+        for (let staffLine of musicSystem.StaffLines) {
+            this.drawStaffLineSymbols(staffLine);
+        }
+        if (this.drawingParameters.drawMarkedAreas) {
+            this.drawMarkedAreas(musicSystem);
+        }
+        if (this.drawingParameters.drawComments) {
+            this.drawComment(musicSystem);
+        }
+    }
+
+    protected activateSystemRendering(systemId: number, absBoundingRect: RectangleF2D,
+                                      systemBoundingBoxInPixels: RectangleF2D, createNewImage: boolean): boolean {
+        return true;
+    }
+
+    protected drawSystemLineObject(systemLine: SystemLine): void {
+        // empty
     }
 
-    private drawStaffLine(staffLine: StaffLine): void {
-        for (let idx: number = 0, len: number = staffLine.Measures.length; idx < len; ++idx) {
-            let measure: StaffMeasure = staffLine.Measures[idx];
+    protected drawStaffLine(staffLine: StaffLine): void {
+        for (let measure of staffLine.Measures) {
             this.drawMeasure(measure);
         }
     }
+
+    // protected drawSlur(slur: GraphicalSlur, abs: PointF2D): void {
+    //
+    // }
+
+    protected drawOctaveShift(staffLine: StaffLine, graphicalOctaveShift: GraphicalOctaveShift): void {
+        this.drawSymbol(graphicalOctaveShift.octaveSymbol, MusicSymbolDrawingStyle.Normal, graphicalOctaveShift.PositionAndShape.AbsolutePosition);
+        let absolutePos: PointF2D = staffLine.PositionAndShape.AbsolutePosition;
+        if (graphicalOctaveShift.dashesStart.x < graphicalOctaveShift.dashesEnd.x) {
+            let horizontalLine: GraphicalLine = new GraphicalLine(graphicalOctaveShift.dashesStart, graphicalOctaveShift.dashesEnd,
+                                                                  this.rules.OctaveShiftLineWidth);
+            this.drawLineAsHorizontalRectangleWithOffset(horizontalLine, absolutePos, <number>GraphicalLayers.Notes);
+        }
+        if (!graphicalOctaveShift.endsOnDifferentStaffLine || graphicalOctaveShift.isSecondPart) {
+            let verticalLine: GraphicalLine;
+            let dashEnd: PointF2D = graphicalOctaveShift.dashesEnd;
+            let octShiftVertLineLength: number = this.rules.OctaveShiftVerticalLineLength;
+            let octShiftLineWidth: number = this.rules.OctaveShiftLineWidth;
+            if (graphicalOctaveShift.octaveSymbol === MusicSymbol.VA8 || graphicalOctaveShift.octaveSymbol === MusicSymbol.MA15) {
+                verticalLine = new GraphicalLine(dashEnd, new PointF2D(dashEnd.x, dashEnd.y + octShiftVertLineLength), octShiftLineWidth);
+            } else {
+                verticalLine = new GraphicalLine(new PointF2D(dashEnd.x, dashEnd.y - octShiftVertLineLength), dashEnd, octShiftLineWidth);
+            }
+            this.drawLineAsVerticalRectangleWithOffset(verticalLine, absolutePos, <number>GraphicalLayers.Notes);
+        }
+    }
+
+    protected drawStaffLines(staffLine: StaffLine): void {
+        if (staffLine.StaffLines !== undefined) {
+            let position: PointF2D = staffLine.PositionAndShape.AbsolutePosition;
+            for (let i: number = 0; i < 5; i++) {
+                this.drawLineAsHorizontalRectangleWithOffset(staffLine.StaffLines[i], position, <number>GraphicalLayers.Notes);
+            }
+        }
+    }
+
+    // protected drawEnding(ending: GraphicalRepetitionEnding, absolutePosition: PointF2D): void {
+    //     if (undefined !== ending.Left)
+    //         drawLineAsVerticalRectangle(ending.Left, absolutePosition, <number>GraphicalLayers.Notes);
+    //     this.drawLineAsHorizontalRectangle(ending.Top, absolutePosition, <number>GraphicalLayers.Notes);
+    //     if (undefined !== ending.Right)
+    //         drawLineAsVerticalRectangle(ending.Right, absolutePosition, <number>GraphicalLayers.Notes);
+    //     this.drawLabel(ending.Label, <number>GraphicalLayers.Notes);
+    // }
+    // protected drawInstantaniousDynamic(expression: GraphicalInstantaniousDynamicExpression): void {
+    //     expression.ExpressionSymbols.forEach(function (expressionSymbol) {
+    //         let position: PointF2D = expressionSymbol.PositionAndShape.AbsolutePosition;
+    //         let symbol: MusicSymbol = expressionSymbol.GetSymbol;
+    //         drawSymbol(symbol, MusicSymbolDrawingStyle.Normal, position);
+    //     });
+    // }
+    // protected drawContinuousDynamic(expression: GraphicalContinuousDynamicExpression,
+    //     absolute: PointF2D): void {
+    //     throw new Error("not implemented");
+    // }
+    protected drawSymbol(symbol: MusicSymbol, symbolStyle: MusicSymbolDrawingStyle, position: PointF2D,
+                         scalingFactor: number = 1, layer: number = <number>GraphicalLayers.Notes): void {
+        //empty
+    }
+
+    protected get leadSheet(): boolean {
+        return this.graphicalMusicSheet.LeadSheet;
+    }
+
+    protected set leadSheet(value: boolean) {
+        this.graphicalMusicSheet.LeadSheet = value;
+    }
+
+    private drawPage(page: GraphicalMusicPage): void {
+        if (!this.isVisible(page.PositionAndShape)) {
+            return;
+        }
+        for (let system of page.MusicSystems) {
+            if (this.isVisible(system.PositionAndShape)) {
+                this.drawMusicSystem(system);
+            }
+        }
+        if (page === page.Parent.MusicPages[0]) {
+            for (let label of page.Labels) {
+                this.drawLabel(label, <number>GraphicalLayers.Notes);
+            }
+        }
+    }
+
+    private drawMarkedAreas(system: MusicSystem): void {
+        for (let markedArea of system.GraphicalMarkedAreas) {
+            if (markedArea !== undefined) {
+                if (markedArea.systemRectangle !== undefined) {
+                    this.drawRectangle(markedArea.systemRectangle, <number>GraphicalLayers.Background);
+                }
+                if (markedArea.settings !== undefined) {
+                    this.drawLabel(markedArea.settings, <number>GraphicalLayers.Comment);
+                }
+                if (markedArea.labelRectangle !== undefined) {
+                    this.drawRectangle(markedArea.labelRectangle, <number>GraphicalLayers.Background);
+                }
+                if (markedArea.label !== undefined) {
+                    this.drawLabel(markedArea.label, <number>GraphicalLayers.Comment);
+                }
+            }
+        }
+    }
+
+    private drawComment(system: MusicSystem): void {
+        for (let comment of system.GraphicalComments) {
+            if (comment !== undefined) {
+                if (comment.settings !== undefined) {
+                    this.drawLabel(comment.settings, <number>GraphicalLayers.Comment);
+                }
+                if (comment.label !== undefined) {
+                    this.drawLabel(comment.label, <number>GraphicalLayers.Comment);
+                }
+            }
+        }
+    }
+
+    private drawStaffLineSymbols(staffLine: StaffLine): void {
+        let parentInst: Instrument = staffLine.ParentStaff.ParentInstrument;
+        let absX: number = staffLine.PositionAndShape.AbsolutePosition.x;
+        let absY: number = staffLine.PositionAndShape.AbsolutePosition.y + 2;
+        let borderRight: number = staffLine.PositionAndShape.BorderRight;
+        if (parentInst.highlight && this.drawingParameters.drawHighlights) {
+            this.drawLineAsHorizontalRectangle(
+                new GraphicalLine(
+                    new PointF2D(absX, absY),
+                    new PointF2D(absX + borderRight, absY),
+                    4,
+                    OutlineAndFillStyleEnum.Highlighted
+                ),
+                <number>GraphicalLayers.Highlight
+            );
+        }
+        let style: MusicSymbolDrawingStyle = MusicSymbolDrawingStyle.Disabled;
+        let symbol: MusicSymbol = MusicSymbol.PLAY;
+        let drawSymbols: boolean = this.drawingParameters.drawActivitySymbols;
+        switch (this.phonicScoreMode) {
+            case PhonicScoreModes.Midi:
+                symbol = MusicSymbol.PLAY;
+                if (this.midiPlaybackAvailable && staffLine.ParentStaff.audible) {
+                    style = MusicSymbolDrawingStyle.PlaybackSymbols;
+                }
+                break;
+            case PhonicScoreModes.Following:
+                symbol = MusicSymbol.MIC;
+                if (staffLine.ParentStaff.following) {
+                    style = MusicSymbolDrawingStyle.FollowSymbols;
+                }
+                break;
+            default:
+                drawSymbols = false;
+                break;
+        }
+        if (drawSymbols) {
+            let p: PointF2D = new PointF2D(absX + borderRight + 2, absY);
+            this.drawSymbol(symbol, style, p);
+        }
+        if (this.drawingParameters.drawErrors) {
+            for (let measure of staffLine.Measures) {
+                let measurePSI: BoundingBox = measure.PositionAndShape;
+                let absXPSI: number = measurePSI.AbsolutePosition.x;
+                let absYPSI: number = measurePSI.AbsolutePosition.y + 2;
+                if (measure.hasError && this.graphicalMusicSheet.ParentMusicSheet.DrawErroneousMeasures) {
+                    this.drawLineAsHorizontalRectangle(
+                        new GraphicalLine(
+                            new PointF2D(absXPSI, absYPSI),
+                            new PointF2D(absXPSI + measurePSI.BorderRight, absYPSI),
+                            4,
+                            OutlineAndFillStyleEnum.ErrorUnderlay
+                        ),
+                        <number>GraphicalLayers.MeasureError
+                    );
+                }
+            }
+        }
+    }
 }

+ 68 - 0
src/MusicalScore/Graphical/SelectionEndSymbol.ts

@@ -0,0 +1,68 @@
+import {GraphicalObject} from "./GraphicalObject";
+import {MusicSystem} from "./MusicSystem";
+import {OutlineAndFillStyleEnum} from "./DrawingEnums";
+import {StaffLine} from "./StaffLine";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+import {BoundingBox} from "./BoundingBox";
+import {GraphicalLine} from "./GraphicalLine";
+import {CollectionUtil} from "../../Util/collectionUtil";
+
+export class SelectionEndSymbol extends GraphicalObject {
+    constructor(system: MusicSystem, xPosition: number) {
+        super();
+        let xCoordinate: number = xPosition;
+        let yCoordinate: number = system.PositionAndShape.AbsolutePosition.y;
+        let lineThickness: number = 0.4;
+        let height: number = CollectionUtil.last(system.StaffLines).PositionAndShape.RelativePosition.y + 4;
+        this.verticalLine = new GraphicalLine(
+            new PointF2D(xCoordinate, yCoordinate),
+            new PointF2D(xCoordinate, yCoordinate + height),
+            lineThickness,
+            OutlineAndFillStyleEnum.SelectionSymbol
+        );
+        for (let idx: number = 0, len: number = system.StaffLines.length; idx < len; ++idx) {
+            let staffLine: StaffLine = system.StaffLines[idx];
+            let anchor: PointF2D = new PointF2D(xCoordinate, yCoordinate + staffLine.PositionAndShape.RelativePosition.y);
+            let arrowPoints: PointF2D[] = new Array(3);
+            anchor.y -= .2;
+            arrowPoints[0].x = anchor.x - 3;
+            arrowPoints[0].y = anchor.y + 1.2;
+            arrowPoints[1].x = anchor.x - 2;
+            arrowPoints[1].y = anchor.y + 0.4;
+            arrowPoints[2].x = anchor.x - 2;
+            arrowPoints[2].y = anchor.y + 2;
+            this.arrows.push(arrowPoints);
+            let linePoints: PointF2D[] = new Array(8);
+            let arrowThickness: number = .8;
+            anchor.x -= .1;
+            anchor.y += .3;
+            let hilfsVar: number = .2;
+            linePoints[0].x = anchor.x - 2;
+            linePoints[0].y = anchor.y + 1.5 - hilfsVar;
+            linePoints[1].x = anchor.x - 1;
+            linePoints[1].y = anchor.y + 1.5 - hilfsVar;
+            linePoints[2].x = anchor.x - 1;
+            linePoints[2].y = anchor.y + 2.5;
+            linePoints[3].x = anchor.x - 2;
+            linePoints[3].y = anchor.y + 2.5;
+            linePoints[4].x = linePoints[0].x;
+            linePoints[4].y = linePoints[0].y - arrowThickness;
+            linePoints[5].x = linePoints[4].x + arrowThickness + 1;
+            linePoints[5].y = linePoints[4].y;
+            linePoints[6].x = linePoints[5].x;
+            linePoints[6].y = linePoints[3].y + arrowThickness;
+            linePoints[7].x = linePoints[3].x;
+            linePoints[7].y = linePoints[6].y;
+            this.arrowlines.push(linePoints);
+        }
+        this.boundingBox = new BoundingBox(this);
+        this.boundingBox.AbsolutePosition = new PointF2D(xCoordinate, yCoordinate);
+        this.boundingBox.BorderLeft = -lineThickness;
+        this.boundingBox.BorderRight = 4;
+        this.boundingBox.BorderBottom = height;
+    }
+
+    public verticalLine: GraphicalLine;
+    public arrows: PointF2D[][];
+    public arrowlines: PointF2D[][];
+}

+ 52 - 0
src/MusicalScore/Graphical/SelectionStartSymbol.ts

@@ -0,0 +1,52 @@
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+import {StaffLine} from "./StaffLine";
+import {OutlineAndFillStyleEnum} from "./DrawingEnums";
+import {GraphicalLine} from "./GraphicalLine";
+import {MusicSystem} from "./MusicSystem";
+import {GraphicalObject} from "./GraphicalObject";
+import {BoundingBox} from "./BoundingBox";
+import {CollectionUtil} from "../../Util/collectionUtil";
+
+export class SelectionStartSymbol extends GraphicalObject {
+    constructor(system: MusicSystem, xPosition: number) {
+        super();
+        let xCoordinate: number = xPosition;
+        let yCoordinate: number = system.PositionAndShape.AbsolutePosition.y;
+        let lineThickness: number = 0.4;
+        let height: number = CollectionUtil.last(system.StaffLines).PositionAndShape.RelativePosition.y + 4;
+        this.verticalLine = new GraphicalLine(
+            new PointF2D(xCoordinate, yCoordinate),
+            new PointF2D(xCoordinate, yCoordinate + height),
+            lineThickness,
+            OutlineAndFillStyleEnum.SelectionSymbol
+        );
+        for (let idx: number = 0, len: number = system.StaffLines.length; idx < len; ++idx) {
+            let staffLine: StaffLine = system.StaffLines[idx];
+            let anchor: PointF2D = new PointF2D(xCoordinate, yCoordinate + staffLine.PositionAndShape.RelativePosition.y);
+            let arrowPoints: PointF2D[] = new Array(7);
+            arrowPoints[0].x = anchor.x + 4;
+            arrowPoints[0].y = anchor.y + 2;
+            arrowPoints[1].x = anchor.x + 2.5;
+            arrowPoints[1].y = anchor.y + 0.5;
+            arrowPoints[2].x = anchor.x + 2.5;
+            arrowPoints[2].y = anchor.y + 1.3;
+            arrowPoints[3].x = anchor.x + 1;
+            arrowPoints[3].y = anchor.y + 1.3;
+            arrowPoints[4].x = anchor.x + 1;
+            arrowPoints[4].y = anchor.y + 2.7;
+            arrowPoints[5].x = anchor.x + 2.5;
+            arrowPoints[5].y = anchor.y + 2.7;
+            arrowPoints[6].x = anchor.x + 2.5;
+            arrowPoints[6].y = anchor.y + 3.5;
+            this.arrows.push(arrowPoints);
+        }
+        this.boundingBox = new BoundingBox(this);
+        this.boundingBox.AbsolutePosition = new PointF2D(xCoordinate, yCoordinate);
+        this.boundingBox.BorderLeft = -lineThickness;
+        this.boundingBox.BorderRight = 4;
+        this.boundingBox.BorderBottom = height;
+    }
+
+    public verticalLine: GraphicalLine;
+    public arrows: PointF2D[][];
+}

+ 8 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts

@@ -51,11 +51,18 @@ export class VexFlowMeasure extends StaffMeasure {
      * This is needed to evaluate a measure a second time by system builder.
      */
     public resetLayout(): void {
-        this.stave = new Vex.Flow.Stave(0, 0, 0);
         // Take into account some space for the begin and end lines of the stave
         // Will be changed when repetitions will be implemented
         this.beginInstructionsWidth = 20 / this.unit;
         this.endInstructionsWidth = 20 / this.unit;
+        this.stave = new Vex.Flow.Stave(0, 0, 0);
+    }
+
+    public clean(): void {
+        this.beams = {};
+        //this.vfbeams = {};
+        this.connectors = [];
+        console.log("clean!");
     }
 
     /**

+ 15 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -26,7 +26,6 @@ import {Tuplet} from "../../VoiceData/Tuplet";
 import Dictionary from "typescript-collections/dist/lib/Dictionary";
 import {VexFlowMeasure} from "./VexFlowMeasure";
 import {VexFlowTextMeasurer} from "./VexFlowTextMeasurer";
-//import {VexFlowMeasure} from "./VexFlowMeasure";
 
 import Vex = require("vexflow");
 import {PointF2D} from "../../../Common/DataObjects/PointF2D";
@@ -37,6 +36,21 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
         MusicSheetCalculator.TextMeasurer = new VexFlowTextMeasurer();
     }
 
+    protected clearRecreatedObjects(): void {
+        super.clearRecreatedObjects();
+        for (let staffMeasures of this.graphicalMusicSheet.MeasureList) {
+            for (let staffMeasure of staffMeasures) {
+                (<VexFlowMeasure>staffMeasure).clean();
+            }
+        }
+    }
+
+    //protected clearSystemsAndMeasures(): void {
+    //    for (let measure of measures) {
+    //
+    //    }
+    //}
+
     /**
      * The main method for the Calculator.
      */

+ 65 - 15
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts

@@ -3,29 +3,38 @@ import {MusicSheetDrawer} from "../MusicSheetDrawer";
 import {RectangleF2D} from "../../../Common/DataObjects/RectangleF2D";
 import {VexFlowMeasure} from "./VexFlowMeasure";
 import {GraphicalMusicSheet} from "../GraphicalMusicSheet";
+import {ITextMeasurer} from "../../Interfaces/ITextMeasurer";
+import {PointF2D} from "../../../Common/DataObjects/PointF2D";
+import {GraphicalLabel} from "../GraphicalLabel";
 /**
  * Created by Matthias on 22.06.2016.
  */
 export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
-    constructor(canvas: HTMLCanvasElement) {
-        super();
+    private renderer: Vex.Flow.Renderer;
+    private ctx: Vex.Flow.CanvasContext;
+
+    constructor(canvas: HTMLCanvasElement, textMeasurer: ITextMeasurer, isPreviewImageDrawer: boolean = false) {
+        super(textMeasurer, isPreviewImageDrawer);
         this.renderer = new Vex.Flow.Renderer(canvas, Vex.Flow.Renderer.Backends.CANVAS);
         this.ctx = this.renderer.getContext();
+    }
 
+    public scale(k: number): void {
+        this.ctx.scale(k, k);
     }
 
-    private renderer: Vex.Flow.Renderer;
-    private ctx: Vex.Flow.CanvasContext;
+    public resize(x: number, y: number): void {
+        this.renderer.resize(x, y);
+    }
 
-    public drawSheet(graphicalMusicSheet: GraphicalMusicSheet): void {
-        // FIXME units
-        // FIXME actual page size
-        let unit: number = 10;
-        this.renderer.resize(
-            unit * graphicalMusicSheet.ParentMusicSheet.pageWidth,
-            unit * graphicalMusicSheet.ParentMusicSheet.pageWidth
-        );
-        super.drawSheet(graphicalMusicSheet);
+    /**
+     * Converts a distance from unit to pixel space.
+     * @param unitDistance the distance in units
+     * @returns {number} the distance in pixels
+     */
+    public calculatePixelDistance(unitDistance: number): number {
+        // ToDo: implement!
+        return unitDistance;
     }
 
     protected drawMeasure(measure: VexFlowMeasure): void {
@@ -36,7 +45,48 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
         return measure.draw(this.ctx);
     }
 
-    protected applyScreenTransformation(rectangle: RectangleF2D): RectangleF2D {
-        throw new Error("not implemented");
+    /**
+     * Renders a Label to the screen (e.g. Title, composer..)
+     * @param graphicalLabel holds the label string, the text height in units and the font parameters
+     * @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 bitmapWidth Not needed for now.
+     * @param bitmapHeight Not needed for now.
+     * @param heightInPixel the height of the text in screen coordinates
+     * @param screenPosition the position of the lower left corner of the text in screen coordinates
+     */
+    protected renderLabel(graphicalLabel: GraphicalLabel, layer: number, bitmapWidth: number,
+                          bitmapHeight: number, heightInPixel: number, screenPosition: PointF2D): void {
+        // ToDo: implement!
+    }
+
+    /**
+     * 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
+     */
+    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number): void {
+        // ToDo: implement!
+    }
+
+    /**
+     * Converts a point from unit to pixel space.
+     * @param point
+     * @returns {PointF2D}
+     */
+    protected applyScreenTransformation(point: PointF2D): PointF2D {
+        // ToDo: implement!
+        return point;
+    }
+
+    /**
+     * Converts a rectangle from unit to pixel space.
+     * @param rectangle
+     * @returns {RectangleF2D}
+     */
+    protected applyScreenTransformationForRect(rectangle: RectangleF2D): RectangleF2D {
+        // ToDo: implement!
+        return rectangle;
     }
 }

+ 5 - 1
test/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts

@@ -5,6 +5,9 @@ import {MusicSheetReader} from "../../../../src/MusicalScore/ScoreIO/MusicSheetR
 import {VexFlowMusicSheetCalculator} from "../../../../src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator";
 import {TestUtils} from "../../../Util/TestUtils";
 import {IXmlElement} from "../../../../src/Common/FileIO/Xml";
+import {VexFlowTextMeasurer} from "../../../../src/MusicalScore/Graphical/VexFlow/VexFlowTextMeasurer";
+import {Fraction} from "../../../../src/Common/DataObjects/fraction";
+import {OutlineAndFillStyleEnum} from "../../../../src/MusicalScore/Graphical/DrawingEnums";
 
 describe("VexFlow Music Sheet Drawer", () => {
 
@@ -17,6 +20,7 @@ describe("VexFlow Music Sheet Drawer", () => {
         let reader: MusicSheetReader = new MusicSheetReader();
         let sheet: MusicSheet = reader.createMusicSheet(score, path);
         let gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
+        gms.Cursors.push(gms.calculateCursorLineAtTimestamp(new Fraction(), OutlineAndFillStyleEnum.PlaybackCursor));
 
         // Create heading in the test page
         let h1: Element = document.createElement("h1");
@@ -25,7 +29,7 @@ describe("VexFlow Music Sheet Drawer", () => {
         // Create the canvas in the document:
         let canvas: HTMLCanvasElement = document.createElement("canvas");
         document.body.appendChild(canvas);
-        (new VexFlowMusicSheetDrawer(canvas)).drawSheet(gms);
+        (new VexFlowMusicSheetDrawer(canvas, new VexFlowTextMeasurer())).drawSheet(gms);
         done();
     });