コリスさんの 『[CSS]これから増えてきそうなMaterial Designにぴったり!気持ちいいアニメーションで表示させるモーダルコンテンツ』
ってやつを見て良いなと思ったので tmlib.js でも作ってみました!!
画面遷移とかにつかうと便利ですね♪
Demo
ボタンを押すとサークルに変形して画面いっぱいに広がります.
もう一度クリックすると元に戻ります.
Code
/*
* # tutorial - tmlib.js
* tmlib.js のチュートリアルです.
* http://phi-jp.github.io/tmlib.js/tutorial.html
*/
var SCREEN_WIDTH = 640; // スクリーン幅
var SCREEN_HEIGHT = 960; // スクリーン高さ
var SCREEN_CENTER_X = SCREEN_WIDTH/2; // スクリーン幅の半分
var SCREEN_CENTER_Y = SCREEN_HEIGHT/2; // スクリーン高さの半分
var ASSETS = {
"player": "http://jsrun.it/assets/s/A/3/j/sA3jL.png",
"bg": "http://jsrun.it/assets/a/G/5/Y/aG5YD.png",
};
// main
tm.main(function() {
// キャンバスアプリケーションを生成
var app = tm.display.CanvasApp("#world");
// リサイズ
app.resize(SCREEN_WIDTH, SCREEN_HEIGHT);
// ウィンドウにフィットさせる
app.fitWindow();
// ローダーで画像を読み込む
var loading = tm.ui.LoadingScene({
assets: ASSETS,
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT,
});
// 読み込み完了後に呼ばれるメソッドを登録
loading.onload = function() {
// メインシーンに入れ替える
var scene = MainScene();
app.replaceScene(scene);
};
// ローディングシーンに入れ替える
app.replaceScene(loading);
// 実行
app.run();
});
// シーンを定義
tm.define("MainScene", {
superClass: "tm.app.Scene",
init: function() {
this.superInit();
// モーフィングボタンを生成
var button = MorphingButton({
fillStyle: "hsl({0}, 60%, 50%)".format(Math.rand(0, 360)),
cornerRadius: 16,
fontSize: 48,
text: 'Button',
}).addChildTo(this);
button.setPosition(SCREEN_CENTER_X, SCREEN_CENTER_Y);
// 円が広がりきった際のイベント
button.oncircled = function() {
this.app.pushScene(TestScene());
// シーンが戻ってきたらボタンも戻す
this.one('resume', function() {
button.morphDefault();
});
}.bind(this);
button.onpointingover = function() {
this.app.element.style.cursor = 'pointer';
}.bind(this);
button.onpointingout = function() {
this.app.element.style.cursor = 'auto';
}.bind(this);
button.onpush = function() {
this.app.element.style.cursor = 'auto';
}.bind(this);
},
update: function(app) {
}
});
tm.define("TestScene", {
superClass: "tm.app.Scene",
init: function() {
this.superInit();
var label = tm.display.Label('tmlib.js でモーフィングボタンを\n作ってみたよ♪').addChildTo(this);
label.setPosition(SCREEN_CENTER_X, SCREEN_CENTER_Y);
label.alpha = 0;
label.tweener
.fadeIn(200);
},
onpointingstart: function() {
this.app.popScene();
}
});
tm.define("MorphingButton", {
superClass: "tm.ui.FlatButton",
init: function(param) {
this.superInit(param);
this.initialWidth = this.width;
this.initialHeight = this.height;
this.initialCornerRadius = this.cornerRadius;
this.on('push', function() {
this.morphCircle();
});
},
// 円形に変形
morphCircle: function(radius) {
var circleSize = radius || 1200;
this.setInteractive(false);
this.label.tweener
.clear()
.fadeOut(200)
;
this.tweener
.clear()
.wait(300)
.to({
width: this.height,
cornerRadius: this.height/2
}, 300, 'easeOutQuint')
.to({
width: circleSize,
height: circleSize,
cornerRadius: circleSize/2
}, 500, 'easeOutQuint')
.call(function() {
this.flare('circled');
this.setInteractive(true);
}, this)
;
},
// 元の形に変形
morphDefault: function() {
this.setInteractive(false);
this.label.tweener
.clear()
.wait(800)
.fadeIn(200)
;
this.tweener
.clear()
.to({
width: this.initialHeight,
height: this.initialHeight,
cornerRadius: this.initialHeight/2
}, 500, 'easeOutQuint')
.to({
width: this.initialWidth,
cornerRadius: this.initialCornerRadius,
}, 300, 'easeOutQuint')
.call(function() {
this.flare('defaulted');
this.setInteractive(true);
}, this)
;
},
});
Tips
押したときにイベント登録
今回は MorphingButton
というクラスを定義して使っています.
MorphingButton
は tm.ui.FlatButton を継承しているので押すと push イベントが発火します.
init 時に push イベントを登録し, ここで押されたら円形に広がるという処理を登録しています.
this.on('push', function() {
this.morphCircle();
});
良い感じのタイミングでシーン遷移
ボタンを生成している側で, 広がりきった際に発火するイベント circled
に
関数を登録しています.
ここで, TestScene を pushScene()
しています.
そして pushScene したシーンが破棄されたら, ボタンが置いてあるシーン TestScene 側で
resume
イベントが発火するのでボタンを元に戻す関数 morphDefault()
を呼んでいます.
これでキレイにアニメーションしながら画面遷移することができます.
// 円が広がりきった際のイベント
button.oncircled = function() {
this.app.pushScene(TestScene());
// シーンが戻ってきたらボタンも戻す
this.one('resume', function() {
button.morphDefault();
});
}.bind(this);
以上, 備忘録でした!