Skip to content

Commit ace7f9f

Browse files
committed
Add IntersectionObserver for initial load and lazy loading
1 parent 92ebca4 commit ace7f9f

File tree

4 files changed

+23
-76
lines changed

4 files changed

+23
-76
lines changed

src/CoreSettings.ts

-7
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,6 @@ export class CoreSettings {
3636
*/
3737
public tracks: unknown = null;
3838

39-
/**
40-
* Gets or sets the interval in which alphaTab should check whether the
41-
* target element for rendering is already visible.
42-
* @target web
43-
*/
44-
public visibilityCheckInterval: number = 500;
45-
4639
/**
4740
* Gets or sets whether lazy loading for displayed elements is enabled.
4841
*/

src/generated/CoreSettingsSerializer.ts

-6
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ export class CoreSettingsSerializer {
2828
o.set("tex", obj.tex);
2929
/*@target web*/
3030
o.set("tracks", obj.tracks);
31-
/*@target web*/
32-
o.set("visibilityCheckInterval", obj.visibilityCheckInterval);
3331
o.set("enableLazyLoading", obj.enableLazyLoading);
3432
o.set("engine", obj.engine);
3533
o.set("logLevel", (obj.logLevel as number));
@@ -59,10 +57,6 @@ export class CoreSettingsSerializer {
5957
case "tracks":
6058
obj.tracks = (v as unknown);
6159
return true;
62-
/*@target web*/
63-
case "visibilitycheckinterval":
64-
obj.visibilityCheckInterval = (v as number);
65-
return true;
6660
case "enablelazyloading":
6761
obj.enableLazyLoading = (v as boolean);
6862
return true;

src/platform/javascript/BrowserUiFacade.ts

+23-61
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,11 @@ export class BrowserUiFacade implements IUiFacade<unknown> {
3434
private _api!: AlphaTabApiBase<unknown>;
3535
private _contents: string | null = null;
3636
private _file: string | null = null;
37-
private _visibilityCheckIntervalId: number = 0;
38-
private _visibilityCheckInterval: number = 0;
3937
private _totalResultCount: number = 0;
4038
private _initialTrackIndexes: number[] | null = null;
39+
private _intersectionObserver: IntersectionObserver;
4140

42-
private _rootContainerBecameVisible: IEventEmitter = new EventEmitter();
43-
public rootContainerBecameVisible: IEventEmitter;
41+
public rootContainerBecameVisible: IEventEmitter = new EventEmitter();
4442
public canRenderChanged: IEventEmitter = new EventEmitter();
4543

4644
public get resizeThrottle(): number {
@@ -61,7 +59,7 @@ export class BrowserUiFacade implements IUiFacade<unknown> {
6159
}
6260

6361
let isAnyNotLoaded = false;
64-
for(const checker of this._fontCheckers.values()) {
62+
for (const checker of this._fontCheckers.values()) {
6563
if (!checker.isFontLoaded) {
6664
isAnyNotLoaded = true;
6765
}
@@ -88,29 +86,25 @@ export class BrowserUiFacade implements IUiFacade<unknown> {
8886
this.areWorkersSupported = 'Worker' in window;
8987
Environment.bravuraFontChecker.fontLoaded.on(this.onFontLoaded.bind(this));
9088

91-
this.rootContainerBecameVisible = {
92-
on: (value: any) => {
93-
if (this.rootContainer.isVisible) {
94-
value();
95-
} else {
96-
this._rootContainerBecameVisible.on(value);
97-
98-
if (this._visibilityCheckIntervalId === 0) {
99-
this._visibilityCheckIntervalId = window.setInterval(() => {
100-
if (this._api.container.isVisible) {
101-
window.clearInterval(this._visibilityCheckIntervalId);
102-
this._visibilityCheckIntervalId = 0;
103-
(this._rootContainerBecameVisible as EventEmitter).trigger();
104-
}
105-
}, this._visibilityCheckInterval);
106-
}
89+
this._intersectionObserver = new IntersectionObserver(this.onElementVisibilityChanged.bind(this), {
90+
threshold: [0, 0.01, 1]
91+
});
92+
this._intersectionObserver.observe(rootElement);
93+
}
94+
95+
private onElementVisibilityChanged(entries: IntersectionObserverEntry[]) {
96+
for (const e of entries) {
97+
if (e.isIntersecting) {
98+
const htmlElement = e.target as HTMLElement;
99+
if (htmlElement === (this.rootContainer as HtmlElementContainer).element) {
100+
(this.rootContainerBecameVisible as EventEmitter).trigger();
101+
this._intersectionObserver.unobserve((this.rootContainer as HtmlElementContainer).element);
102+
} else if ('svg' in htmlElement.dataset) {
103+
this.replacePlaceholder(htmlElement, htmlElement.dataset['svg'] as string);
104+
this._intersectionObserver.unobserve(htmlElement);
107105
}
108-
},
109-
110-
off: (value: any) => {
111-
this._rootContainerBecameVisible.off(value);
112106
}
113-
};
107+
}
114108
}
115109

116110
public createWorkerRenderer(): IScoreRenderer {
@@ -132,10 +126,6 @@ export class BrowserUiFacade implements IUiFacade<unknown> {
132126
settings.setSongBookModeSettings();
133127
}
134128
api.settings = settings;
135-
if (settings.core.engine === 'default' || settings.core.engine === 'svg') {
136-
api.container.scroll.on(this.showSvgsInViewPort.bind(this));
137-
api.container.resize.on(this.showSvgsInViewPort.bind(this));
138-
}
139129
this.setupFontCheckers(settings);
140130

141131
this._initialTrackIndexes = this.parseTracks(settings.core.tracks);
@@ -147,8 +137,6 @@ export class BrowserUiFacade implements IUiFacade<unknown> {
147137
}
148138
this.createStyleElement(settings);
149139
this._file = settings.core.file;
150-
151-
this._visibilityCheckInterval = settings.core.visibilityCheckInterval;
152140
}
153141

154142
private setupFontCheckers(settings: Settings): void {
@@ -284,28 +272,6 @@ export class BrowserUiFacade implements IUiFacade<unknown> {
284272
});
285273
}
286274

287-
private showSvgsInViewPort(): void {
288-
let placeholders: NodeList = (this._api.canvasElement as HtmlElementContainer).element.querySelectorAll(
289-
'[data-lazy=true]'
290-
);
291-
for (let i: number = 0; i < placeholders.length; i++) {
292-
let placeholder: HTMLElement = placeholders.item(i) as HTMLElement;
293-
if (this.isElementInViewPort(placeholder)) {
294-
this.replacePlaceholder(placeholder, (placeholder as any)['svg']);
295-
}
296-
}
297-
}
298-
299-
public isElementInViewPort(element: HTMLElement): boolean {
300-
let rect: DOMRect = element.getBoundingClientRect();
301-
return (
302-
rect.top + rect.height >= 0 &&
303-
rect.top <= window.innerHeight &&
304-
rect.left + rect.width >= 0 &&
305-
rect.left <= window.innerWidth
306-
);
307-
}
308-
309275
private createStyleElement(settings: Settings): void {
310276
let elementDocument: HTMLDocument = (this._api.container as HtmlElementContainer).element.ownerDocument!;
311277
Environment.createStyleElement(elementDocument, settings.core.fontDirectory);
@@ -402,10 +368,6 @@ export class BrowserUiFacade implements IUiFacade<unknown> {
402368
while (canvasElement.childElementCount > this._totalResultCount) {
403369
canvasElement.removeChild(canvasElement.lastChild!);
404370
}
405-
// directly show the elements in the viewport once we're done.
406-
if (this._api.settings.core.enableLazyLoading) {
407-
this.showSvgsInViewPort();
408-
}
409371
} else {
410372
let body: unknown = renderResult.renderResult;
411373
if (typeof body === 'string') {
@@ -419,11 +381,11 @@ export class BrowserUiFacade implements IUiFacade<unknown> {
419381
placeholder.style.width = renderResult.width + 'px';
420382
placeholder.style.height = renderResult.height + 'px';
421383
placeholder.style.display = 'inline-block';
422-
if (!this._api.settings.core.enableLazyLoading || this.isElementInViewPort(placeholder)) {
384+
if (!this._api.settings.core.enableLazyLoading) {
423385
this.replacePlaceholder(placeholder, body);
424386
} else {
425-
(placeholder as any)['svg'] = body;
426-
placeholder.setAttribute('data-lazy', 'true');
387+
placeholder.dataset['svg'] = body;
388+
this._intersectionObserver.observe(placeholder);
427389
}
428390
} else {
429391
if (this._totalResultCount < canvasElement.childElementCount) {

test/model/JsonConverter.test.ts

-2
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ describe('JsonConverterTest', () => {
9494
expected.core.tex = true;
9595
/**@target web*/
9696
expected.core.tracks = [1, 2, 3];
97-
/**@target web*/
98-
expected.core.visibilityCheckInterval = 4711;
9997

10098
expected.core.enableLazyLoading = false;
10199
expected.core.engine = "engine";

0 commit comments

Comments
 (0)