diff --git a/external/vexflow/vexflow.d.ts b/external/vexflow/vexflow.d.ts index b14e8b661..655103af6 100644 --- a/external/vexflow/vexflow.d.ts +++ b/external/vexflow/vexflow.d.ts @@ -321,12 +321,20 @@ declare namespace Vex { export class CanvasContext extends RenderContext { public vexFlowCanvasContext: CanvasRenderingContext2D; + // TODO CanvasRenderingContext2D isn't defined anywhere, and defining it leads to problems. + // this somehow works, though. + public background_fillStyle: { fill: string }; + public setBackgroundFillStyle(style: string): void; + public clear(x: number, y: number, width: number, height: number): void; } export class SVGContext extends RenderContext { public svg: SVGElement; public attributes: any; public state: any; + public setBackgroundFillStyle(style: string): void; + public background_attributes: any; + public clear(x: number, y: number, width: number, height: number): void; } export class StaveConnector { diff --git a/src/MusicalScore/Graphical/DrawingEnums.ts b/src/MusicalScore/Graphical/DrawingEnums.ts index 9ff1d0b91..e56033bab 100644 --- a/src/MusicalScore/Graphical/DrawingEnums.ts +++ b/src/MusicalScore/Graphical/DrawingEnums.ts @@ -36,7 +36,8 @@ export enum OutlineAndFillStyleEnum { Comment7, Comment8, Comment9, - Comment10 + Comment10, + BackgroundWhite, } // tslint:disable-next-line:max-line-length A linebreak would be more confusing here @@ -74,6 +75,7 @@ OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment7, "Blanched 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"); +OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.BackgroundWhite, "White"); export enum StyleSets { MarkedArea, diff --git a/src/MusicalScore/Graphical/EngravingRules.ts b/src/MusicalScore/Graphical/EngravingRules.ts index ca23563d1..3b834e328 100644 --- a/src/MusicalScore/Graphical/EngravingRules.ts +++ b/src/MusicalScore/Graphical/EngravingRules.ts @@ -142,6 +142,7 @@ export class EngravingRules { private noteDistancesScalingFactors: number[] = [1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0]; private durationDistanceDict: {[_: number]: number; } = {}; private durationScalingDistanceDict: {[_: number]: number; } = {}; + private backgroundColorFillStyle: string = "#FFF"; // white constructor() { // global variables @@ -1135,6 +1136,12 @@ export class EngravingRules { public get DurationScalingDistanceDict(): {[_: number]: number; } { return this.durationScalingDistanceDict; } + public get BackgroundColorFillStyle(): string { + return this.backgroundColorFillStyle; + } + public set BackgroundColorFillStyle(value: string) { + this.backgroundColorFillStyle = value; + } /** * This method maps NoteDurations to Distances and DistancesScalingFactors. diff --git a/src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend.ts b/src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend.ts index edbb4e91b..1a6d06e31 100644 --- a/src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend.ts +++ b/src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend.ts @@ -6,8 +6,10 @@ import {Fonts} from "../../../Common/Enums/Fonts"; import {RectangleF2D} from "../../../Common/DataObjects/RectangleF2D"; import {PointF2D} from "../../../Common/DataObjects/PointF2D"; import {VexFlowConverter} from "./VexFlowConverter"; +import { EngravingRules } from "../EngravingRules"; export class CanvasVexFlowBackend extends VexFlowBackend { + private backgroundFillStyle: string = EngravingRules.Rules.BackgroundColorFillStyle; public getBackendType(): number { return Vex.Flow.Renderer.Backends.CANVAS; @@ -23,6 +25,8 @@ export class CanvasVexFlowBackend extends VexFlowBackend { this.renderer = new Vex.Flow.Renderer(this.canvas, this.getBackendType()); this.ctx = this.renderer.getContext(); this.canvasRenderingCtx = this.ctx.vexFlowCanvasContext; + this.ctx.setBackgroundFillStyle(this.backgroundFillStyle); + (this.canvasRenderingCtx as any).setBackgroundFillStyle(this.backgroundFillStyle); } /** @@ -36,15 +40,38 @@ export class CanvasVexFlowBackend extends VexFlowBackend { (this.canvas as any).height = height; this.renderer = new Vex.Flow.Renderer(this.canvas, this.getBackendType()); this.ctx = this.renderer.getContext(); + this.ctx.setBackgroundFillStyle(this.backgroundFillStyle); this.canvasRenderingCtx = this.ctx.vexFlowCanvasContext; + (this.canvasRenderingCtx as any).setBackgroundFillStyle(this.backgroundFillStyle); } public getContext(): Vex.Flow.CanvasContext { return this.ctx; } - public clear(): void { - (this.ctx).clearRect(0, 0, (this.canvas).width, (this.canvas).height); + public clear(x: number = -1, y: number = -1, width: number = -1, height: number = -1): void { + if (x !== -1) { + if (this.backgroundFillStyle === "transparent") { + // (this.ctx).clearRect(0, 0, (this.canvas).width, (this.canvas).height); + // TODO clearRect currently doesn't do anything in Vexflow for Canvas. + // Also, canvas width and height are often very small, smaller than sheet.pageWidth + } else { + // fill canvas with background color + // TODO currently this prevents the cursor from showing if it's on z=-1 + const renderCtx: any = this.canvasRenderingCtx; + renderCtx.save(); + renderCtx.setFillStyle(this.backgroundFillStyle); + renderCtx.fillRect(x, y, width, height); + renderCtx.restore(); // there's no getFillStyle() right now. + } + } + } + + public getBackgroundColor(): string { + return this.backgroundFillStyle; + } + public setBackgroundColor(colorOrStyle: string): void { + this.backgroundFillStyle = colorOrStyle; } public scale(k: number): void { diff --git a/src/MusicalScore/Graphical/VexFlow/SvgVexFlowBackend.ts b/src/MusicalScore/Graphical/VexFlow/SvgVexFlowBackend.ts index 8a920a2a4..ce8e1c6ab 100644 --- a/src/MusicalScore/Graphical/VexFlow/SvgVexFlowBackend.ts +++ b/src/MusicalScore/Graphical/VexFlow/SvgVexFlowBackend.ts @@ -6,8 +6,10 @@ import {FontStyles} from "../../../Common/Enums/FontStyles"; import {Fonts} from "../../../Common/Enums/Fonts"; import {RectangleF2D} from "../../../Common/DataObjects/RectangleF2D"; import {PointF2D} from "../../../Common/DataObjects/PointF2D"; +import { EngravingRules } from "../EngravingRules"; export class SvgVexFlowBackend extends VexFlowBackend { + private backgroundFillStyle: string = EngravingRules.Rules.BackgroundColorFillStyle; public getBackendType(): number { return Vex.Flow.Renderer.Backends.SVG; @@ -21,14 +23,14 @@ export class SvgVexFlowBackend extends VexFlowBackend { container.appendChild(this.inner); this.renderer = new Vex.Flow.Renderer(this.canvas, this.getBackendType()); this.ctx = this.renderer.getContext(); - + this.ctx.setBackgroundFillStyle(this.backgroundFillStyle); } public getContext(): Vex.Flow.SVGContext { return this.ctx; } - public clear(): void { + public clear(x: number = -1, y: number = -1, width: number = -1, height: number = -1): void { const { svg } = this.ctx; if (!svg) { return; @@ -38,6 +40,34 @@ export class SvgVexFlowBackend extends VexFlowBackend { while (svg.lastChild) { svg.removeChild(svg.lastChild); } + + if (x !== -1) { + if (this.backgroundFillStyle === "transparent") { + (this.ctx as any).clearRect(x, y, width, height); + // should in theory fill with transparency + // currently fills with bgcolor in vexflow + } else { + // filling with background color currently prevents cursor showing if on z=-1 + // note that rect works like canvascontext.fillRect right now + (this.ctx as any).rect(x, y, width, height, this.ctx.background_attributes); + + // could also use clearRect for now + // (this.ctx as any).clearRect(x, y, width, height); + + // this alternative prevents the cursor from showing (unless alpha<1) + // const backgroundRectangle: RectangleF2D = new RectangleF2D(x, y, width, height); + // this.renderRectangleByStyle(backgroundRectangle, this.backgroundFillStyle, 1); + } + } + } + + public getBackgroundColor(): string { + return this.backgroundFillStyle; + } + + public setBackgroundColor(colorOrStyle: string): void { + this.backgroundFillStyle = colorOrStyle; + this.ctx.setBackgroundFillStyle(colorOrStyle); } public scale(k: number): void { @@ -59,10 +89,16 @@ export class SvgVexFlowBackend extends VexFlowBackend { this.ctx.restore(); } public renderRectangle(rectangle: RectangleF2D, styleId: number, alpha: number = 1): void { + const style: string = VexFlowConverter.style(styleId); + this.renderRectangleByStyle(rectangle, style, alpha); + } + private renderRectangleByStyle(rectangle: RectangleF2D, style: string, alpha: number = 1): void { this.ctx.save(); - this.ctx.attributes.fill = VexFlowConverter.style(styleId); + this.ctx.attributes.fill = style; this.ctx.attributes["fill-opacity"] = alpha; + // this.ctx.attributes["stroke-width"] = 0; this.ctx.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height); + // (this.ctx).rect(rectangle.x, rectangle.y, rectangle.width, rectangle.height, this.ctx.attributes); this.ctx.restore(); this.ctx.attributes["fill-opacity"] = 1; } diff --git a/src/MusicalScore/Graphical/VexFlow/VexFlowBackend.ts b/src/MusicalScore/Graphical/VexFlow/VexFlowBackend.ts index 44a6c48c9..e480fb288 100644 --- a/src/MusicalScore/Graphical/VexFlow/VexFlowBackend.ts +++ b/src/MusicalScore/Graphical/VexFlow/VexFlowBackend.ts @@ -39,7 +39,15 @@ export abstract class VexFlowBackend { this.renderer.resize(x, y); } - public abstract clear(): void; + public abstract clear(x: number, y: number, width: number, height: number): void; + public abstract getBackgroundColor(): string; + + /** sets background color. + * does not fill the background immediately, need rerender for that. + * setting color to "transparent" will skip drawing a background in clear(). + * @param colorOrStyle color name (e.g. "white") or Vexflow style ("#FFF") + */ + public abstract setBackgroundColor(colorOrStyle: string): void; public abstract translate(x: number, y: number): void; public abstract renderText(fontHeight: number, fontStyle: FontStyles, font: Fonts, text: string, diff --git a/src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts b/src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts index 676bfe3e8..514569a08 100644 --- a/src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts +++ b/src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts @@ -33,8 +33,8 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer { this.backend = backend; } - public clear(): void { - this.backend.clear(); + public clear(x: number = -1, y: number = -1, width: number = -1, height: number = -1): void { + this.backend.clear(x, y, width, height); } /** diff --git a/src/OpenSheetMusicDisplay/Cursor.ts b/src/OpenSheetMusicDisplay/Cursor.ts index a4f4d0d5c..4ac093c49 100644 --- a/src/OpenSheetMusicDisplay/Cursor.ts +++ b/src/OpenSheetMusicDisplay/Cursor.ts @@ -15,7 +15,7 @@ export class Cursor { this.openSheetMusicDisplay = openSheetMusicDisplay; const curs: HTMLElement = document.createElement("img"); curs.style.position = "absolute"; - curs.style.zIndex = "-1"; + curs.style.zIndex = "0"; this.cursorElement = curs; this.container.appendChild(curs); } @@ -144,7 +144,7 @@ export class Cursor { c.width = this.cursorElement.width; c.height = 1; const ctx: CanvasRenderingContext2D = c.getContext("2d"); - ctx.globalAlpha = 0.5; + ctx.globalAlpha = 0.3; // Generate the gradient const gradient: CanvasGradient = ctx.createLinearGradient(0, 0, this.cursorElement.width, 0); gradient.addColorStop(0, "white"); // it was: "transparent" diff --git a/src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts b/src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts index 2610e320f..325e84bb5 100644 --- a/src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts +++ b/src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts @@ -158,11 +158,16 @@ export class OpenSheetMusicDisplay { this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(7, 4), OutlineAndFillStyleEnum.PlaybackCursor));*/ // Update Sheet Page const height: number = this.graphic.MusicPages[0].PositionAndShape.BorderBottom * 10.0 * this.zoom; + this.drawer.clear(); this.drawer.resize(width, height); this.drawer.scale(this.zoom); + // clear and fill with background color + this.drawer.clear(0, 0, width, height); + // Finally, draw this.drawer.drawSheet(this.graphic); + // Update the cursor position this.cursor.update(); }