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);
}
}