2009.09.14
category
comments

ASだけでJSを動作させる

ExternalInterfaceを使うとJavaScriptと連携できるんだけど、HTMLにJSを書くのはめんどくさいしJSファイルをサーバーにアップするのも手間なのでASだけでJSを動作させるテスト。Flashサイトで良く使いそうなJSをまとめてクラスにしてみた。staticメソッドにしてあるので、インポートした後はnewせずにクラス名から直接呼び出せる。とりあえず10種類用意したので、随時追加していこうかなー。

上記のデモのHTML見てもらえば分かるけど、このFlashから指示してるJSの記述は一切していない。なのでswfファイルだけサーバーにアップすればJSも動く。HTMLにJSのリンクタグとか仕込まなくてもいいのでちょっとだけ楽できるよと。ドキュメントクラスからの使い方はこんな感じ。

private function onClick(e:MouseEvent):void
{
	var browser:String = JsUtils.getBrowser();
	switch(e.currentTarget.name)
	{
		//-----[ポップアップを開く]
		case "btn1":
			var url:String = "http://www.google.co.jp/";

			//-----[safariのみ_blankで対応]
			if (browser != null && browser.indexOf("Safari") >= 0)	navigateToURL(new URLRequest(url), "_blank");
			else JsUtils.windowOpen(url, 400, 400, 0, 0, true, false, "yes");
			break;
		//-----[ウインドウを揺らす]
		case "btn2":
			JsUtils.windowShake();
			break;
		//-----[アラートを表示]
		case "btn3":
			JsUtils.alert(browser);
			break;
		//-----[現在のURLを取得]
		case "btn4":
			JsUtils.alert(JsUtils.getLocation());
			break;
		//-----[ウインドウの移動]
		case "btn5":
			JsUtils.windowMove(0, 0);
			break;
		//-----[ウインドウのリサイズ]
		case "btn6":
			JsUtils.windowResize(400, 400);
			break;
		//-----[クッキーを保存]
		case "btn7":
			JsUtils.setCookie("cookiename", "hogehoge", 7);
			break;
		//-----[クッキーを取得]
		case "btn8":
			JsUtils.alert(JsUtils.getCookie("cookiename"));
			break;
		//-----[タイトルの変更]
		case "btn9":
			JsUtils.setTitle("fugafuga");
			break;
		//-----[タイトルの取得]
		case "btn10":
			JsUtils.alert(JsUtils.getTitle());
			break;
	}
}

やってる事は大したこと無くて、ExternalInterface.call()の中で関数を文字列としてコールしてるだけ。Flash側からは文字列でも、JSに渡された瞬間に関数になって実行さるイメージなのかな。リファラーも取れるので、GoogleやYahooからどんなキーワード検索で飛んできたのかもFlash側に渡してやれる。LPOみたいにFlash内のレイアウトや配置をキーワードに合わせて動的に変更したりも出来るだろうから、色々使い道はあるかも。

JsUtilsクラスはこちらからどうぞ。

2009.09.08
category
comments

サーバータイムを使ったミリ秒対応のカウントダウン

ティザーサイト等で良く使われる「オープンまであと何日」みたいなカウントダウンを作ってみる。Flashだけで作るとローカルタイムに依存するので、ユーザーに時計を進められるとネタばれすることも。たまに見かけるけど。上のデモはアクセスした日から常に1ヶ月先をカウントダウンします。残りゼロになっても、何も起きませんよ。

サーバーから時間を取得した後にFlash側で経過時間を足して、目的の時間から差分を取ることでどのPCから見てもカウントダウンの時刻を同期することができる。

カウンタークラスにしてみた。ドキュメントクラスでは下記のように使います。

package
{
	import flash.display.Sprite;
	import flash.text.TextField;
	import info.five.net.Counter;
	import info.five.events.CountEvent;

	/**
	 * ...
	 * @author 5ive
	 */
	public class Main extends Sprite
	{
		public function Main():void
		{
			var d:Date = new Date();
			var ctr:Counter = new Counter(d.fullYear, d.month + 2, d.date);
			ctr.getServerTime("servertime.php");
			ctr.addEventListener(Counter.CHANGE, onChange);
			ctr.addEventListener(Counter.FINISH, onFinish);
		}

		private function onFinish(e:CountEvent):void
		{
			trace("finish!");
		}

		private function onChange(e:CountEvent):void
		{
			countText.text = e.day + "d  " + e.hour + "h  " + e.minute + "m  " + e.second + "s  " + e.milisecond + "ms";
		}
	}
}

new Counter()の引数でカウントさせたい未来の日付と時間を渡す。getServerTime()メソッドでPHPへのパスを渡す。後はCHANGEとFINISHイベントをリスナーに登録して時間が流れるのを待つだけ。

Counter.as

package info.five.net
{
	import flash.display.Sprite;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLVariables;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.EventDispatcher;
	import flash.utils.getTimer;

	import info.five.events.CountEvent;

	/**
	 * ...
	 * @author 5ive
	 */
	public class Counter extends EventDispatcher
	{
		public static const CHANGE:String = "change";
		public static const FINISH:String = "finish";
		private var _loader:URLLoader;
		private var _serverTime:Number;
		private var _swfTime:Number;
		private var _futureDate:Date;
		private var _sp:Sprite;

		public function Counter(year:uint, month:uint, day:uint, hour:uint = 0, monuites:uint = 0, second:uint = 0, milisecond:uint = 0):void
		{
			_sp = new Sprite();
			_futureDate = new Date(year, month - 1, day, hour, monuites, second, milisecond);
		}

		//------------------------------
		//   サーバーへの問い合わせ
		//------------------------------
		public function getServerTime(url:String):void
		{
			//-----[キャッシュ対策]
			var date:Date = new Date();
			url += "?t=" + date.getTime();

			//-----[サーバーの時間取得]
			_loader = new URLLoader();
			_loader.addEventListener(Event.COMPLETE, onComplete);
			_loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
			_loader.load(new URLRequest(url));
		}

		//------------------------------
		//   IOErrorEvent
		//------------------------------
		private function onError(e:IOErrorEvent):void
		{
			trace("error=" + e.text);
		}

		//------------------------------
		//   サーバーの時間取得
		//------------------------------
		private function onComplete(e:Event):void
		{
			var urlVariables:URLVariables = new URLVariables(_loader.data);
			_serverTime = Number(urlVariables.returnValue);
			_swfTime = getTimer();

			//-----[URLLoaderの削除]
			_loader.removeEventListener(Event.COMPLETE, onComplete);
			_loader.removeEventListener(IOErrorEvent.IO_ERROR, onError);
			_loader.data = null;
			_loader = null;

			//-----[タイマーの開始]
			if (_futureDate.getTime() < _serverTime)
			{
				trace("[error]:カウントする日付が過去を指定しています。");
			}
			else
			{
				if (_sp != null) _sp.addEventListener(Event.ENTER_FRAME, onTicks);
			}
		}

		//------------------------------
		//   タイマーの更新
		//------------------------------
		private function onTicks(e:Event):void
		{
			var passage:Number = _serverTime + (getTimer() - _swfTime);
			var diff:Number = _futureDate.getTime() - passage;
			var day:* = Math.floor(diff / (24 * 60 * 60 * 1000));
			var total:* = Math.floor(diff / (60 * 60 * 1000));
			var hour:* = total - (day * 24);
			var minute:* = Math.floor(diff / (60 * 1000)) - (total * 60);
			var second:* = Math.ceil(diff / 1000) - ((minute * 60) + (total * 60 * 60)) - 1;
			var milisecond:String = diff.toString().substr(diff.toString().length - 3, 3);

			//-----[2桁で表示]
			day = String(day + 100).substr(1, 2);
			hour = String(hour + 100).substr(1, 2);
			minute = String(minute + 100).substr(1, 2);
			second = String(second + 100).substr(1, 2);

			//-----[イベントクラスに値を格納]
			var ce:CountEvent = new CountEvent(CountEvent.CHANGE);

			if (diff > 100)
			{
				ce.day = day;
				ce.hour = hour;
				ce.minute = minute;
				ce.second = second;
				ce.milisecond = milisecond;
				dispatchEvent(ce);
			}
			else
			{
				ce.day = "00";
				ce.hour = "00";
				ce.minute = "00";
				ce.second = "00";
				ce.milisecond = "000";
				dispatchEvent(ce);

				dispatchEvent(new CountEvent(CountEvent.FINISH));
				kill();
			}
		}

		//------------------------------
		//   データの破棄
		//------------------------------
		public function kill():void
		{
			_sp.removeEventListener(Event.ENTER_FRAME, onTicks);
			_sp = null;
		}
	}
}

Counterクラスではサーバータイムを取得した瞬間にENTER_FRAMEを発動。そこからFlash内での経過ミリ秒を加算していき、目的の時間との差分を計算してCountEventクラスに各時間を格納させる。そのイベントをドキュメントクラスに返して時間を取得させる。

CountEvent.as

package info.five.events
{
	import flash.events.Event;

	public class CountEvent extends Event
	{
		public static const CHANGE:String = "change";
		public static const FINISH:String = "finish";
		public var day:String;
		public var hour:String;
		public var minute:String;
		public var second:String;
		public var milisecond:String;

		//------------------------------
		//   コンストラクタ
		//------------------------------
		public function CountEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false):void
		{
			super(type, bubbles, cancelable);
		}

		//------------------------------
		//   クローン
		//------------------------------
		public override function clone():Event
		{
			return new CountEvent(type, bubbles, cancelable);
		}
	}
}

CountEventクラスには「day」、「hour」、「minute」、「second」、「milisecond」プロパティが用意されているので、ドキュメントクラス側で必要に応じて取得して表示させて下さい。

serverttime.php

<?php
 $stamp = microtime();
 $ary = split(" ", $stamp);
 echo "returnValue=".(string)$ary[1].(string)(int)($ary[0] * 1000);
?>

最後にサーバーに置くPHP。Flash側のgetTimer()のミリ秒と、PHP側のmicrotime()のミリ秒で桁が違うので、桁合わせのためにちょっとだけごにょごにょしてます。microtime()でミリ秒を取得すると小数点付きで分割して計算されるので、一度文字列にしてFlash側に合わせるように変換かけてます。

2008.04.23
category
tag
comments

PHPに複数データを渡してみる

AS3ではURLRequest.dataで送信できるデータは1つなので、複数の変数をPHPに渡したい場合はURLVariablesを使う。URLVariablesをインスタンス化した後に、通常のオブジェクトと同様、任意のプロパティに値を格納していく。ここでは「title」、「url」、「text」の3つの要素を各プロパティに入れている。URLVariablesに格納した後は、URLRequestにて呼び出したいPHPのパスと通信方法を指定(今回はPOST通信)し、URLRequest.dataにURLVariablesを突っ込む。最後にnavigateToURL()でPHPを表示させ、Flashからデータを受け取っているか確認する。

Main.as

package
{
	import flash.display.Stage;
	import flash.display.Sprite;
	import flash.net.URLVariables;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.navigateToURL;

	public class Main extends Sprite
	{
		//------------------------------
		//   コンストラクタ
		//------------------------------
		public function Main()
		{
			sendData();
		}

		//------------------------------
		//   データ送信
		//------------------------------
		public function sendData():void
		{
			var variables:URLVariables = new URLVariables();
			variables.title = "5ive.blog";
			variables.url = "http://www.5ive.info/blog/";
			variables.text = "PHPに複数のデータを渡す方法";

			var urlRequest:URLRequest = new URLRequest();
			urlRequest.url = "variables.php";
			urlRequest.method = URLRequestMethod.POST;
			urlRequest.data = variables;

			//phpに送信
			navigateToURL(urlRequest , "_self");
		}
	}
}

variables.php

$title = $_POST['title'];
$url = $_POST['url'];
$text = $_POST['text'];

echo "title = ".$title."";
echo "url = ".$url."";
echo "text = ".$text."";
2007.08.03
category
comments

CASAを使ってPHPとやりとりする

通常はsendAndLoadを使うけど、CASAを使うともっと手軽に出来ます。new VarsLoad()の第1引数でPHPのパスを指定し、第2引数で「GET」か「POST」の送信方法を指定する。myVarsLoad.setValue(“text”, “Hello World”);でPHPに渡したい値を指定する。第1引数が変数名で第2引数が値になる。

PHPからの返り値を受け取るにはコンプリートハンドラーの中でthis.myVarsLoad.getValue(“text”)とすればよい。この場合の引数はPHPから返ってくる変数名を指定する。ちなみにPHPからの返り値を全て見たいときはtrace(this.myVarsLoad.$receive)とすればよい。さらにPHPから返ってくるオブジェクトそのものを見たいときは前回のエントリーでも書いたObjectDumper.toString()メソッドを使うと一発で理解できる。trace(ObjectDumper.toString(myVarsLoad, true, true));とすれば中身が丸見え。

CASA使うとコード量が格段に減ってすっきりするので気持ちよい。

import org.casaframework.load.data.VarsLoad;

//-----[初期設定]
var myVarsLoad:VarsLoad;

//-----[ボタンクリックでPHPと通信]
btn.onRelease = function()
{
	myVarsLoad = new VarsLoad("やりとりしたいPHPのパス", "GET");
	myVarsLoad.addEventObserver(_root, VarsLoad.EVENT_LOAD_COMPLETE, "onDataLoad");
	myVarsLoad.setValue("text", "Hello World");
	myVarsLoad.start();
}

//-----[ロード完了]
function onDataLoad(sender:VarsLoad):Void
{
	trace(this.myVarsLoad.getValue("text"));
}
2007.06.18
category
comments

AMFPHPを試す

AMF通信をやってみる。まずはFlash Remoting用のコンポーネントをダウンロードしてインストールする。

次にamfphpをダウンロード。現時点でのバージョンはamfphp-1.2.6。解凍してamfphpフォルダごとlocalhost直下にアップする。

今回の場合はhttp://localhost/amfphp/browser/index.htmlにアクセスしてデフォルト画面が表示されていればインストール成功となる。この画面がサービスブラウザとなりコードの修正や引数のやりとりを確認する事ができる。ここからはサービス用のphpファイルとflaファイルを作成。

HelloWorld.php(クラス名とファイル名を統一すること)

class HelloWorld
{
    //-----[AMFPHPのテーブル設定]
    function HelloWorld()
    {
        $this->methodTable = array
        (
            "say" => array
            (
                "access" => "remote",
                "description" => "文字列を返します"
            )
        );
    }

    //-----[flashから呼ばれる関数]
    function say($sArgments)
    {
        return 'You said: ' . $sArgments;
    }
}

フラッシュからの引数は$sArgmentsに格納される。このphpをhttp://localhost/amfphp/servicesにアップする。
※この状態でサービスブラウザにアクセスするとHelloWorldがサービスとして登録される。

HelloWorld.fla(ルートの1フレーム目)

import mx.remoting.*;
import mx.rpc.*;
import mx.remoting.debug.NetDebug;

var gatewayUrl:String = "http://localhost/amfphp/gateway.php";

NetDebug.initialize();
var _service:Service = new Service(gatewayUrl, null, 'HelloWorld', null , null);
var pc:PendingCall = _service.say("Hello!");
pc.responder = new RelayResponder(this, "handleResult", "handleError");

function handleResult(re:ResultEvent)
{
    trace(re.result);
}

function handleError(fe:FaultEvent)
{
    trace("エラー");
}

トレースすると”You said: Hello!”が出力される。xmlを経由しなくてもphpとflashでオブジェクトのやりとりが出来るので便利。DBからセレクトしたデータをflashに直接渡したり、phpに配列を渡したりとかなりお手軽にできそう。ここまでくるとMovableTypeとかでxmlを出力してflashに読み込ませるCMS的パターンは壊滅なんじゃないかと。従来のXMLを読み込んでパースかけるやり方よりも高速に送受信ができるらしい。なるほど。

2007.06.15
category
tag
comments

外部画像を読み込んでスムージング

画像の読み込みをリスナーで捕まえるにはcontentLoaderInfoを使う。スムージングをかけるには読み込み完了時にビットマップ化して、スムージングプロパティをtrueにする。回転させるとスムージングがかかってるのが良く分かる。

var imgLoader:Loader = new Loader();
imgLoader.load(new URLRequest("画像のurl"));
imgLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);

//-----[読み込み中イベントの処理]
function onProgress(e:Event):void
{
    trace("progress = " + Math.round((e.bytesLoaded * 100) / (e.bytesTotal)));
}

//-----[読み込み完了イベントの処理]
function onComplete(e:Event):void
{
    //-----[スムージング処理]
    var loadedImage:Bitmap = Bitmap(imgLoader.content);
    loadedImage.smoothing = true;
    addChild(loadedImage);
    loadedImage.rotation = 15;
}
2007.05.17
category
comments

ドメイン間ポリシーファイルについて

異なるドメイン間でXMLとかをやり取りする場合、「crossdomain.xml」を設置する必要がある。Flash側にはcrossdomain.xmlが置かれているドメインを設定することでクロスアクセスが可能になる。アクセス許可の範囲はポリシーファイルの置かれたディレクトリ以下に限られる。毎回忘れるのでメモ。

Flash側に以下を記述。

System.security.loadPolicyFile("crossdomain.xmlのパス");

Flashからアクセスしたいサーバーにcrossdomain.xmlをアップする。
crossdomain.xml

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
	<site-control permitted-cross-domain-policies="all" />
	<allow-access-from domain="許可したいドメイン" />
</cross-domain-policy>
2007.04.12
category
comments

flashとjavascriptとphpでやりとりするには

flashとjavascriptのやり取りは「ExternalInterface」を使う。

function getJavascript()
{
   var obj = new Object();
   obj.infoTitle = document.URL;
   obj.infoUrl = document.title;
}
import flash.external.*;

if(ExternalInterface.available)
{
   infoObj = ExternalInterface.call("getJavascript");
   title.text = infoObj.infoTitle;
   url.text = infoObj.infoUrl;
}
else
{
   title.text = "ExternalInterfaceを利用することが出来ません";
}

javascriptからのデータがinfo.objの中に格納される。

続いて、flashとphpのやり取りは「sendAndLoad」を使う。

$message= $_POST["message"];
echo "responce=".$message."をflashに返します";
//-----[送受信オブジェクトのインスタンス化]
var loadLV:LoadVars = new LoadVars();
var sendLV:LoadVars = new LoadVars();

//-----[渡したい変数名と値を定義]
sendLV.message = "hoge";

//-----[コールバック関数を定義]
loadLV.onLoad = function(success)
{
   if (success == true)
   {
      trace(loadLV.responce);
   }
   else
   {
      trace("通信エラー");   //hogeをflashに返します"
   }
}

//-----[sendAndLoadメソッドを使ってデータの送受信を行う]
sendLV.sendAndLoad("phpファイルのパス", loadLV, "POST");
page 1 / 11