Hatena::ブログ(Diary)

jiroの日記 このページをアンテナに追加 RSSフィード

2008-08-02

[]YAHOOのcrossdomain.xmlが外部からアクセス不可に変更された

http://api.jlp.yahoo.co.jp/crossdomain.xml

<cross-domain-policy>

<allow-access-from domain="*.yahoo.co.jp" secure="false" />

</cross-domain-policy>

今日恋文判定器を触ってみたら、動かなくなってた。なんでだ!?と思って除いてみるとYAHOOのcrossdomain.xmlがかわってましたよ。これじゃActionScriptから使えないじゃないですか!!なんかで教えてくれても良いのに、、、

2008-05-19

[][]Flex3のローカライズを使用する

http://livedocs.adobe.com/flex/3_jp/html/l10n_3.html#727650

に書いてあるけど、一応メモ。

まず、

copylocale en_US ja_JP

で日本用のロケールを作成します。これは、frameworks/locale/locale_nameにフレームワークのロケールを作成します。

一度はこのコマンドを実行しておかないと、コンパイル時にそんなディレクトリないよと怒られてしまうので、はまらないようにしましょう。

次にconfigを設定します。

<flex-config>
	<compiler>
		<locale>
			<locale-element>en_US</locale-element>
			<locale-element>ja_JP</locale-element>
		</locale>
		<source-path>
			<path-element>../locale/{locale}</path-element>
		</source-path>
	</compiler>
</flex-config>

要するに、使用するロケールの定義をすることと、ロケールのディレクトリがソースパス入るように設定します。

ちなみに{locale}というのがそれぞれ、en_USとか、ja_JPとなるみたい。ないと怒られるのでmkdirしておきましょう。

次にすることは../locale/ja_JP/Fuga.propertiesを作成すること。もちろんen_USにも。

hoge=ほげ

あとは、ソースコードにリソースバンドルを使用するように記述してあげるだけ。

<mx:Label text="@Resource(key='hoge', bundle='Fuga')"/>

動的に言語を選択させるには

ResourceManagerを使用します。ResourceManagerのlocaleChainに使用するロケールを設定する事で、動的に表示言語を変更する事ができます。

ちなみにresourceManagerプロパティでResourceManagerのインスタンスにアクセスできます。つまり、

resourceManager.localeChain = ["en_US"];

とか

resourceManager.localeChain = ["js_JP"];

とかすれば良い訳です。なんですが、ここではまりました。@Resource(key=....という書き方だとBindしてくれていないみたいで一向に値が変わりませんでした。

なので、次のようにmxmlに記述します

<mx:Label text="{resourceManager.getString('Fuga', 'hoge')}"/>

これでやっと切り替える事ができるようになります。

ちなみに、なんで配列になっているのかというと、優先順位を決められるのだそうです。インデックスの頭の方から優先的に使用するキーを探しにいき、

一つでもキーが見つからない場合は、次のインデックスの言語をためします。

最後までいっても見つからない場合は、ロケールが見つからなかったと判断し、getStringしてもnullしか帰ってきません。

だから、文字列が軒並み空白になっているときは、localeChainか、キーが設定されていないのではないかと疑いましょう。

初期表示はユーザの言語に合わせたい

Accept-Language HTTP ヘッダーや Capabilities.languageを利用してユーザの言語を初期化時に設定します。


Capabilities.languageにはFlash PlayerやAirの環境の言語コードが入っています。

言語コードだけで、国情報は入っていないので、このままlocaleChainに突っ込んでも、ロケールは見つからず、全ての欄がnull(空文字)になってしまうので注意。

国情報を付加してlocaleChainを設定します。

if (Capabilities.language == 'ja') resourceManager.localeChain = ['ja_JP'];

Accept-Languageはどうやって取得するのかわからないのですが、JavaScriptでAccept-Languageを取得して、それをflashVarsに渡してあげるのではないかと思います。

2008-03-17

[]BlendModeの確認サンプル

勉強途中です。確認用にこんなものを作ってみた。でもソースも見ないとうまく伝わらないな。

見せ方を考えないとだめだ。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import mx.core.*;
import mx.controls.*;
import mx.events.*;
import mx.containers.*;

[Bindable]
private var modes:Array = [
	{label:'NORMAL', data: BlendMode.NORMAL},
	{label:'ADD', data: BlendMode.ADD},
	{label:'ALPHA', data: BlendMode.ALPHA},
	{label:'DARKEN', data: BlendMode.DARKEN},
	{label:'DIFFERENCE', data: BlendMode.DIFFERENCE},
	{label:'ERASE', data: BlendMode.ERASE},
	{label:'HARDLIGHT', data: BlendMode.HARDLIGHT},
	{label:'INVERT', data: BlendMode.INVERT},
	{label:'LAYER', data: BlendMode.LAYER},
	{label:'LIGHTEN', data: BlendMode.LIGHTEN},
	{label:'MULTIPLY', data: BlendMode.MULTIPLY},
	{label:'OVERLAY', data: BlendMode.OVERLAY},
	{label:'SCREEN', data: BlendMode.SCREEN},
	{label:'SUBTRACT', data: BlendMode.SUBTRACT}
];

private var startX:Number;
private var startY:Number;
private var startElX:Number;
private var startElY:Number;
private var target:UIComponent;
private function initRect(a:Number = 1):void {
	var g:Graphics = rect.graphics;
	g.clear();
	g.beginFill(0xff0000, a);
	g.drawRect(0, 0, 100, 100);
	g.endFill();
}
private function initCircle(a:Number = 1):void {
	var g:Graphics = circle.graphics;
	g.clear();
	g.beginFill(0x00ffff, a);
	g.drawCircle(50, 50, 50);
	g.endFill();
}

private function onMouseDown(event:MouseEvent):void {
	event.stopPropagation();
	target = UIComponent(event.target);
	startX = event.stageX;
	startY = event.stageY;
	startElX = target.x;
	startElY = target.y;
	canvas.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
	canvas.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}

private function onMouseMove(event:MouseEvent):void {
	var currentX:Number = event.stageX;
	var currentY:Number = event.stageY;
	var deltaX:Number = currentX - startX;
	var deltaY:Number = currentY - startY;
	target.x = startElX + deltaX;
	target.y = startElY + deltaY;
}

private function onMouseUp(event:MouseEvent):void {
	canvas.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
	canvas.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
]]>
</mx:Script>
<mx:HBox>
	<mx:Canvas horizontalScrollPolicy="off" verticalScrollPolicy="off">
		<mx:Image source="@Embed(source='assets/palau.jpg')"/>
		<mx:Canvas backgroundColor="0" alpha="{canvasAlpha.value / 100}" width="100%" height="100%" id="canvas" horizontalScrollPolicy="off" verticalScrollPolicy="off">
			<mx:UIComponent id="rect" width="100" height="100" creationComplete="initRect();" mouseDown="onMouseDown(event);"/>
			<mx:UIComponent id="circle" width="100" height="100" creationComplete="initCircle();" mouseDown="onMouseDown(event);"/>
		</mx:Canvas>
	</mx:Canvas>
	<mx:VBox>
		<mx:Label text="キャンバスのBlendMode"/>
		<mx:ComboBox id="canvasBlendMode" dataProvider="{modes}" close="canvas.blendMode = ComboBox(event.target).selectedItem.data" rowCount="{modes.length}"/>
		<mx:Label text="キャンバスの透明度"/>
		<mx:HSlider id="canvasAlpha" value="50" minimum="0" maximum="100" liveDragging="true"/>
		<mx:CheckBox id="canvasBlurFilter" label="BlurFiter" change="canvas.filters = canvasBlurFilter.selected ? [new BlurFilter()] : [];"/>
		<mx:Label text="四角のBlendMode"/>
		<mx:ComboBox id="rectBlendMode" dataProvider="{modes}" close="rect.blendMode = ComboBox(event.target).selectedItem.data" rowCount="{modes.length}"/>
		<mx:CheckBox id="rectBlurFilter" label="BlurFiter" change="rect.filters = rectBlurFilter.selected ? [new BlurFilter()] : [];"/>
		<mx:Label text="四角の透明度"/>
		<mx:HSlider id="rectAlpha" value="100" minimum="0" maximum="100" liveDragging="true" change="initRect(event.value / 100)"/>
		<mx:Label text="円のBlendMode"/>
		<mx:ComboBox id="circleBlendMode" dataProvider="{modes}" close="circle.blendMode = ComboBox(event.target).selectedItem.data" rowCount="{modes.length}"/>
		<mx:CheckBox id="circleBlurFilter" label="BlurFiter" change="circle.filters = circleBlurFilter.selected ? [new BlurFilter()] : [];"/>
		<mx:Label text="円の透明度"/>
		<mx:HSlider id="circleAlpha" value="100" minimum="0" maximum="100" liveDragging="true" change="initCircle(event.value / 100)"/>
	</mx:VBox>
</mx:HBox>
</mx:Application>

2008-03-08

[][]FlexでTweenerを使用するときの注意点

mxmlでアプリケーションを作っていると、addChildした瞬間と、実際にエレメントが表示される時間が異なる。


Flexを使っていなければ、すぐに表示されるけど、Flexを使用している場合はpreinitialize, initialize, creationComplete等のイベントを発行し、順次エレメントを作成する。そして、creationCompleteが呼ばれるタイミングで表示される。

だから、下のようなコードはうまく動かず、tweenが終わった頃にエレメントが表示されてしまって、タイミングがあわない。

private function createBox(event:MouseEvent):void {
        var box:Study16Box = new Study16Box();
        var gP:Point = new Point(event.stageX, event.stageY);
        var lP:Point = c.globalToLocal(gP);
        box.x = lP.x;
        box.y = lP.y;
        c.addChild(box);
        Tweener.addTween(box, {time: 1, x: lP.x + 100, transition: 'easeOutBack'});
}

こんなふうになる。


つまり、creationCompleteの時点で表示されるのであれば下のようにコードを書けば良い

private function createBox(event:MouseEvent):void {
        var box:Study16Box = new Study16Box();
        var gP:Point = new Point(event.stageX, event.stageY);
        var lP:Point = c.globalToLocal(gP);
        box.x = lP.x;
        box.y = lP.y;
        c.addChild(box);
        box.addEventListener('creationComplete', function(event:Event):void {
                Tweener.addTween(box, {time: 1, x: lP.x + 100, transition: 'easeOutBack'});
        });
}

で、こんな風になる

見やすいように無名関数で書いたけど、Study16Boxの中に書くのが奇麗かな。

2008-03-01

[][]膨大な数のエレメントを作成する

もうなんていうか、膨大な数のデータって本当に嫌いになりました。普通に表示するだけなら簡単なくせに、数が膨大になると今まで考えなかった方法でなんとかしなきゃいけなくて、、、AS3でもエレメントの生成には結構時間かかっちゃうし、あー!もーやだ!と思って、がりっとやっつけました。ここは一般受けしやすいようにJavaScriptで実装した。


で、できたのがこれ。

JavaScriptで膨大な数のエレメントを作成する


ユーザが見ている場所をとにかく一番最初に表示したいですよね。

  1. エレメントのデータを保持し、Domは作成しない
  2. 現在見ているビューの中心から近くに描画される順にデータをソート
  3. ソートしたデータをもとに描画
  4. ViewのonScrollイベントが発生したら、2からやり直し

ブラウザだと、一度作ってしまえばスクロール時にも問題にならないから、作ったエレメントはそのままにしておき、FlexのIDataRendererのようにインスタンスを使い回すような事はしていません。これで膨大な量のデータでも、結構使えるUIになるんじゃないかな


この考え方はもちろんAS3でも通用しますよね!?しかし、4時間もこれだけにかけてしまった。。。。寝なきゃダー