actor/base-actor.ts

import { ActorElement, AppearEvent, IActor, IStage } from '../common/types';
import { Subject } from 'rxjs';

/**
 * Stage 에 등록될 Actor.
 * 스테이지에 진입, 이탈 시 계속 알려주는 기본형.
 * @class BaseActor
 * @implements {IActor}
 */
export class BaseActor implements IActor {
  /**
   * @param element 옵저버에 등록되어야 하는 native element
   */
  constructor(element: ActorElement) {
    this.element = element;
  }

  /**
   * 옵저버에 등록될 native element
   */
  element: ActorElement;

  /**
   * 이벤트 Observable
   * @see https://rxjs-dev.firebaseapp.com/guide/subject
   */
  events: Subject<AppearEvent> = new Subject<AppearEvent>();

  /**
   * 해당 인스턴스가 등록된 스테이지
   */
  stage: IStage<BaseActor>;

  /**
   * 현재 진입 여부 상태
   */
  isAppear: boolean = null;

  /**
   * 해당 인스턴스를 관찰하는 스테이지를 연결
   * @param stage 스테이지
   */
  bind(stage: IStage<BaseActor>) {
    this.stage = stage;
  }

  /**
   * 진입, 이탈 등 이벤트 알림
   * @param type 이벤트 타입
   * @param [entry] 상태 변경시 관찰된 상태
   */
  dispatch(type: string, entry?: IntersectionObserverEntry) {
    this.events.next(
      new AppearEvent(type, {
        actor: this,
        entry,
      })
    );
  }

  /**
   * 스테이지 진입
   * @param [entry] 스테이지 진입시 관찰 상태
   */
  appear(entry?: IntersectionObserverEntry): void {
    if (this.isAppear === true) return;
    this.isAppear = true;
    this.dispatch(AppearEvent.APPEAR, entry);
  }

  /**
   * 스테이지 이탈
   * @param [entry] 스테이지 이탈시 관찰 상태
   */
  disappear(entry?: IntersectionObserverEntry): void {
    if (this.isAppear === false) return;
    this.isAppear = false;
    this.dispatch(AppearEvent.DISAPPEAR, entry);
  }

  /**
   * 파기
   */
  dispose() {
    if (this.stage) {
      this.stage.unobserve(this);
    }
  }
}