Source: tiny/transitions/Transition.js

import Point from '../core/math/Point';
import Graphics from '../core/graphics/Graphics';
import Container from '../core/display/Container';
import { WIN_SIZE } from '../core/const';
import * as ActionInterval from '../actions/ActionInterval';
import Action from '../actions/Action';
import { scale, point } from '../../utils';

/**
 * 各种转场
 *
 * 内置的所有转场如下表:
 *
 * | 转场名 | 描述
 * | :--: | :--
 * | FadeColor | 颜色过渡
 * | FadeWhite | 白色过渡
 * | ProgressH | 横向进度
 * | ProgressV | 纵向进度
 * | ProgressInOut | 内=>外扩散
 * | ProgressOutIn | 外=>内扩散
 * | ProgressRadialCW | 顺时针射线
 * | ProgressRadialCCW | 逆时针射线
 * | MoveInL | 左侧移入
 * | MoveInR | 右侧移入
 * | MoveInT | 头部移入
 * | MoveInB | 底部移入
 * | SlideInL | 左=>右滑动
 * | SlideInR | 右=>左滑动
 * | SlideInT | 头=>底滑动
 * | SlideInB | 底=>头滑动
 *
 * @example
 * var app = new Tiny.Application()
 * app.replaceScene(sceneName, 'MoveInL', 300);
 *
 * @class
 * @memberof Tiny
 */
export default class Transition {
  /**
   *
   * @param {Tiny.DisplayObject} stage
   * @param {Tiny.DisplayObject} scene
   * @param {number} duration
   */
  constructor(stage, scene, duration) {
    this.stage = stage;
    this.scene = scene;
    this.duration = duration || 600;

    /**
     * Fired when Transition is end.
     *
     * @example
     * // 为了保证性能,转场时会进行舞台中显示对象的销毁和重新创建,故场景中的 Action 需要监听 transitionend 后执行
     * sceneName.on('transitionend', function(){
     *  sprite.runAction(Tiny.RepeatForever(action));
     * });
     * app.replaceScene(sceneName, 'SlideInR');
     *
     * @protected
     * @event Tiny.Transition#transitionend
     * @param {Tiny.Container} Container - 进行转场的场景
     */
  }

  /**
   *
   * @param color
   * @private
   */
  Fade(color) {
    const self = this;
    const fadeOutAction = ActionInterval.FadeOut(this.duration);
    const fadeInAction = ActionInterval.FadeIn(this.duration);

    const g = new Graphics();
    g.beginFill(color || 0x000000);
    g.drawRect(0, 0, WIN_SIZE.width, WIN_SIZE.height);
    g.endFill();
    g.setOpacity(0);

    self.stage.addChild(g);

    fadeInAction.onComplete = function() {
      self.stage.removeChildren();
      self.stage.addChild(self.scene);
      self.stage.addChild(g);
      self.scene.emit('transitionend');
      g.runAction(fadeOutAction);
    };

    g.runAction(fadeInAction);
  }

  /**
   *
   */
  FadeWhite() {
    this.Fade(0xFFFFFF);
  }

  /**
   * @example
   * var app = new Tiny.Application()
   * app.replaceScene(sceneName, 'FadeColor', 500, 0xFF0000);
   */
  FadeColor(arg) {
    this.Fade(arg[0]);
  }

  /**
   * @private
   */
  Progress(action, g) {
    const self = this;

    self.stage.addChild(self.scene);
    self.stage.addChild(g);

    self.scene.mask = g;

    // self.stage.children.forEach(function (child) {
    //     child.mask = g;
    // });

    action.onComplete = function() {
      self.scene.mask = null;
      self.stage.removeChildren();
      self.stage.addChild(self.scene);
      self.scene.emit('transitionend');
    };

    g.runAction(action);
  }

  /**
   *
   */
  ProgressH() {
    const moveToAction = ActionInterval.MoveTo(this.duration, { x: WIN_SIZE.width });

    const g = new Graphics();
    g.beginFill(0xFFFFFF);
    g.drawRect(-WIN_SIZE.width, 0, WIN_SIZE.width, WIN_SIZE.height);
    g.endFill();

    this.Progress(moveToAction, g);
  }

  /**
   *
   */
  ProgressV() {
    const moveToAction = ActionInterval.MoveTo(this.duration, { y: WIN_SIZE.height });

    const g = new Graphics();
    g.beginFill(0xFFFFFF);
    g.drawRect(0, -WIN_SIZE.height, WIN_SIZE.width, WIN_SIZE.height);
    g.endFill();

    this.Progress(moveToAction, g);
  }

  /**
   *
   */
  ProgressInOut() {
    const scaleToAction = ActionInterval.ScaleTo(this.duration, scale(WIN_SIZE.width, WIN_SIZE.height));

    const g = new Graphics();
    g.beginFill(0xFFFFFF);
    g.drawRect(0, 0, 1, 1);
    g.endFill();
    g.setPosition(WIN_SIZE.width / 2, WIN_SIZE.height / 2);
    g.setPivot(0.5);

    this.Progress(scaleToAction, g);
  }

  /**
   *
   */
  ProgressOutIn() {
    const self = this;
    const scaleToAction = ActionInterval.ScaleTo(this.duration, scale(0));
    const moveToAction = ActionInterval.MoveTo(this.duration, point(WIN_SIZE.width / 2, WIN_SIZE.height / 2));

    const g = new Graphics();
    g.beginFill(0xFFFFFF);
    g.drawRect(0, 0, WIN_SIZE.width, WIN_SIZE.height);
    g.endFill();
    g.setPivot(0.5);

    const container = new Container();
    self.stage.children.forEach(function(child) {
      container.addChild(child);
    });
    container.mask = g;
    self.stage.removeChildren();
    self.stage.addChild(self.scene);
    self.stage.addChild(container);
    self.stage.addChild(g);
    self.scene.emit('transitionend');

    scaleToAction.onComplete = function() {
      container.mask = null;
      self.stage.removeChild(container);
      self.stage.removeChild(g);
    };

    g.runAction([scaleToAction, moveToAction]);
  }

  /**
   * @private
   */
  ProgressRadial(ccw) {
    const rotateXY = function(x, y, angle) {
      let rad = Math.PI * angle / 180;

      if (ccw) {
        rad = -rad;
      }

      const cosVal = Math.cos(rad);
      const sinVal = Math.sin(rad);
      return new Point(cosVal * x - sinVal * y, sinVal * x + cosVal * y);
    };
    const computeMaskPolygon = function(x, y, radius, angle) {
      while (angle < 0) {
        angle += 360;
      }
      angle %= 360;

      const delta = rotateXY(0, -2 * radius, angle);
      let a270 = 270;
      let a90 = 90;
      const pts = [new Point(x, y - 2 * radius), new Point(x, y), new Point(x + delta.x, y + delta.y)];

      if (ccw) {
        a270 = 90;
        a90 = 270;
        pts.reverse();
      }

      if (angle > a270) {
        pts.push(new Point(x - 2 * radius, y));
      }
      if (angle > 180) {
        pts.push(new Point(x, y + 2 * radius));
      }
      if (angle > a90) {
        pts.push(new Point(x + 2 * radius, y));
      }

      return pts;
    };

    const centerX = WIN_SIZE.width / 2;
    const centerY = WIN_SIZE.height / 2;
    const radius = Math.max(WIN_SIZE.width, WIN_SIZE.height);

    const g = new Graphics();

    const updatePieMask = function(angle) {
      g.clear();
      const pts = computeMaskPolygon(centerX, centerY, radius, angle);
      g.beginFill(0xFFFFFF);
      g.moveTo(pts[0].x, pts[0].y);
      for (let i = 1; i < pts.length; ++i) {
        g.lineTo(pts[i].x, pts[i].y);
      }
      g.lineTo(pts[0].x, pts[0].y);
      g.endFill();
    };

    const action = new Action(this.duration, { angle: 360 });
    action.yoyo = false;
    action.repeatTimes = 0;
    action.onUpdate = function(tween, object) {
      updatePieMask(~~tween.angle);
    };

    this.Progress(action, g);
  }

  /**
   *
   */
  ProgressRadialCW() {
    this.ProgressRadial(false);
  }

  /**
   *
   */
  ProgressRadialCCW() {
    this.ProgressRadial(true);
  }

  /**
   * @private
   */
  MoveIn() {
    const self = this;
    const action = ActionInterval.MoveTo(this.duration, new Point());

    self.stage.addChild(self.scene);

    action.onComplete = function() {
      self.stage.removeChildren();
      self.stage.addChild(self.scene);
      self.scene.emit('transitionend');
    };

    self.scene.runAction(action);
  }

  /**
   *
   */
  MoveInL() {
    this.scene.setPositionX(-WIN_SIZE.width);
    this.MoveIn();
  }

  /**
   *
   */
  MoveInR() {
    this.scene.setPositionX(WIN_SIZE.width);
    this.MoveIn();
  }

  /**
   *
   */
  MoveInT() {
    this.scene.setPositionY(-WIN_SIZE.height);
    this.MoveIn();
  }

  /**
   *
   */
  MoveInB() {
    this.scene.setPositionY(WIN_SIZE.height);
    this.MoveIn();
  }

  /**
   * @private
   */
  SlideIn(x, y) {
    const self = this;
    const container = new Container();
    self.stage.children.forEach(function(child) {
      container.addChild(child);
    });
    self.stage.removeChildren();

    container.addChild(self.scene);

    self.scene.setPosition(x, y);
    self.stage.addChild(container);
    const action = ActionInterval.MoveTo(this.duration, { x: -x, y: -y });

    action.onComplete = function() {
      self.stage.removeChildren();
      self.scene.setPosition(0);
      self.stage.addChild(self.scene);
      self.scene.emit('transitionend');
    };

    container.runAction(action);
  }

  /**
   *
   */
  SlideInL() {
    this.SlideIn(-WIN_SIZE.width, 0);
  }

  /**
   *
   */
  SlideInR() {
    this.SlideIn(WIN_SIZE.width, 0);
  }

  /**
   *
   */
  SlideInT() {
    this.SlideIn(0, -WIN_SIZE.height);
  }

  /**
   *
   */
  SlideInB() {
    this.SlideIn(0, WIN_SIZE.height);
  }
}
Documentation generated by JSDoc 3.4.3 on Fri Jul 09 2021 19:32:26 GMT+0800 (CST)