/** * AutoSitemap * * @author Yasu ( clockmaker.jp ) * @version 2.1.1 * @see http://clockmaker.jp/ * * AutoSitemap is (c) 2009-2010 yasu (clockmaker.jp) and is released under the MIT License: * http://www.opensource.org/licenses/mit-license.php * */ package jp.clockmaker.prog4 { import caurina.transitions.Tweener; import flash.display.*; import flash.events.*; import flash.text.*; import jp.nium.utils.ClassUtil; import jp.progression.casts.CastButton; import jp.progression.Progression; import jp.progression.scenes.SceneId; import jp.progression.scenes.SceneLoader; import jp.progression.scenes.SceneObject; /** * AutoSitemap クラスは Progression のシーン構造を GUI で表示するための拡張機能です。 */ public class AutoSitemap { static private const SITEMAP_BACKGROUND_ALPHA:Number = 0.75; static private const SITEMAP_BACKGROUND_HEIGHT:int = 200; static private const SITEMAP_SHOW_TAB_HEIGHT:int = 30; static private const PADDING_LEFT:int = 10; static private const PADDING_TOP:int = 5; static private var _menu:Sprite; static private var _manager:Progression; static private var _sitemaps:Array; static private var _btns:Array = []; static private var _fmt:TextFormat; static private var _tab:Sprite; static private var _arrow:Sprite; static private var _pageArea:Sprite; static private var _tabText:TextField; static private var _isTweening:Boolean = false; static private var _isAttention:Boolean = false; static private var _isShowSitemap:Boolean = false; /** * 初期化をおこないます * @param progression Progression インスタンスです。 * * @example * // Progression インスタンスを作成する * var manager:Progression = new Progression( "index", stage ); * * // AutoSitemap を初期化する * AutoSitemap.initialize( manager ); * */ static public function initialize(manager:Progression):void { _manager = manager; _manager.stage.addEventListener(MouseEvent.MOUSE_MOVE, _onMouseMove); // text format _fmt = new TextFormat(); _fmt.size = 11; _fmt.color = 0xFFFFFF; _fmt.font = "_sans"; // menu _menu = new Sprite(); _manager.stage.addEventListener(Event.RESIZE, _onResize, false, int.MAX_VALUE, true); _onResize(); _menu.y = -SITEMAP_BACKGROUND_HEIGHT; // tab _tab = new Sprite(); _tab.y = SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT; _tab.graphics.beginFill(0, 0.25); _tab.graphics.drawRect(0, 0, _manager.stage.stageWidth, SITEMAP_SHOW_TAB_HEIGHT); _tab.graphics.endFill(); _tab.buttonMode = true; //tab.toolTip.delay = 0; // tab text _tabText = new TextField(); _tabText.autoSize = TextFieldAutoSize.LEFT; _tabText.text = "Show Sitemap"; _tabText.x = 25; _tabText.y = 5; _tabText.selectable = false; _tabText.mouseEnabled = false; _tabText.defaultTextFormat = _fmt _tab.addChild(_tabText) // arrow _arrow = _createArrow(); _arrow.x = 16; _arrow.y = 14; _tab.addChild(_arrow) _menu.addChild(_tab); // page var maskArea:Sprite = new Sprite(); maskArea.graphics.beginFill(0); maskArea.graphics.drawRect(0, 0, _manager.stage.stageWidth, SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT); _pageArea = new Sprite(); _pageArea.mask = maskArea; _pageArea.graphics.beginFill(0, 0); _pageArea.graphics.drawRect(0, 0, 1, SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT); _menu.addChild(_pageArea); } /** * マウスが動いたときのハンドラー */ static private function _onMouseMove(e:MouseEvent):void { if (_isTweening) return; if (_isShowSitemap) return; if (e.stageY < SITEMAP_SHOW_TAB_HEIGHT) _attentionSitemap(); else _hideSitemap(); } /** * サイトマップをアテンションします。 */ static private function _attentionSitemap():void { _manager.stage.addChild(_menu); _tabText.text = "Show Sitemap" _arrow.rotation = 0; _isTweening = true; Tweener.addTween(_menu, { y : SITEMAP_SHOW_TAB_HEIGHT - SITEMAP_BACKGROUND_HEIGHT, transition : "easeOutBack", time : 0.4, onComplete : function():void { _isTweening = false; } }); _tab.addEventListener(MouseEvent.CLICK, _showSitemap); } /** * サイトマップを表示します */ static private function _showSitemap(e:MouseEvent = null):void { _tab.removeEventListener(MouseEvent.CLICK, _showSitemap); _generateSitemap(); _isTweening = true; _isShowSitemap = true; _pageArea.y = 0; // マウス操作を無効にする _menu.mouseChildren = false; _menu.mouseEnabled = false; Tweener.addTween(_menu, { y : 0, time : 0.5, transition : "easeOutExpo", onComplete : function():void { _isTweening = false; _tabText.text = "Hide Sitemap" _arrow.rotation = 180; // マウス操作を有効にする _menu.mouseChildren = true; _menu.mouseEnabled = true; _tab.addEventListener(MouseEvent.CLICK, _hideSitemap); _manager.stage.addEventListener(Event.ENTER_FRAME, _onEnterFrame); } }); } /** * サイトマップを隠します */ static private function _hideSitemap(e:MouseEvent = null):void { if (_menu.y == -SITEMAP_BACKGROUND_HEIGHT) return; _manager.stage.removeEventListener(Event.ENTER_FRAME, _onEnterFrame); _tab.removeEventListener(MouseEvent.CLICK, _hideSitemap); _isTweening = true; // マウス操作を無効にする _menu.mouseChildren = false; _menu.mouseEnabled = false; Tweener.addTween(_menu, { y : -SITEMAP_BACKGROUND_HEIGHT, time : 0.5, transition : "easeInOutExpo", onComplete : function():void { if (_manager.stage.contains(_menu)) _manager.stage.removeChild(_menu); while (_btns.length) _pageArea.removeChild(_btns.pop()); _isTweening = false; _isShowSitemap = false; // マウス操作を有効にする _menu.mouseChildren = true; _menu.mouseEnabled = true; } }) } /** * サイトマップが開いているときの、ページのスクロール処理です。 */ static private function _onEnterFrame(e:Event):void { var my:Number = Math.min(SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT, Math.max(0, _menu.mouseY)); var aim:Number; if(_pageArea.height <= SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT) aim = - (_pageArea.height - SITEMAP_BACKGROUND_HEIGHT + SITEMAP_SHOW_TAB_HEIGHT) * (my / (SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT)); else aim = - (_pageArea.height - SITEMAP_BACKGROUND_HEIGHT + SITEMAP_SHOW_TAB_HEIGHT + PADDING_TOP * 2) * (my / (SITEMAP_BACKGROUND_HEIGHT - SITEMAP_SHOW_TAB_HEIGHT)); _pageArea.y += (aim - _pageArea.y) * 0.2; } /** * サイトマップを生成します。 */ static private function _generateSitemap():void { _sitemaps = []; _searchPRML(_manager.root); for (var i:int = 0; i < _sitemaps.length; i++) { var btn:DisplayObject = _pageArea.addChild(_createBtn(_sitemaps[i])); btn.y = i * 20 + PADDING_TOP; _btns.push(btn); } } /** * SceneObjectから再帰関数として構造を取得します。 */ static private function _searchPRML(scene:SceneObject):void { _sitemaps.push(scene); // 子シーンオブジェクトの配列を取得する var children:Array; if (scene is SceneLoader) { children = (scene as SceneLoader).content ? (scene as SceneLoader).content.scenes : []; } else if (scene is SceneObject) { children = scene.scenes; } // 子シーンノードを走査する var l:int = children.length; for ( var i:int = 0; i < l; i++ ) { var child:SceneObject = SceneObject( children[i] ); _searchPRML(child); } } /** * サイトマップボタンを作成します。 */ static private function _createBtn(scene:SceneObject):CastButton { // ルートからのシーンIDを調べる var sceneId:SceneId = scene.localToGlobal(scene.sceneId); // シーンの深さを検出します var depth:int = sceneId.length - 1; var btn:CastButton = new CastButton(); var textField:TextField = new TextField(); textField.autoSize = TextFieldAutoSize.LEFT; textField.htmlText = "» " + (scene.title ? scene.title : scene.name); textField.x = depth * 75 + PADDING_LEFT; textField.selectable = false; btn.mouseChildren = false; btn.addChild(textField); textField.setTextFormat(_fmt); var zabuton:Sprite = new Sprite(); zabuton.graphics.beginFill(0xFFFFFF, 0.1); //背景色 zabuton.graphics.lineStyle(1, 0xFFFFFF); //背景色 zabuton.graphics.drawRect(-1, 0.5, _manager.stage.stageWidth + 1, textField.textHeight + 6);//初期+左上のXY座標,幅,高さ,角丸幅 zabuton.graphics.endFill(); //塗り潰し終了 if(_manager.current == scene) btn.graphics.beginFill(0xFFFFFF, 0.2); //背景色 else btn.graphics.beginFill(0x0, 0); //背景色 btn.graphics.drawRect(0, 0, _manager.stage.stageWidth, textField.textHeight + 6) btn.graphics.endFill(); //塗り潰し終了 zabuton.alpha = 0; btn.addChild(zabuton); // ボタンがロールオーバーしたとき btn.onCastRollOver = function():void { zabuton.alpha = 1; } // ボタンがロールアウトしたとき btn.onCastRollOut = function():void { zabuton.alpha = 0; } btn.addEventListener(MouseEvent.CLICK, _hideSitemap, false, int.MAX_VALUE, true); // ボタンを押したときの遷移先を指定 btn.sceneId = scene.sceneId; // SceneObject のクラスパスがわかると開発時に便利だけど、エンドユーザー向けではないので実装保留 btn.toolTip.text = ClassUtil.getClassPath(scene); if (_manager.current == scene) { btn.toolTip.text = "Current Page"; } return btn; } /** * 矢印アイコンを作成します。 */ static private function _createArrow():Sprite { var sp:Sprite = new Sprite(); sp.graphics.beginFill(0xFFFFFF); sp.graphics.drawRect(-4, -2, 2, 2); sp.graphics.drawRect(-2, 0, 2, 2); sp.graphics.drawRect(0, 2, 2, 2); sp.graphics.drawRect(2, 0, 2, 2); sp.graphics.drawRect(4, -2, 2, 2); sp.graphics.endFill(); return sp; } /** * リサイズ時の処理です。 */ static private function _onResize(e:Event = null):void { _menu.graphics.clear(); _menu.graphics.beginFill(0, SITEMAP_BACKGROUND_ALPHA); _menu.graphics.drawRect(0, 0, _manager.stage.stageWidth, SITEMAP_BACKGROUND_HEIGHT); } /** * @private */ public function AutoSitemap() { throw new Error("AutoSitemap クラスはインスタンス化することはできません"); } } }