ProgressBar Illusion
/**
* Copyright paq ( http://wonderfl.net/user/paq )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/qhUn
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
/**
* どれが一番早くみえるか。
*
* 参考
* http://gizmodo.com/5719988/the-devious-progress-bar-illusion
*
* @author paq
*/
[SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="60")]
public class ProgressBarIllusion extends Sprite
{
/**
* コンストラクタ
*/
public function ProgressBarIllusion()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private var _progressBars:Vector.<ProgressBar> = new Vector.<ProgressBar>();
/**
* 初期化します.
*
* <p>この関数は一度だけ呼び出してください。</p>
*
* @param event
*/
private function init(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
ComponentManager.initialize(new EnterFrameTicker());
_progressBars.push(new ProgressBar(this, 0, 0, ProgressBar.SIMPLE));
_progressBars.push(new ProgressBar(this, 0, 0, ProgressBar.TWINKLE, 1));
_progressBars.push(new ProgressBar(this, 0, 0, ProgressBar.TWINKLE, 2));
_progressBars.push(new ProgressBar(this, 0, 0, ProgressBar.GRADIENT, -1));
_progressBars.push(new ProgressBar(this, 0, 0, ProgressBar.GRADIENT, 1));
_progressBars.push(new ProgressBar(this, 0, 0, ProgressBar.GRADIENT, 0));
_progressBars.push(new ProgressBar(this, 0, 0, ProgressBar.GRADIENT, 0.5));
_progressBars.push(new ProgressBar(this, 0, 0, ProgressBar.GRADIENT, 3));
_progressBars.push(new ProgressBar(this, 0, 0, ProgressBar.GRADIENT, 4));
var len:int = _progressBars.length;
for (var i:int; i < len; i++ )
{
_progressBars[i].x = 10;
_progressBars[i].y = 10 + i * 50;
_progressBars[i].size(stage.stageWidth - 20, 40);
}
addEventListener(Event.ENTER_FRAME, loop);
stage.addEventListener(MouseEvent.CLICK, function():void {
var len:int = _progressBars.length;
for (var i:int; i < len; i++ )
{
_progressBars[i].value = 0;
}
});
}
/**
* フレーム実行ハンドラ
*
* @param event
*/
private function loop(event:Event):void
{
var len:int = _progressBars.length;
for (var i:int; i < len; i++ )
{
_progressBars[i].value += 0.001;
}
}
}
}
import flash.display.DisplayObjectContainer;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.ColorMatrixFilter;
import flash.geom.Matrix;
class ComponentManager
{
/**
* 新しい ComponentManager クラスのインスタンスを作成します
*/
public function ComponentManager()
{
}
private static var _ticker:ITicker;
private static var _components:Vector.<Component>;
/**
*
* @param ticker
*/
public static function initialize(ticker:ITicker):void
{
_ticker = ticker;
_components = new Vector.<Component>();
}
/**
* 指定されたコンポーネントを追加します
*
* @param component
*/
public static function addComponent(component:Component):void
{
_components.push(component);
}
/**
* 全てのコンポーネントを更新します
*/
public static function updateAll():void
{
var len:int = _components.length;
for (var i:int = 0; i < len; i++ )
{
_components[i].update();
}
}
}
interface ITicker
{
function tick():void;
}
class EnterFrameTicker implements ITicker
{
/**
* 新しい EnterFrameTicker クラスのインスタンスを作成します
*/
public function EnterFrameTicker()
{
_sprite = new Sprite();
_sprite.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private var _sprite:Sprite;
/**
* @inheritDoc
*/
public function tick():void
{
ComponentManager.updateAll();
}
//---------------------------------------------
// イベントハンドラ
//---------------------------------------------
/**
* フレーム実行ハンドラ
*
* @param event
*/
private function onEnterFrame(event:Event):void
{
tick();
}
}
class Component extends Sprite
{
/**
* 新しい Component クラスのインスタンスを作成します
*
* @param parent DisplayObjectContainer.
* @param xpos コンポーネントのX座標.
* @param ypos コンポーネントのY座標.
*/
public function Component(parent:DisplayObjectContainer = null, xpos:Number = 0, ypos:Number = 0)
{
if (parent)
{
parent.addChild(this);
}
this.x = xpos;
this.y = ypos;
initialize();
// コンポーネントマネージャーに追加
ComponentManager.addComponent(this);
}
protected var _width:Number;
protected var _height:Number;
/**
* コンポーネントの大きさを変更します
*
* @param w 幅.
* @param h 高さ.
*/
public function size(w:int, h:int):void
{
_width = w;
_height = h;
dispatchEvent(new Event(Event.RESIZE));
}
/**
* コンポーネントを初期化します
*/
protected function initialize():void
{
}
/**
* コンポーネントを更新します
*/
public function update():void
{
}
/**
* コンポーネントを正常に戻します
*/
public function normalize():void
{
}
//---------------------------------------------
// getter / setter
//---------------------------------------------
override public function get width():Number
{
return _width;
}
override public function set width(value:Number):void
{
_width = value;
dispatchEvent(new Event(Event.RESIZE));
}
override public function get height():Number
{
return _height;
}
override public function set height(value:Number):void
{
_height = value;
dispatchEvent(new Event(Event.RESIZE));
}
}
class ProgressBar extends Component
{
/**
* 新しい ProgressBar クラスのインスタンスを作成します
*
* @param parent DisplayObjectContainer.
* @param xpos コンポーネントのX座標.
* @param ypos コンポーネントのY座標.
*/
public function ProgressBar(parent:DisplayObjectContainer = null, xpos:Number = 0, ypos:Number = 0, type:String = null, speed:Number = 0)
{
_parent = parent;
if (type == null || type == "")
{
type = SIMPLE;
}
_type = type;
_speed = speed;
super(parent, xpos, ypos);
addEventListener(Event.RESIZE, onResize);
}
/** もっとも単純な表示方法です */
public static const SIMPLE:String = "simple";
/** 定期的に光らせます */
public static const TWINKLE:String = "twinkle";
private var _twinkle:Number;
private var _twinkleReverse:Boolean;
/** グラデーションで描画します */
public static const GRADIENT:String = "gradient";
private var _gradationX:Number;
private var _type:String;
private var _speed:Number;
private var _value:Number;
private var _maxValue:Number;
private var _parent:DisplayObjectContainer;
private var _bar:Sprite;
private var _cover:Sprite;
/**
* @inheritDoc
*/
override protected function initialize():void
{
size(200, 20);
_value = 0.0;
_maxValue = 1.0;
_gradationX = 0;
_twinkle = 100;
_twinkleReverse = false;
_bar = new Sprite();
_bar.scaleX = 0;
addChild(_bar);
_cover = new Sprite();
addChild(_cover);
_cover.mask = _bar;
normalize();
}
/**
* @inheritDoc
*/
override public function update():void
{
var percent:Number = _value / _maxValue;
_bar.scaleX = percent;
var g:Graphics = _cover.graphics;
switch (_type)
{
case SIMPLE:
// 何もしない
break;
case TWINKLE:
// TODO: 色関係をもっとスマートにする
_twinkle -= _speed;
if (_twinkle < 0)
{
_twinkle = 100;
_twinkleReverse = !_twinkleReverse;
}
var light:uint;
if (_twinkleReverse)
{
light = 100 - _twinkle;
}
else
{
light = _twinkle;
}
var color:uint = 0x2CA9E1;
var colorR:uint = (color >> 16 & 0xFF) + light;
var colorG:uint = (color >> 8 & 0xFF) + light;
var colorB:uint = (color & 0xFF) + light;
if (colorR > 255) colorR = 255;
if (colorG > 255) colorG = 255;
if (colorB > 255) colorB = 255;
g.clear();
g.beginFill(colorR << 16 | colorG << 8 | colorB);
g.drawRect(0, 0, _width, _height);
break;
case GRADIENT:
_gradationX -= _speed;
g.clear();
g.beginGradientFill(GradientType.LINEAR,
[0x2CA9E1, 0xA0D8EF],
[1, 1],
[0, 255],
new Matrix(0.025, 0, 0, 0, _gradationX),
SpreadMethod.REFLECT);
g.drawRect(0, 0, _width, _height);
break;
}
}
/**
* @inheritDoc
*/
override public function normalize():void
{
var g:Graphics;
g = _bar.graphics;
g.clear();
g.beginFill(0x000000);
g.drawRect(0, 0, _width, _height);
g = _cover.graphics;
g.clear();
switch (_type)
{
case SIMPLE:
g.beginFill(0x2ca9e1);
g.drawRect(0, 0, _width, _height);
break;
case TWINKLE:
g.beginFill(0x2ca9e1);
g.drawRect(0, 0, _width, _height);
break;
case GRADIENT:
// 何もしない
break;
}
}
//---------------------------------------------
// イベントハンドラ
//---------------------------------------------
/**
* リサイズされたときに呼び出されます
*
* @param event
*/
private function onResize(event:Event):void
{
normalize();
}
//---------------------------------------------
// getter / setter
//---------------------------------------------
public function get value():Number
{
return _value;
}
public function set value(value:Number):void
{
_value = value;
if (_value > _maxValue)
{
_value = _maxValue;
}
}
public function get maxValue():Number
{
return _maxValue;
}
public function set maxValue(value:Number):void
{
_maxValue = value;
}
}