import { isInDOM } from "../lib/utils"; import { CancellablePromise } from "../lib/polyfill"; export default class ProgressivePreloader { public preloader: HTMLDivElement = null; private circle: SVGCircleElement = null; private progress = 0; private promise: CancellablePromise = null; private tempID = 0; private detached = true; constructor(elem?: Element, private cancelable = true) { this.preloader = document.createElement('div'); this.preloader.classList.add('preloader-container'); this.preloader.innerHTML = `
`; if(cancelable) { this.preloader.innerHTML += ` `; } else { this.preloader.classList.add('preloader-swing'); } this.circle = this.preloader.firstElementChild.firstElementChild.firstElementChild as SVGCircleElement; if(elem) { this.attach(elem); } if(this.cancelable) { this.preloader.addEventListener('click', () => { if(this.promise && this.promise.cancel) { this.promise.cancel(); this.detach(); } }); } } public attach(elem: Element, reset = true, promise?: CancellablePromise) { if(promise) { this.promise = promise; let tempID = --this.tempID; promise.then(() => { if(tempID == this.tempID) { this.detach(); } }); promise.notify = (details: {done: number, total: number}) => { if(tempID != this.tempID) return; console.log('preloader download', promise, details); let percents = details.done / details.total * 100; this.setProgress(percents); }; } if(this.cancelable && reset) { this.setProgress(0); } this.detached = false; window.requestAnimationFrame(() => { if(this.detached) return; this.detached = false; elem.append(this.preloader); }); /* let isIn = isInDOM(this.preloader); if(isIn && this.progress != this.defaultProgress) { this.setProgress(this.defaultProgress); } elem.append(this.preloader); if(!isIn && this.progress != this.defaultProgress) { this.setProgress(this.defaultProgress); } */ } public detach() { this.detached = true; if(this.preloader.parentElement) { window.requestAnimationFrame(() => { if(!this.detached) return; this.detached = true; if(this.preloader.parentElement) { this.preloader.parentElement.removeChild(this.preloader); } }); } } public setProgress(percents: number) { this.progress = percents; if(!isInDOM(this.circle)) { return; } if(percents == 0) { this.circle.style.strokeDasharray = ''; return; } let totalLength = this.circle.getTotalLength(); console.log('setProgress', (percents / 100 * totalLength)); this.circle.style.strokeDasharray = '' + Math.max(5, percents / 100 * totalLength) + ', 200'; } }