swimlane/ngx-ui

View on GitHub
projects/swimlane/ngx-ui/src/lib/components/loading/loading.service.ts

Summary

Maintainability
A
25 mins
Test Coverage
import { Injectable, ComponentRef } from '@angular/core';

import { InjectionService } from '../../services/injection/injection.service';
import { LoadingComponent } from './loading.component';

@Injectable({
  providedIn: 'root'
})
export class LoadingService {
  threshold = 250;

  set progress(val: number) {
    if (this.instance) {
      this.instance.progress = val;
    }

    this._progress = val;
  }

  get progress(): number {
    return this._progress;
  }

  get count(): number {
    return this._count;
  }

  private get instance() {
    if (this.component) return this.component.instance;
  }

  private _count = 0;
  private timeout: any;
  private component: ComponentRef<LoadingComponent>;
  private _progress = 0;

  constructor(private readonly injectionService: InjectionService) {}

  start(autoIncrement = true): void {
    this.create();
    this._count++;

    if (autoIncrement) {
      clearTimeout(this.timeout);

      const fn = () => {
        this.increment();
        if (this.progress < 100) {
          this.timeout = setTimeout(fn, this.threshold);
        } else {
          this.complete();
        }
      };

      this.timeout = setTimeout(fn, this.threshold);
    }
  }

  stop(): void {
    this._count--;
    clearTimeout(this.timeout);
  }

  reset(num = 0): void {
    this.progress = num;
  }

  complete(all = false): void {
    this._count--;

    if (this.count <= 0 || all) {
      this.progress = 100;
      this._count = 0;

      setTimeout(() => {
        this.hide();
        this.progress = 0;
      }, this.threshold * 2);
    }
  }

  hide(): void {
    this.stop();

    if (this.instance) {
      this.instance.visible = false;
    }
  }

  private create(): ComponentRef<LoadingComponent> {
    if (!this.component) {
      this.component = this.injectionService.appendComponent(LoadingComponent);
    }

    this.instance.visible = true;
    this.instance.progress = this.progress;

    return this.component;
  }

  private increment(): void {
    if (this.progress >= 100) return;

    // inspired by angular-loading-bar
    // https://github.com/chieffancypants/angular-loading-bar
    const stat = this.progress / 100;
    let rnd = 0;

    if (stat >= 0 && stat < 0.25) {
      // Start out between 3 - 6% increments
      rnd = (Math.random() * (5 - 3 + 1) + 3) / 100;
    } else if (stat >= 0.25 && stat < 0.65) {
      // increment between 0 - 3%
      rnd = (Math.random() * 3) / 100;
    } else if (stat >= 0.65 && stat < 0.9) {
      // increment between 0 - 2%
      rnd = (Math.random() * 2) / 100;
    } else {
      // finally, increment it .5 %
      // after 99%, don't increment:
      rnd = 0.005;
    }

    this.progress = (stat + rnd) * 100;
  }
}