diff --git a/package-lock.json b/package-lock.json index 8c393c362..7ff529f64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@coderline/alphatab", - "version": "1.2.0", + "version": "1.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9ee92f93c..eb806bd82 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@coderline/alphatab", - "version": "1.2.0", + "version": "1.2.1", "description": "alphaTab is a music notation and guitar tablature rendering library", "keywords": [ "guitar", diff --git a/src.csharp/Directory.Build.props b/src.csharp/Directory.Build.props index 59bef48db..083b61b43 100644 --- a/src.csharp/Directory.Build.props +++ b/src.csharp/Directory.Build.props @@ -2,15 +2,15 @@ portable true - 1.1.0 - 1.1.0.0 + 1.2.1 + 1.2.1.0 $(AssemblyVersion) Danielku15 CoderLine AlphaTab en alphaTab is a cross platform music notation and guitar tablature rendering library. - Copyright © 2020, Daniel Kuschny and Contributors + Copyright © 2021, Daniel Kuschny and Contributors MPL-2.0 https://www.alphatab.net https://github.com/CoderLine/alphaTab diff --git a/src/Environment.ts b/src/Environment.ts index b7973c31d..e66c26f37 100644 --- a/src/Environment.ts +++ b/src/Environment.ts @@ -54,6 +54,7 @@ import { Logger } from '@src/Logger'; import { LeftHandTapEffectInfo } from './rendering/effects/LeftHandTapEffectInfo'; import { CapellaImporter } from './importer/CapellaImporter'; import { ResizeObserverPolyfill } from './platform/javascript/ResizeObserverPolyfill'; +import { IntersectionObserverPolyfill } from './platform/javascript/IntersectionObserverPolyfill'; export class LayoutEngineFactory { public readonly vertical: boolean; @@ -124,6 +125,9 @@ export class Environment { vertical-align: top; overflow: visible; } + .at-surface-svg text { + dominant-baseline: central; + } .at { font-family: 'alphaTab'; speak: none; @@ -456,6 +460,11 @@ export class Environment { if(!('ResizeObserver' in globalThis)) { (globalThis as any).ResizeObserver = ResizeObserverPolyfill; } + // IntersectionObserver API does not on older iOS versions + // so we better add a polyfill for it + if (!('IntersectionObserver' in Environment.globalThis)) { + (Environment.globalThis as any).IntersectionObserver = IntersectionObserverPolyfill; + } } else { AlphaTabWebWorker.init(); AlphaSynthWebWorker.init(); @@ -463,4 +472,4 @@ export class Environment { } } -Environment.platformInit(); \ No newline at end of file +Environment.platformInit(); diff --git a/src/platform/javascript/IntersectionObserverPolyfill.ts b/src/platform/javascript/IntersectionObserverPolyfill.ts new file mode 100644 index 000000000..bd294690a --- /dev/null +++ b/src/platform/javascript/IntersectionObserverPolyfill.ts @@ -0,0 +1,64 @@ +/** + * A polyfill of the InsersectionObserver + * @target web + */ +export class IntersectionObserverPolyfill { + private _callback: IntersectionObserverCallback; + private _elements: HTMLElement[] = []; + + public constructor(callback: IntersectionObserverCallback) { + let timer: any = null; + const oldCheck = this._check.bind(this); + this._check = () => { + if (!timer) { + timer = setTimeout(() => { + oldCheck(); + timer = null; + }, 100); + } + }; + + this._callback = callback; + + window.addEventListener('resize', this._check, true); + document.addEventListener('scroll', this._check, true); + } + + public observe(target: HTMLElement) { + if (this._elements.indexOf(target) >= 0) { + return; + } + this._elements.push(target); + this._check(); + } + + public unobserve(target: HTMLElement) { + this._elements = this._elements.filter(item => { + return item != target; + }); + }; + + private _check() { + const entries: IntersectionObserverEntry[] = []; + this._elements.forEach(element => { + const rect = element.getBoundingClientRect(); + const isVisible = ( + rect.top + rect.height >= 0 && + rect.top <= window.innerHeight && + rect.left + rect.width >= 0 && + rect.left <= window.innerWidth + ); + + if (isVisible) { + entries.push({ + target: element, + isIntersecting: true + } as any); + } + }); + + if (entries.length) { + this._callback(entries, this as any); + } + } +} \ No newline at end of file diff --git a/src/platform/svg/SvgCanvas.ts b/src/platform/svg/SvgCanvas.ts index 938dda354..75e6d7803 100644 --- a/src/platform/svg/SvgCanvas.ts +++ b/src/platform/svg/SvgCanvas.ts @@ -23,7 +23,7 @@ export abstract class SvgCanvas implements ICanvas { public beginRender(width: number, height: number): void { this.buffer = `\n`; + }px" class="at-surface-svg">\n`; this._currentPath = ''; this._currentPathIsEmpty = true; this.textBaseline = TextBaseline.Top; diff --git a/src/rendering/glyphs/ChordDiagramGlyph.ts b/src/rendering/glyphs/ChordDiagramGlyph.ts index 7ea5dc2f7..7e9e2f489 100644 --- a/src/rendering/glyphs/ChordDiagramGlyph.ts +++ b/src/rendering/glyphs/ChordDiagramGlyph.ts @@ -23,23 +23,24 @@ export class ChordDiagramGlyph extends EffectGlyph { public doLayout(): void { super.doLayout(); + const scale = this.scale; let res: RenderingResources = this.renderer.resources; - this._textRow = res.effectFont.size * 1.5; - this._fretRow = res.effectFont.size * 1.5; + this._textRow = res.effectFont.size * 1.5 * scale; + this._fretRow = res.effectFont.size * 1.5 * scale; if (this._chord.firstFret > 1) { - this._firstFretSpacing = ChordDiagramGlyph.FretSpacing * this.scale; + this._firstFretSpacing = ChordDiagramGlyph.FretSpacing * scale; } else { this._firstFretSpacing = 0; } this.height = this._textRow + this._fretRow + - (ChordDiagramGlyph.Frets - 1) * ChordDiagramGlyph.FretSpacing * this.scale + - 2 * ChordDiagramGlyph.Padding; + (ChordDiagramGlyph.Frets - 1) * ChordDiagramGlyph.FretSpacing * scale + + 2 * ChordDiagramGlyph.Padding * scale; this.width = this._firstFretSpacing + - (this._chord.staff.tuning.length - 1) * ChordDiagramGlyph.StringSpacing * this.scale + - 2 * ChordDiagramGlyph.Padding; + (this._chord.staff.tuning.length - 1) * ChordDiagramGlyph.StringSpacing * scale + + 2 * ChordDiagramGlyph.Padding * scale; } public paint(cx: number, cy: number, canvas: ICanvas): void { @@ -114,14 +115,14 @@ export class ChordDiagramGlyph extends EffectGlyph { info[1] = guitarString; } } - let y: number = cy + fret * fretSpacing + fretSpacing / 2 + 0.5; + let y: number = cy + fret * fretSpacing + fretSpacing / 2 + 0.5 * this.scale; let x: number = cx + (this._chord.strings.length - guitarString - 1) * stringSpacing; canvas.fillCircle(x, y, circleRadius); } } for(const [fret, strings] of barreLookup) { - let y: number = cy + fret * fretSpacing + fretSpacing / 2 + this.scale; + let y: number = cy + fret * fretSpacing + fretSpacing / 2 + 0.5 * this.scale; let xLeft: number = cx + (this._chord.strings.length - strings[1] - 1) * stringSpacing; let xRight: number = cx + (this._chord.strings.length - strings[0] - 1) * stringSpacing; canvas.fillRect(xLeft, y - circleRadius, xRight - xLeft, circleRadius * 2); diff --git a/src/rendering/glyphs/VoiceContainerGlyph.ts b/src/rendering/glyphs/VoiceContainerGlyph.ts index 04fd4ea02..a135e3d0d 100644 --- a/src/rendering/glyphs/VoiceContainerGlyph.ts +++ b/src/rendering/glyphs/VoiceContainerGlyph.ts @@ -26,7 +26,8 @@ export class VoiceContainerGlyph extends GlyphGroup { } public scaleToWidth(width: number): void { - let force: number = this.renderer.layoutingInfo.spaceToForce(width); + const scale = this.renderer.scale; + let force: number = this.renderer.layoutingInfo.spaceToForce(width / scale); this.scaleToForce(force); }