[AS]空っぽの文字列はNumberキャストで0

xmlの読み込みとかで、要素が空っぽだった場合の判定処理とかに。

var str:String;
trace(0== Number(str))//出力:true

※5/17追記
上記の例だと要素に”0″とか”0000″とかが入ってたときもtrueになっちゃいます。

var str:String = "000"
trace(0== Number(str))//出力:true

[AS]XMLを更新したのにswfに反映されない場合(キャッシュ対策)

Xmlを読み込む際には、URLにユニークな変数を追加して、かならず再読み込みをさせたほうがいいみたい。
基本のURLのままだと、変更しても再読み込みの際、キャッシュから読んで新たに読み込んでくれない。

URL(String)にユニークな変数を追加する関数

import flash.net.LocalConnection;

//基本のURL
var xml_str:String = "http://hoge.com/hoge.xml";
//基本のURLにユニークな変数を追加
xml_str = setNoCashURL(xml_str);

private function setNoCashURL(url_str):String {
	//サーバーにあがってるか同かを調べるため
	var lc:LocalConnection = new LocalConnection();
	//現在のドメイン名を取得
	var domain_str:String = lc.domain;
	//ドメイン名がlocalhostの時はローカルでのテストなので変数はつけない。
	//(変数がついてるとローカルではxmlが読みこまれないみたい)
	if (domain_str != "localhost") {
		//現在時刻を取得することでユニークな数値を取得
		var noCash:Number = new Date().getTime();
		//URLに追加できる形にして数値を文字列化
		var noCash_str:String = "?nocash="+String(noCash);
	} else {
		noCash_str = "";
	}
	
	url_str += noCash_str;
	//変数を追加した文字列を返す
	return url_str;
}

[AS][JS]FLASHで「このページのトップに戻る」ボタンの設定

FLASHでブラウザのスクロールバーを最上部に戻す方法で、最初出来たと思いきや不完全だったのでメモ。

基本設定は以下の通り。
ステージサイズを500×1000くらいにしておく
インスタンス名:_mcのムービークリップをステージの下の方に配置。

まず最初のイマイチアプローチから
以下フレームアクション

//AS:フレームアクション
_mc.addEventListener(MouseEvent.CLICK , xClick);
function xClick (e):void {
	var tf = new TextField();
	addChild(tf);
	tf.text = "リロードしてないよ";    
	navigateToURL(new  URLRequest("#","_self"));
}

これだけで出来ました。
ジャンプ先を#にするとブラウザリロードせずにページの先頭にジャンプできました。
先頭にはリロードしてないよの文字が表示されます。

で、これでいいや、と思いきや・・・
winのSafari3ではブラウザリロードしてしまいテキストが表示されません。
WINのIE6,7、FF3はリロードされなかったんですがね。。。
(HTMLの解釈的にはSafariの方が正しいっぽいような気がしますが)

というわけで別のアプローチ。
jsでスクロールバーを制御する方法。

js自体のソースはこちらのブログを参考にしました。
※イージングでゆっくりページのトップに戻るような処理のjsです。

//JS:HTMLに埋め込むか、jsファイルとしてhtmlで読み込むか
function backToTop() {
    var x1 = x2 = x3 = 0;
    var y1 = y2 = y3 = 0;

    if (document.documentElement) {
        x1 = document.documentElement.scrollLeft || 0;
        y1 = document.documentElement.scrollTop || 0;
    }

    if (document.body) {
        x2 = document.body.scrollLeft || 0;
        y2 = document.body.scrollTop || 0;
    }

    x3 = window.scrollX || 0;
    y3 = window.scrollY || 0;

    var x = Math.max(x1, Math.max(x2, x3));
    var y = Math.max(y1, Math.max(y2, y3));

    window.scrollTo(Math.floor(x / 2), Math.floor(y / 2));

    if (x > 0 || y > 0) {
        window.setTimeout("backToTop()", 25);
    }
}

上記関数をhtmlに仕込んでおいて、Flash側には以下のように設定

//AS:フレームアクション
_mc.addEventListener(MouseEvent.CLICK , xClick);

// 呼びたいJSの関数名
var callJasFunction:String = "backToTop";

// JavaScriptの実行
function xClick (e):void {
	var tf = new TextField();
	addChild(tf);
	tf.text = "リロードしてないよ";
	ExternalInterface.call(callJasFunction)
}

これでOKなのですが、Htmlにjs仕込むのが面倒くさい。
できることならFLASHだけで完結できないか、と。
と思ったら、こんな書き方でもFLASH上でJSを実行できるらしい。

//AS:フレームアクション
_mc.addEventListener(MouseEvent.CLICK , xClick);

// 呼びたいJSの関数
var callJasFunction:String = "function backToTop() {var x1 = x2 = x3 = 0;var y1 = y2 = y3 = 0;if (document.documentElement) {x1 = document.documentElement.scrollLeft || 0;y1 = document.documentElement.scrollTop || 0;}if (document.body) {x2 = document.body.scrollLeft || 0;y2 = document.body.scrollTop || 0;}x3 = window.scrollX || 0;y3 = window.scrollY || 0;var x = Math.max(x1, Math.max(x2, x3));var y = Math.max(y1, Math.max(y2, y3));window.scrollTo(Math.floor(x / 2), Math.floor(y / 2));if (x > 0 || y > 0) {window.setTimeout('backToTop()', 25);}}";

// JavaScriptの実行
function xClick (e):void {
	var tf = new TextField();
	addChild(tf);
	tf.text = "リロードしてないよ";
	ExternalInterface.call(callJasFunction)
}

ようは、関数名のところに関数全部書いちゃってもOKみたい。
これなら、Html変更しなくていいから楽チンだ!
と思いきや、これだと不具合ありました・・・

jsの再帰処理的な部分が実行されず、最初の一回しか実行されてないっぽい。
↓ここの部分

//上述したJSの一部を抜粋
if (x > 0 || y > 0) {
    window.setTimeout("backToTop()", 25);
}

でも最初の一回は実行されるので、一回でトップに戻るようなjsなら問題なくページの頭だしは可能。
jsをこれだけにすれば、とりあえずイージングなしの頭だしは可能でした。

//AS:フレームアクション
_mc.addEventListener(MouseEvent.CLICK , xClick);

// 呼びたいJSの関数
var callJasFunction:String = "function backToTop() {window.scrollTo(0, 0);}";

// JavaScriptの実行
function xClick (e):void {
	var tf = new TextField();
	addChild(tf);
	tf.text = "リロードしてないよ";
	ExternalInterface.call(callJasFunction)
}

※2009/5/12追記

以下の書き方で再帰処理も可能でした。
document.insertScriptなんてものを使えばよいのだね。
JSよくわかんね。

_mc.addEventListener(MouseEvent.CLICK , xClick);

// 呼びたいJSの関数名
var callJasFunction:String = "document.insertScript = function(){ backToTop = function() {var x1 = x2 = x3 = 0;var y1 = y2 = y3 = 0;if (document.documentElement) {x1 = document.documentElement.scrollLeft || 0;y1 = document.documentElement.scrollTop || 0;}if (document.body) {x2 = document.body.scrollLeft || 0;y2 = document.body.scrollTop || 0;}x3 = window.scrollX || 0;y3 = window.scrollY || 0;var x = Math.max(x1, Math.max(x2, x3));var y = Math.max(y1, Math.max(y2, y3));window.scrollTo(Math.floor(x / 2), Math.floor(y / 2));if (x > 0 || y > 0) {window.setTimeout('backToTop()', 25);}}}"; 
var method = " backToTop";
//上記関数を読み込み(この段階では、関数backToTopは実行されないみたい)
ExternalInterface.call(callJasFunction)
// JavaScriptの実行
function xClick (e):void {
//ここで初めて実行されるみたい。
ExternalInterface.call("backToTop")
}

[AS]配列の中身をシャッフルする方法

忘れるのでメモ

function shuffleArray(myArray:Array){
	var i:Number = myArray.length;
	while(i){
		var randomNumber:Number = Math.floor(Math.random()*(i--));
		var temp:Object = myArray[i];
		myArray[i] = myArray[randomNumber];
		myArray[randomNumber] = temp;
	}
}

[AS]swfからcsvファイルをダウンロードするには

いろいろググってみても「出来ない」という結論しか見当たらなかったのだけど、どうやらAS2を対象にした結論だったのか、AS3なら簡単にできるようす。
(csvに限らず、ファイルならなんでも保存OKな感じ)

ステージに_mcというインスタンス名をつけたMCを配置して、フレームアクションに

var file:FileReference = new FileReference();

//ステージに_mcというインスタンス名をつけたMCを配置
_mc.addEventListener(MouseEvent.CLICK , xClick);

function xClick (e:MouseEvent):void {
	try{
		//ダウンロードしたいファイルのURLをURLRequestする。
		file.download(new URLRequest("http://393.bz/sam/data.csv"));
	} catch(e:Error){
		//エラー時の処理
		trace("error");
	}
}

[AS][PHP]GMT(正確にはUTC)タイムを取得する方法

ローカルの時間(PCに設定されてる時計による)ではなく、正確な時間を取得したい場合。
ただFLASH単体では、UTC(GMTみたいなもの)の取得はできないようす。
なのでサーバーサイドのプログラムPHPを使ったら意外と簡単にできました。

↓PHPはこれだけ

<?php
//GMTを取得
$time09 = gmdate("D M d Y H:i:s", time()+9*60*60);
//ASでは、utc_timeというプロパティで扱える
echo "utc_time=".$time09
?>

FLASH側はこんな感じで、読み込みます。
以下、フレームアクション

//フレームアクション
//PHPファイルのURLを定義
var request:URLRequest = new URLRequest ( "get_utc.php" );
//送信方法をPOSTに
request.method = URLRequestMethod.POST;

//ローダーを作って、PHPを読み込み(実行)
var loader:URLLoader = new URLLoader (request);
loader.addEventListener(Event.COMPLETE, onComplete);
loader.load(request);

//PHP読み込み(実行)後の処理
function onComplete(event:Event):void {
	//↓PHPからの戻り値を変数に格納
	var vars:URLVariables = new URLVariables( event.target.data );
	//UTCデータを格納するための変数
	var utc:String;
	//データがちゃんとあった場合は、
	if (vars.utc_time!= undefined) {
		//変数に、文字列を渡す
		utc = vars.utc_time;
		next(utc);
		//ムービープレビューのときはローカルタイムを取得
	} else {
		var date:Date = new Date();
		utc = date.toString();
		next(utc);
		tf.text = "↓ローカルタイムです";
	}
}
//PHPから読み込んだ文字列を引数にしてDateインスタンスを作成で完了
function next(utc) {
	var date:Date = new Date(utc);
	tf2.text = String(date);
}

//結果表示用のテキストフィールド(2つ用意)
var tf:TextField = new TextField();
tf.autoSize ="left";
addChild(tf);
var tf2:TextField = new TextField();
tf2.autoSize ="left";
addChild(tf2);
tf2.y = 30;

ポイントはPHPから取得した文字列をそのままDateクラスのコンストラクタの引数に突っ込めば、その情報を持ったDateインスタンスが作れるところですかね。
(逆に言うと、PHPで取得する文字列は、Dateクラスで認識できる形にしてあげる必要があるってことかね)

ただこの場合の「UTCタイム」はサーバーの時計ってことになるのかな?
ってことは、サーバーの時計が狂ったらアウトってことなんだろうね。

[AS]XMLで要素数が何個あるかわからないデータを取得する時の方法 (for each ( in )の使い方) 

フレームアクションでこんな感じ。

var xml:XML = 
<sampleXML>
<test>まるいち</test>
<test>まるに</test>
<test>まるさん</test>
<test>まるよん</test>
<test>まるご</test>
</sampleXML>;

trace(xml);

var xmlArray:Array = new Array();

var sampleXMLList:XMLList = xml.test;

//配列にtest要素を突っ込む
for (var i:uint = 0; i< sampleXMLList.length(); i++) {
	xmlArray.push(xml.test[i]);
}
//配列の中身を確認
for (i = 0; i < xmlArray.length; i++) {
	trace("xmlArray その1 : "+xmlArray[i]);
}

//配列を空にする。
xmlArray = [];

//配列にtest要素を突っ込む
for each (var container:Object in xml.test) {
	xmlArray.push(container);
}
//配列の中身を確認
for (i = 0; i < xmlArray.length; i++) {
	trace("xmlArray その2 : "+xmlArray[i]);
}

プレビュー時の出力はこんな感じ

まるいち
まるに
まるさん
まるよん
まるご

xmlArray その1 : まるいち
xmlArray その1 : まるに
xmlArray その1 : まるさん
xmlArray その1 : まるよん
xmlArray その1 : まるご
xmlArray その2 : まるいち
xmlArray その2 : まるに
xmlArray その2 : まるさん
xmlArray その2 : まるよん
xmlArray その2 : まるご

注意するのは
Arrayの中身を数えるのは、Array.length
XMLListの中身を数えるのは、XMLList.length();
微妙に違うところ。

あとfor each (in)分を使えば、データの数がわからなくとも、データがあるだけループさせられる。

[AS]読み込んだXMLの内容を改行したときに余分な改行があった場合

読み込んだXMLをTextFieldに表示させるときに、
XML側では、こんな感じで書くとその中の改行がそのまま表示できる。

<?xml version="1.0" encoding="UTF-8"?>
<sample>
<description>
<![CDATA[あかさなた
はまやらわ]]>
</description>
</sample>

ただその際に改行コードの問題で、一回しか改行してないつもりでも2行で改行されてしまうときがある。

↓こうでてほしいのに
あかさなた
はまやらわ

↓こうなる
あかさなた

はまやらわ

Windowsの改行コードの問題なので、
xmlから読み込んだストリングの改行コードを変換してあげればOK

//xmlから読み込んだストリングの
var strictDescription:String = xml.description[0];
//改行コードを\nに統一する。
strictDescription = strictDescription.replace(/\r\n/g, '\n');

[AS]FMSからストリーミングした動画の表示拡大するときはVideoオブジェクトを直接拡大しないとだめっぽい。

ストリーミングした動画を拡大するときはVideoオブジェクトを直接操作したほうがいいっぽい。

たとえば、MovieClipクラスを拡張して、Videoを再生するクラスがあったとする。

package  {
	import flash.display.MovieClip;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.events.NetStatusEvent;
	import flash.net.NetStream;
	
	public class LoadMovie extends MovieClip {
		
		private var ncUrl:String
		private var nsUrl:String
		private var nc:NetConnection;
		private var video:Video;
		
		public function LoadMovie(ncUrl:String, nsUrl:String, w:uint = 320, h:uint = 320 ) {
			trace("FmsMain");
			this.ncUrl = ncUrl;
			this.nsUrl = nsUrl;
			
			video = new Video();
			video.width = w;
			video.height = h;
			initConnect();
		}
		
		function initConnect():void {
			
			//ネットコネクションを作る
			nc = new NetConnection();
			nc.client = new Object();
			//ネットコネクションの接続状態を調べるリスナー
			nc.addEventListener(NetStatusEvent.NET_STATUS , onNcStatus);
			//ネットコネクションを接続する。
			nc.connect(ncUrl);
		}
		//ネットコネクションの状態でいろいろ出力される
		private function onNcStatus(e:NetStatusEvent):void {
			trace("onNcStatus : "+e.info.code);
			switch (e.info.code) {
				//もし無事に接続されたら、
				case "NetConnection.Connect.Success":
				initStream();
				break;
				case "NetConnection.Connect.Failed":
				trace("onNcStatus : "+e.info.code);
				break;
				case "NetStream.Play.StreamNotFound":
				trace("not Found");
				break;
				default :
				break;
			}
		}
		
		//ネットストリームの初期化処理
		private function initStream():void {
			//ネットコネクションを作る
			var ns:NetStream = new NetStream(nc);
			//ネットコネクションの接続状態を調べるリスナー
			ns.addEventListener(NetStatusEvent.NET_STATUS, onNsStatus);
			//読み込みの時間を設定
			ns.bufferTime = 2;
			//メタデータ取得用のオブジェクトを設定
			ns.client = new Object();
			//videoインスタンスを作成
			video.attachNetStream(ns);
			addChild(video);
			ns.play(nsUrl);
		}
		
		private function onNsStatus(e:NetStatusEvent):void {
			switch (e.info.code) {
				//もし失敗したら
				case "NetStream.Play.StreamNotFound":
				trace("NetStream Not Found");
				break;
				
				default :
				trace("onNsStatus : "+e.info.code);
			}
		}
		
	}
	
}

このクラスを利用するときはフレームアクションで、
(ローカルにelevator.flvがあるのが前提)

var ncUrl:String = null
var nsUrl:String = "elevator.flv"
var fms2:LoadMovie = new LoadMovie(ncUrl,nsUrl);
addChild(fms2);

この動画のサイズを変えたいときに

var ncUrl:String = null
var nsUrl:String = "elevator.flv"
var fms2:LoadMovie = new LoadMovie(ncUrl,nsUrl);
addChild(fms2);
fms2.width = 500;
fms2.height = 500;

まあlこれでも拡大されるのは予想通り。
ただしFMSのflvを読んでる場合は拡大されるずに動画が非表示になる。
(音はなってるから再生はされてるようす)

//これだと動画がなぜか表示されない
var ncUrl:String = "rtmp://hoge.moge"
var nsUrl:String = "doke"
var fms2:LoadMovie = new LoadMovie(ncUrl,nsUrl);
addChild(fms2);
fms2.width = 500;
fms2.height = 500;

LoadMovieクラスには、引数w,hでvideoオブジェクトのwidth、heightを操作できるようにしてあるので、

//これなら動画の大きさを操作できる。
var ncUrl:String = "rtmp://hoge.moge"
var nsUrl:String = "doke"
w = 500;
h = 500;
var fms2:LoadMovie = new LoadMovie(ncUrl,nsUrl,w,h);
addChild(fms2);

もちろんローカルのflvを再生するときもこのVideoオブジェクトを操作する方法でOK。
なので、つねにこっちの方法を使った方が安全っぽい。


上記の例でFMSから読み込んだ場合のLoadMovieオブジェクトのwidthとheightは、w,hをどんな値を設定しても0になるようだ。
(ローカルflvを読み込んだ場合は指定した数値となる)

//FMSの場合
var ncUrl:String = "rtmp://hoge.moge"
var nsUrl:String = "doke"
w = 500;
h = 500;
var fms2:LoadMovie = new LoadMovie(ncUrl,nsUrl,w,h);
addChild(fms2);
trace(fms2.width) //出力:0
trace(fms2.height) //出力:0

ローカルflvを読み込んだ場合

//ローカルFLVの場合
var ncUrl:String = null
var nsUrl:String = "elevator.flv"
w = 500;
h = 500;
var fms2:LoadMovie = new LoadMovie(ncUrl,nsUrl,w,h);
addChild(fms2);
trace(fms2.width) //出力:500
trace(fms2.height) //出力:500

FMSから読み込んだものは実体がないということなのかな?

[AS]FMSを使った動画再生をするときの設定の注意点

FMS:Flash Media Server
ローカルのflvのprogressive再生のときとFMSでの設定の違いをメモしとく
NetConnectionの設定で
ローカルflvの時は

//ローカルのflvを再生するとき
var nc:NetConnection = new NetConnection();
nc.connect(null);

FMSのときは、

//FMSを使うとき
var nc:NetConnection = new NetConnection();
nc.connect("rtmp://hoge.moge.ore.dore");
nc.client = new Object();

FMSのときはnc.connectにURLを設定(flvファイルの手前のフォルダまで)
※上の例はURLが rtmp://hoge.moge.dore.flvだった場合
あと、nc.client、ローカルflvでは設定しなくていいけど、FMSのときは設定してあげないとエラーになる。

あとNetStreamの設定
ローカルflvのときは、

var ns:NetStream = new NetStream(nc);
ns.play("doke.flv")

FMSのときは

var ns:NetStream = new NetStream(nc);
ns.play("doke")

FMSのときは、.flvをつけると宜しくないようす。

情報追記:2011/02/22
http://memo.393.bz/archives/1480