Flip Panel -- めくれるサムシング。
ぱたぱたとめくれるパネル。
めくり処理は、FlipPanel内でPageクラスのdrawをスレッド制御してる感じ。
draw内は y-tti 氏のソースから拝借。あざっす!http://wonderfl.net/c/wJDq
めくりスピードは、スレッドに渡す引数で制御。
/**
* Copyright djakarta_trap ( http://wonderfl.net/user/djakarta_trap )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/fVYK
*/
package
{
import com.bit101.components.InputText;
import com.bit101.components.PushButton;
import com.bit101.components.TextArea;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.FocusEvent;
import flash.events.MouseEvent;
import flash.utils.Dictionary;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import net.hires.debug.Stats;
import org.libspark.thread.EnterFrameThreadExecutor;
import org.libspark.thread.Thread;
[SWF(frameRate="60", backgroundColor="#FFFFFF")]
/**
* ...
* @author djakarta-trap
*/
public class FlipClassTest extends Sprite
{
private var _flipPanel:FlipPanel;
private var dic:Dictionary;
private var flip1:FlipPanel;
private var flip2:FlipPanel;
private var flip3:FlipPanel;
private var input:InputText;
public function FlipClassTest()
{
Thread.initialize(new EnterFrameThreadExecutor());
var flipImageData:Array = [];
for (var u:int = 0; u < 3 ; u++)
{
var arr:Array = [];
for (var i:int = 1; i <= 10; i++)
{
var pageAbove:Page = new Page(new CustomBitmapData(100, 50, i.toString() + " ページ目:上"));
var pageBelow:Page = new Page(new CustomBitmapData(100, 50, i.toString() + " ページ目:下"));
arr.push(new SpreadPage(pageAbove, pageBelow));
};
flipImageData.push(arr);
};
flip1 = new FlipPanel(flipImageData[0]);
flip2 = new FlipPanel(flipImageData[1]);
flip3 = new FlipPanel(flipImageData[2]);
flip2.x = stage.stageWidth*0.5 - flip2.width*0.5;
flip2.y = stage.stageHeight*0.5 - flip2.height*0.5 - 100;
flip1.x = flip2.x - flip1.width - 20;
flip1.y = flip2.y;
flip3.x = flip2.x + flip2.width + 20;
flip3.y = flip2.y;
addChild(flip1);
addChild(flip2);
addChild(flip3);
var btn1:PushButton = new PushButton(null, flip1.x, flip1.y + 100, "gotoPage", _onClick);
var btn2:PushButton = new PushButton(null, flip2.x, flip2.y + 100, "gotoPage", _onClick);
var btn3:PushButton = new PushButton(null, flip3.x, flip3.y + 100, "gotoPage", _onClick);
dic = new Dictionary();
dic[btn1] = flip1.gotoPage;
dic[btn2] = flip2.gotoPage;
dic[btn3] = flip3.gotoPage;
btn1.y = btn2.y = btn3.y = stage.stageHeight - btn1.height;
addChild(btn1);
addChild(btn2);
addChild(btn3);
addChild(new Stats());
var loopBtn:PushButton = new PushButton(null, stage.stageWidth * 0.5, stage.stageHeight * 0.5, "loop fliping", _toggleLoopFlip);
loopBtn.x -= loopBtn.width*0.5;
addChild(loopBtn);
input = new InputText(null, 0, 0, "set page index you want to go.");
input.width = 160;
input.x = stage.stageWidth * 0.5 - input.width * 0.5;
input.y = btn2.y - 50;
input.restrict = "1234567890";
input.addEventListener(FocusEvent.FOCUS_IN, function(e:FocusEvent):void { input.removeEventListener(e.type, arguments.callee); input.text = ""; } );
addChild(input);
};
private function _toggleLoopFlip(e:MouseEvent):void
{
flip1.loopFliping();
flip2.loopFliping();
flip3.loopFliping();
}
private function _onClick(e:MouseEvent):void
{
dic[e.target].apply(null,[int(input.text)]);
};
}
}
interface IFlip
{
function flipForward():void;
function flipBackward():void;
function loopFliping():void;
function gotoPage(pageIndex:int):void;
function isFliping():Boolean;
}
import flash.display.DisplayObject;
import flash.display.Sprite;
import org.libspark.betweenas3.core.tweens.groups.SerialTween;
import org.libspark.thread.Thread;
import org.libspark.thread.ThreadState;
import org.libspark.thread.utils.SerialExecutor;
class FlipPanel extends Sprite implements IFlip
{
private var _pages:Array/*SpreadPage*/;
private var _pageIndex:int;
private var _loopFlipThread:SerialExecutor;
private var _currentFlipThread:Thread;
private var _numPages:int;
private var _gotoPageThread:SerialExecutor;
/**
* パタパタめくれるパネル。上下にめくれる。
* 見開きページをSpreadPageインスタンスで管理してる。
*/
public function FlipPanel(spreadPages:Array)
{
super();
this._pages = spreadPages;
_numPages = _pages.length;
//全ページアド。でも、見えない状態でね。
for (var i:int = _pages.length - 1; i >= 0; i--)
{
var item:SpreadPage = _pages[i];
item.mouseChildren = false;
item.mouseEnabled = false;
item.visible = false;
addChild(item);
};
_initialize();
};
private function _initialize():void
{
_pageIndex = 0;
gotoAndStop(_pageIndex);
_pages[_pageIndex].visible = true;
};
public function flipForward():void
{
var next:SpreadPage, current:SpreadPage;
//今が最終見開きページの場合
if (_pageIndex >= _pages.length - 1) {
next = _pages[0];
}else {
next = _pages[_pageIndex + 1];
};
next.visible = true;
current = _pages[_pageIndex];
//次のページを準備する。
next.prepareFlipForward();
//アニメーションスタート
_currentFlipThread = new FlipForwardThread(current, next, this, 8);
_currentFlipThread.start();
//データ更新
if (_pageIndex >= _pages.length - 1) {
_pageIndex = 0;
}else {
++_pageIndex;
};
};
/**
* 指定された表示オブジェクトを、指定したツリーインデックスへ移動させる。
*/
public function setPageIndex(target:DisplayObject, toIndex:int):void
{
if (!contains(target)) {
return;
};
addChildAt(target, toIndex);
};
public function getPageIndex(target:DisplayObject):int
{
if (!contains(target)) {
return -1;
};
return getChildIndex(target);
}
public function flipBackward():void
{
//今回は実装しない。
};
/**
* めくりが永遠に続く。トグル的に機能する。
*/
public function loopFliping():void
{
if (_loopFlipThread && _loopFlipThread.state <= ThreadState.TIMED_WAITING) {
_loopFlipThread.interrupt();
_loopFlipThread = null;
return;
};
_loopFlipThread = new SerialExecutor();
if (_gotoPageThread && _gotoPageThread.state <= ThreadState.TIMED_WAITING) {
_gotoPageThread.interrupt();
_gotoPageThread = null;
if (_currentFlipThread && _currentFlipThread.state <= ThreadState.TIMED_WAITING) {
_loopFlipThread.addThread(_currentFlipThread);
};
};
_loopFlipThread.addThread( new LoopFlipThread(this, 500));
_loopFlipThread.start();
};
/**
* 指定した見開きページへアニメーション移動させる。
* @param goalIndex 行き先のページインデックス
*/
public function gotoPage(goalIndex:int):void
{
var isGotoPaging:Boolean = false;
if (_gotoPageThread && _gotoPageThread.state <= ThreadState.TIMED_WAITING) {
isGotoPaging = true;
_gotoPageThread.interrupt();
_gotoPageThread = null;
};
_gotoPageThread = new SerialExecutor();
var flipTimes:int = (_pageIndex < goalIndex) ? goalIndex - _pageIndex : (_numPages - (_pageIndex+1)) + (goalIndex + 1);
if (_loopFlipThread && _loopFlipThread.state <= ThreadState.TIMED_WAITING) {
_loopFlipThread.interrupt();
_loopFlipThread = null;
//今現在の1ページ分のめくりを非同期処理したいときはコメントアウトを解除。
//if (_currentFlipThread && _currentFlipThread.state <= ThreadState.TIMED_WAITING) {
//_gotoPageThread.addThread(_currentFlipThread);
//};
};
_gotoPageThread.addThread(new SpecifiedTimesFlip(this, flipTimes, 500));
_gotoPageThread.start();
};
/**
* 指定した見開きページへ、アニメーションなしで移動させる
*/
public function gotoAndStop(goalIndex:int):void
{
if (_gotoPageThread && _gotoPageThread.state <= ThreadState.TIMED_WAITING) {
_gotoPageThread.interrupt();
_gotoPageThread = null;
};
if (_loopFlipThread && _loopFlipThread.state <= ThreadState.TIMED_WAITING) {
_loopFlipThread.interrupt();
_loopFlipThread = null;
};
var flipTimes:int = (_pageIndex < goalIndex) ? goalIndex - _pageIndex : (_numPages - (_pageIndex + 1)) + (goalIndex + 1);
for (var i:int = 0; i < flipTimes; i++)
{
var highestPage:DisplayObject = getChildAt(numPages - 1);
if (i == 0) highestPage.visible = false;
if (i == flipTimes - 1) getChildAt(numPages - 2).visible = true;
addChildAt(highestPage, 0);
};
//update
_pageIndex = goalIndex;
}
public function isFliping():Boolean
{
return false;
}
public function get numPages():int { return _numPages; }
}
import flash.display.DisplayObjectContainer;
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Point;
import org.libspark.thread.Thread;
/**
* ページを表すクラス。見開き状態を1ページとしてます。
* ...
* @author djakarta-trap
*/
class SpreadPage extends Sprite
{
/**
* 捲れる際のパース感を現す。この値が大きいほど、パース感が増す。
*/
public static const distorion:Number = 4;
private var _above:Page;
private var _below:Page;
public function SpreadPage(above:Page, below:Page)
{
this._below = below;
this._above = above;
addChild(_below);
addChild(_above);
_below.y = _above.originalHeight;
_below.draw(new Point(0, 0), new Point(_below.originalWidth, 0), new Point(0, _below.originalHeight), new Point(_below.originalWidth, _below.originalHeight));
_above.draw(new Point(0, 0), new Point(_above.originalWidth, 0), new Point(0, _above.originalHeight), new Point(_above.originalWidth, _above.originalHeight));
};
public function prepareFlipForward():void
{
_above.draw(new Point(0, 0), new Point(_above.originalWidth, 0), new Point(0, _above.originalHeight), new Point(_above.originalWidth, _above.originalHeight));
_below.draw(new Point(0, 0), new Point(_below.originalWidth, 0), new Point(-distorion, 0), new Point(_below.originalWidth + distorion, 0));
}
public function get above():Page { return _above; }
public function get below():Page { return _below; }
}
import flash.display.BitmapData;
import flash.display.Shape;
import flash.geom.Matrix;
import flash.geom.Point;
/**
* SpreadPageにおける1ページ分を表すクラス。
* ...
* @author djakarta-trap
*/
class Page extends Shape
{
private var _bitmapData:BitmapData;
private var _initialMatrix1:Matrix;
private var _initialMatrix2:Matrix;
private var _originalWidth:Number;
private var _originalHeight:Number;
public function Page(bitmapData:BitmapData)
{
super();
this._bitmapData = bitmapData;
_originalWidth = _bitmapData.width;
_originalHeight = _bitmapData.height;
_initialMatrix1 = _getTriangleMatrix(new Point(0, 0), new Point(_bitmapData.width, 0), new Point(0, _bitmapData.height));
_initialMatrix2 = _getTriangleMatrix(new Point(_bitmapData.width, _bitmapData.height), new Point(0, _bitmapData.height), new Point(_bitmapData.width, 0));
};
public function draw(TL:Point, TR:Point, BL:Point, BR:Point):void
{
graphics.clear();
var mat1:Matrix = _getTriangleMatrix(TL, TR, BL);
var mat2:Matrix = _initialMatrix2.clone();
mat1.concat(_initialMatrix1.clone());
mat2.concat(_getTriangleMatrix(BR, BL, TR));
graphics.beginBitmapFill(_bitmapData, mat1, false, false);
graphics.moveTo(TL.x, TL.y);
graphics.lineTo(TR.x, TR.y);
graphics.lineTo(BL.x, BL.y);
graphics.endFill();
graphics.beginBitmapFill(_bitmapData, mat2, false, false);
graphics.moveTo(BR.x, BR.y);
graphics.lineTo(TR.x,TR.y);
graphics.lineTo(BL.x, BL.y);
graphics.endFill();
};
private function _getTriangleMatrix(p0:Point, p1:Point, p2:Point):Matrix
{
var w:Number = _bitmapData.width;
var h:Number = _bitmapData.height;
var matrix:Matrix = new Matrix();
matrix.a = (p1.x - p0.x) / w;
matrix.b = (p1.y - p0.y) / w;
matrix.c = (p2.x - p0.x) / h;
matrix.d = (p2.y - p0.y) / h;
matrix.tx = p0.x;
matrix.ty = p0.y;
return matrix;
}
public function get originalWidth():Number { return _originalWidth; };
public function get originalHeight():Number { return _originalHeight; }
}
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
class CustomBitmapData extends BitmapData
{
public function CustomBitmapData(width:int, height:int, msg:String = null)
{
super(width, height, false, 0xffffffff);
var sp:Sprite = new Sprite();
var tf:TextField = new TextField();
sp.graphics.lineStyle(2, 0x666666);
sp.graphics.beginFill(0xffffff);
sp.graphics.drawRect(0, 0, width, height);
sp.graphics.endFill();
sp.graphics.lineStyle(1, 0x666666);
sp.graphics.moveTo(0, 0);
sp.graphics.lineTo(width, height);
sp.graphics.moveTo(width, 0);
sp.graphics.lineTo(0, height);
sp.graphics.endFill();
if (msg) {
var tformat:TextFormat = new TextFormat("_sans", 12, 0x666666);
tformat.align = TextFormatAlign.CENTER;
tf.autoSize = TextFieldAutoSize.CENTER;
tf.width = width;
tf.wordWrap = true;
tf.multiline = true;
tf.selectable = false;
tf.mouseEnabled = false;
tf.defaultTextFormat = tformat;
tf.text = msg;
tf.x = 0;
tf.y = sp.height * 0.5 - tf.height * 0.5;
sp.addChild(tf);
};
draw(sp);
}
}
import flash.display.DisplayObjectContainer;
import flash.geom.Point;
import org.libspark.thread.Thread;
class FlipForwardThread extends Thread
{
private var _current:SpreadPage;
private var _next:SpreadPage;
private var _rad:Number;
private var _tl:Point;
private var _tr:Point;
private var _bl:Point;
private var _br:Point;
private var _speed:Number;
private var _panel:FlipPanel;
public function FlipForwardThread(current:SpreadPage, next:SpreadPage, panel:FlipPanel, speed:Number = 2)
{
super();
this._panel = panel;
this._speed = speed;
this._next = next;
this._current = current;
_rad = 0;
_tl = new Point();
_tr = new Point();
_bl = new Point();
_br = new Point();
};
override protected function run():void
{
if (isInterrupted) {
next(null);
}else {
//update
_rad += Math.PI / 180 * _speed;
if (_rad >= Math.PI / 2) {
_panel.setChildIndex(_next, _panel.numPages - 1);
_current.above.draw(new Point(0, 0), new Point(_current.above.originalWidth, 0), new Point(0, _current.above.originalHeight), new Point(_current.above.originalWidth, _current.above.originalHeight));
_nextBelowDown();
return;
};
next(run);
var _distortion:Number = SpreadPage.distorion * Math.cos(_rad);
var _height:Number = _current.above.originalHeight * Math.sin(_rad);
_tl.x = -_distortion; _tl.y = _height;
_tr.x = _current.above.originalWidth + _distortion; _tr.y = _height;
_bl.x = 0; _bl.y = _current.above.originalHeight;
_br.x = _current.above.originalWidth; _br.y = _current.above.originalHeight;
_current.above.draw(_tl, _tr, _bl, _br);
};
}
private function _nextBelowDown():void
{
if (isInterrupted) {
next(null);
}else {
next(_nextBelowDown);
//update
_rad += Math.PI / 180 * _speed;
if (_rad >= Math.PI) {
next(null);
_panel.setChildIndex(_current, 0);
_rad = Math.PI
};
var _distortion:Number = SpreadPage.distorion * Math.sin(_rad);
var _height:Number = -_next.below.originalHeight * Math.cos(_rad);
_tl.x = 0; _tl.y = 0;
_tr.x = _next.below.originalWidth; _tr.y = 0;
_bl.x = -_distortion; _bl.y = _height;
_br.x = _next.below.originalWidth + _distortion; _br.y = _height;
_next.below.draw(_tl, _tr, _bl, _br);
}
}
}
import org.libspark.thread.Thread;
class LoopFlipThread extends Thread
{
private var _flipPanel:FlipPanel;
private var _duration:Number;
public function LoopFlipThread(flipPanel:FlipPanel, duration:Number = 200)
{
super();
this._duration = duration;
this._flipPanel = flipPanel;
};
override protected function run():void
{
if (isInterrupted) {
next(null);
}else {
next(run);
sleep(_duration);
interrupted(_onInterrupt);
_flipPanel.flipForward();
};
};
private function _onInterrupt():void
{
next(null);
}
}
import org.libspark.thread.Thread;
class SpecifiedTimesFlip extends Thread
{
private var _flipPanel:FlipPanel;
private var _flipTimes:int;
private var _duration:Number;
private var _counter:int;
public function SpecifiedTimesFlip(flipPanel:FlipPanel, flipTimes:int, duration:Number)
{
this._duration = duration;
this._flipTimes = flipTimes;
this._flipPanel = flipPanel;
_counter = 0;
};
override protected function run():void
{
if (isInterrupted) {
next(null);
}else {
if (_counter >= _flipTimes) {
next(null);
}else {
next(run);
sleep(_duration);
interrupted(_onInterrupt);
//実行
_flipPanel.flipForward();
//update
_counter++;
};
}
}
private function _onInterrupt():void
{
}
}