import Vex from "vexflow"; 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 {BackendType} from "../../../OpenSheetMusicDisplay/OSMDOptions"; import {GraphicalMusicPage} from "../GraphicalMusicPage"; import {EngravingRules} from "../EngravingRules"; export class VexFlowBackends { public static CANVAS: 0; public static RAPHAEL: 1; // this is currently unused in OSMD, and outdated in Vexflow. // maybe SVG should be 1? but this could be a breaking change if people use numbers (2) instead of names (.SVG). public static SVG: 2; public static VML: 3; // this is currently unused in OSMD, and outdated in Vexflow } export abstract class VexFlowBackend { /** The GraphicalMusicPage the backend is drawing from. Each backend only renders one GraphicalMusicPage, to which the coordinates are relative. */ public graphicalMusicPage: GraphicalMusicPage; protected rules: EngravingRules; public width: number; // read-only public height: number; // read-only public abstract initialize(container: HTMLElement, zoom: number): void; public getInnerElement(): HTMLElement { return this.inner; } public getCanvas(): HTMLElement { return this.canvas; } public abstract getCanvasSize(): number; public getRenderElement(): HTMLElement { //console.log("backend type: " + this.getVexflowBackendType()); let renderingHtmlElement: HTMLElement = this.canvas; // for SVGBackend if (this.getVexflowBackendType() === Vex.Flow.Renderer.Backends.CANVAS) { renderingHtmlElement = this.inner; // usage in removeFromContainer: // for SVG, this.canvas === this.inner, but for Canvas, removing this.canvas causes an error because it's not a child of container, // so we have to remove this.inner instead. } return renderingHtmlElement; } public getRenderer(): Vex.Flow.Renderer { return this.renderer; } public removeAllChildrenFromContainer(container: HTMLElement): void { while (container.children.length !== 0) { container.removeChild(container.children.item(0)); } } // note: removing single children to remove all is error-prone, because sometimes a random SVG-child remains. public removeFromContainer(container: HTMLElement): void { const htmlElementToRemove: HTMLElement = this.getRenderElement(); // only remove child if the container has this child, otherwise it will throw an error. for (let i: number = 0; i < container.children.length; i++) { if (container.children.item(i) === htmlElementToRemove) { container.removeChild(htmlElementToRemove); break; } } // there is unfortunately no built-in container.hasChild(child) method. } public abstract getContext(): Vex.IRenderContext; // public abstract setWidth(width: number): void; // public abstract setHeight(height: number): void; public abstract scale(k: number): void; public resize(width: number, height: number): void { this.renderer.resize(width, height); this.width = width; this.height = height; } public abstract clear(): void; public abstract translate(x: number, y: number): void; public abstract renderText(fontHeight: number, fontStyle: FontStyles, font: Fonts, text: string, heightInPixel: number, screenPosition: PointF2D, color?: string, fontFamily?: string): Node; /** * Renders a rectangle with the given style to the screen. * It is given in screen coordinates. * @param rectangle the rect in screen coordinates * @param layer is the current rendering layer. There are many layers on top of each other to which can be rendered. Not needed for now. * @param styleId the style id * @param alpha alpha value between 0 and 1 */ public abstract renderRectangle(rectangle: RectangleF2D, styleId: number, colorHex: string, alpha: number): Node; public abstract renderLine(start: PointF2D, stop: PointF2D, color: string, lineWidth: number): Node; public abstract renderCurve(points: PointF2D[]): void; public abstract getVexflowBackendType(): Vex.Flow.Renderer.Backends; /** The general type of backend: Canvas or SVG. * This is not used for now (only VexflowBackendType used), but it may be useful when we don't want to use a Vexflow class. */ public abstract getOSMDBackendType(): BackendType; protected renderer: Vex.Flow.Renderer; protected inner: HTMLElement; protected canvas: HTMLElement; }