From b83db8a7d72dff286770b2f129e774034df4086d Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 10 Jan 2021 21:28:10 +0100 Subject: [PATCH] Added usage of resize observer if available. --- package-lock.json | 6 +++ package.json | 1 + .../WinForms/ControlContainer.cs | 12 ----- .../Wpf/FrameworkElementContainer.cs | 12 ----- src/Environment.ts | 6 +++ src/platform/IContainer.ts | 5 -- .../javascript/HtmlElementContainer.ts | 47 ++++++++++++------- .../javascript/ResizeObserverPolyfill.ts | 41 ++++++++++++++++ 8 files changed, 85 insertions(+), 45 deletions(-) create mode 100644 src/platform/javascript/ResizeObserverPolyfill.ts diff --git a/package-lock.json b/package-lock.json index 211bad9b9..8c393c362 100644 --- a/package-lock.json +++ b/package-lock.json @@ -152,6 +152,12 @@ "integrity": "sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==", "dev": true }, + "@types/resize-observer-browser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@types/resize-observer-browser/-/resize-observer-browser-0.1.5.tgz", + "integrity": "sha512-8k/67Z95Goa6Lznuykxkfhq9YU3l1Qe6LNZmwde1u7802a3x8v44oq0j91DICclxatTr0rNnhXx7+VTIetSrSQ==", + "dev": true + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", diff --git a/package.json b/package.json index b3f569802..9ee92f93c 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "devDependencies": { "@rollup/plugin-commonjs": "^17.0.0", "@types/jasmine": "^3.6.2", + "@types/resize-observer-browser": "^0.1.5", "concurrently": "^5.3.0", "cors": "^2.8.5", "fs-extra": "^9.0.1", diff --git a/src.csharp/AlphaTab.Windows/WinForms/ControlContainer.cs b/src.csharp/AlphaTab.Windows/WinForms/ControlContainer.cs index e7d30cc9b..ea7defd03 100644 --- a/src.csharp/AlphaTab.Windows/WinForms/ControlContainer.cs +++ b/src.csharp/AlphaTab.Windows/WinForms/ControlContainer.cs @@ -12,17 +12,6 @@ public ControlContainer(Control control) { Control = control; - Scroll = new DelegatedEventEmitter( - value => - { - if (Control is ScrollableControl scroll) - { - scroll.Scroll += (sender, args) => value(); - } - }, - value => { } - ); - Resize = new DelegatedEventEmitter( value => { Control.Resize += (sender, args) => value(); }, value => { } @@ -127,7 +116,6 @@ public void Clear() Control.Controls.Clear(); } - public IEventEmitter Scroll { get; set; } public IEventEmitter Resize { get; set; } public IEventEmitterOfT MouseDown { get; set; } public IEventEmitterOfT MouseMove { get; set; } diff --git a/src.csharp/AlphaTab.Windows/Wpf/FrameworkElementContainer.cs b/src.csharp/AlphaTab.Windows/Wpf/FrameworkElementContainer.cs index d47b9670c..cec8eb998 100644 --- a/src.csharp/AlphaTab.Windows/Wpf/FrameworkElementContainer.cs +++ b/src.csharp/AlphaTab.Windows/Wpf/FrameworkElementContainer.cs @@ -14,17 +14,6 @@ public FrameworkElementContainer(FrameworkElement control) { Control = control; - Scroll = new DelegatedEventEmitter( - value => - { - if (Control is ScrollViewer scroll) - { - scroll.ScrollChanged += (sender, args) => value(); - } - }, - value => { } - ); - Resize = new DelegatedEventEmitter( value => { Control.SizeChanged += (sender, args) => value(); }, value => { } @@ -153,7 +142,6 @@ public void Clear() } } - public IEventEmitter Scroll { get; set; } public IEventEmitter Resize { get; set; } public IEventEmitterOfT MouseDown { get; set; } public IEventEmitterOfT MouseMove { get; set; } diff --git a/src/Environment.ts b/src/Environment.ts index d9c43eb7f..b7973c31d 100644 --- a/src/Environment.ts +++ b/src/Environment.ts @@ -53,6 +53,7 @@ import { FontLoadingChecker } from '@src/util/FontLoadingChecker'; import { Logger } from '@src/Logger'; import { LeftHandTapEffectInfo } from './rendering/effects/LeftHandTapEffectInfo'; import { CapellaImporter } from './importer/CapellaImporter'; +import { ResizeObserverPolyfill } from './platform/javascript/ResizeObserverPolyfill'; export class LayoutEngineFactory { public readonly vertical: boolean; @@ -450,6 +451,11 @@ export class Environment { Environment.registerJQueryPlugin(); if (!Environment.isRunningInWorker) { Environment.HighDpiFactor = window.devicePixelRatio; + // ResizeObserver API does not yet exist so long on Safari (only start 2020 with iOS Safari 13.7 and Desktop 13.1) + // so we better add a polyfill for it + if(!('ResizeObserver' in globalThis)) { + (globalThis as any).ResizeObserver = ResizeObserverPolyfill; + } } else { AlphaTabWebWorker.init(); AlphaSynthWebWorker.init(); diff --git a/src/platform/IContainer.ts b/src/platform/IContainer.ts index 53969089f..85a433c7d 100644 --- a/src/platform/IContainer.ts +++ b/src/platform/IContainer.ts @@ -63,11 +63,6 @@ export interface IContainer { */ clear(): void; - /** - * This event occurs when a scroll on the control happened. - */ - scroll: IEventEmitter; - /** * This event occurs when the control was resized. */ diff --git a/src/platform/javascript/HtmlElementContainer.ts b/src/platform/javascript/HtmlElementContainer.ts index 5641e0b23..da04edd8f 100644 --- a/src/platform/javascript/HtmlElementContainer.ts +++ b/src/platform/javascript/HtmlElementContainer.ts @@ -2,11 +2,23 @@ import { IEventEmitter, IEventEmitterOfT } from '@src/EventEmitter'; import { IContainer } from '@src/platform/IContainer'; import { IMouseEventArgs } from '@src/platform/IMouseEventArgs'; import { BrowserMouseEventArgs } from '@src/platform/javascript/BrowserMouseEventArgs'; +import { Lazy } from '@src/util/Lazy'; /** * @target web */ export class HtmlElementContainer implements IContainer { + private static resizeObserver: Lazy = new Lazy(() => new ResizeObserver((entries) => { + for (const e of entries) { + let evt = new CustomEvent('resize', { + detail: e + }); + e.target.dispatchEvent(evt); + } + })); + + private _resizeListeners: number = 0; + public get top(): number { return parseFloat(this.element.style.top); } @@ -113,21 +125,29 @@ export class HtmlElementContainer implements IContainer { } }; - this.scroll = { - on: (value: any) => { - window.addEventListener('scroll', value, true); - }, - off: (value: any) => { - window.removeEventListener('scroll', value, true); - } - }; - this.resize = { on: (value: any) => { - window.addEventListener('resize', value, true); + if (this._resizeListeners === 0) { + HtmlElementContainer.resizeObserver.value.observe(this.element); + } + this.element.addEventListener( + 'resize', + value, + true + ); + this._resizeListeners++; }, off: (value: any) => { - window.removeEventListener('resize', value, true); + this.element.removeEventListener( + 'resize', + value, + true + ); + this._resizeListeners--; + if (this._resizeListeners <= 0) { + this._resizeListeners = 0; + HtmlElementContainer.resizeObserver.value.unobserve(this.element); + } } }; } @@ -142,11 +162,6 @@ export class HtmlElementContainer implements IContainer { this.element.style.left = x + 'px'; } - /** - * This event occurs when a scroll on the control happened. - */ - public scroll: IEventEmitter; - /** * This event occurs when the control was resized. */ diff --git a/src/platform/javascript/ResizeObserverPolyfill.ts b/src/platform/javascript/ResizeObserverPolyfill.ts new file mode 100644 index 000000000..3b04a3c12 --- /dev/null +++ b/src/platform/javascript/ResizeObserverPolyfill.ts @@ -0,0 +1,41 @@ +/** + * A very basic polyfill of the ResizeObserver which triggers + * a the callback on window resize for all registered targets. + * @target web + */ +export class ResizeObserverPolyfill { + private _callback: ResizeObserverCallback; + private _targets = new Set(); + + public constructor(callback: ResizeObserverCallback) { + this._callback = callback; + window.addEventListener('resize', this.onWindowResize.bind(this), false); + } + + public observe(target: Element) { + this._targets.add(target); + } + + public unobserve(target: Element) { + this._targets.delete(target); + } + + public disconnect() { + this._targets.clear(); + } + + + private onWindowResize() { + const entries: ResizeObserverEntry[] = []; + for (const t of this._targets) { + entries.push({ + target: t, + // not used by alphaTab + contentRect: undefined!, + borderBoxSize: undefined!, + contentBoxSize: [] + }); + } + this._callback(entries, this); + } +} \ No newline at end of file