Kenji Tachibana's Weblog

« 前の日(Mar月 9日, 2009年) | 日付別メイン | 次の日(Mar月 11日, 2009年) »

http://blogs.sun.com/kenji/date/20090311 2009年 3月 11日 水曜日

JavaFX で Yahoo! map を - JavaFX から javascript を起動する -

数日前、営業部の方 (といっても、エンジニアの方ですが) から、「JavaFX から JavaScript を使いたいのですが?」というご質問をいただきました。
実は、以前から JavaFX から、google や yahoo の地図を起動できないかなぁ、と思っていました。これらの API は、javascript もしくは web サービスで提供されていて、JavaFX から、javascript を起動する方法を考えたのですが、あまりいい方法が見つからず挫折していたので、一瞬、「できないと思います」と答えようとしてしまいました。ところが、その後の説明を聞くと「Java から JavaScript を起動する方法は見つけたのですが、JavaFX から使えないでしょうか?」ということだったのです。
JavaFX では、ご存じの通り、Java のオブジェクトはほとんどそのまま利用できます。なので、「それならできるかも」と思い、サンプルコードを見せていただきました。

... 結局のところ、私は何の役にもたたず、その方が自己解決してくださり、JavaFX から JavaScript を起動する方法を教えていただきました。(ありがとうございます!)

その方法をもとに、以前挫折した、Yahoo Map を JavaFX から起動する方法について、書いておこうと思います(IDE は NetBeans を使っています)。



概略


サンプルで作成するのは、JavaFX で作ったテキストフィールドに、緯度と経度を入力し、ボタンを
押すとその地図を表示する、というものです。緯度と経度の取得方法は、 Yahoo!ディベロッパーズネットワーク を参考にしてください。
できあがりは、以下のようになります。

上の図では、サンマイクロシステムズ本社のある SBS タワーの緯度と経度 (35.62355719, 139.63583278) を入力して、表示した地図です。

JavaFX から JavaScript の関数を呼び出すには、JSObject を利用します。 Java から JavaScript への通信 に JSObject に関する記述がありますが、java1.4 時代のもので、内容的にはちょっと古そうです。なので、ほとんどの情報は、WWW を探して見つけてきたものです。

JSObject は、JRE の plugin.jar にあります。使い方を簡単に説明すると、getWindow メソッドで、
JSObject クラスのインスタンスを取得し、call メソッドで、HTML 上で定義されている javascript の関数を呼び出すことができます。


windonw = JSObject.getWindow(アプレット);
window.call("関数名", 引数);



その1: plugin.jar の追加


plugin.jar は、JRE の lib にあります。NetBeans で、JavaFX プロジェクトを作成し、 「Libraries」 を左クリックして、「Add JAR/Folder」を選択します。
NetBeans で JavaFX を使う方法は、 JavaFX プラグインを使ってみよう! を参照してください。

私の環境の場合、plugin.jar は以下のディレクトリにありました。

C:\Program Files\Java\jdk1.6.0_11\jre\lib\plugin.jar



その2: JavaScript を呼び出す JavaFX スクリプトの作成


次は、JavaScript を呼び出す JavaFX スクリプトの作成です。概要でふれましたが、JavaScript を起動するには、JSObject クラスを利用します。JSObject クラスの getWindow は、Applet クラスのオブジェクトを引数として取るので、まず、JavaFX が動作している Applet オブジェクトを取得する必要があります。Applet オブジェクトは、JavaFX に含まれる javafx.lang.FX クラスの getArgument メソッドを使って以下のように取得します。詳しくは、 JavaFX API doc を参照してください。

var applet: Applet = javafx.lang.FX.getArgument("javafx.applet") as Applet;

次に、getWindow メソッドを使って JSObject クラスのオブジェクトを取得します。その1で plugin.jar を追加してあれば、以下のように JSObject を取得できます。

var window = netscape.javascript.JSObject.getWindow(applet);

最後に、JSObject クラスの call メソッドを使って JavaScript の関数の呼び出しを行います。

window.call("関数名", 引数);

もし、JavaScript 関数から戻り値がある場合は、JavaFX 側の変数に代入することも可能です。
以下は、JavaScript から文字列を戻り値としてとる場合です。

var testval = window.call("関数名", 引数) as String;

JavaFX 側の説明はいったんここまでにします。というのは、呼び出される側の JavaScript がないと、呼び出せないので!



その3: JavaScript 側


次に Yahoo! Map を呼び出す JavaScript (HTML 内に記述) を作成します。Yahoo! Map の使い方は、
http://developer.yahoo.co.jp/webapi/map/maps/v2/js/ を参照してください。非常に簡潔に書いてあるので、読むだけで、一番簡単な地図は表示できるようになると思います。

次に、JavaFX から起動できるように、window.onload() 時ではなく、関数として指定して、任意の時点で地図を表示するように変更します。これらを head タグの間に定義しておきます。


<head>
<script type="text/javascript" src="http://map.yahooapis.jp/MapsService/js/V2/?appid=マップキー"></script>
<script langauge="javascript">
function Start() {
ymap = new YahooMapsCtrl("map");
}
</script>
</head>

マップキーは取得したマップキーを入力してください。

この Start() 関数を JavaFX 側から呼び出すことになります。
ここでは緯度、経度の引数はまだ考えていないので、この関数が実行されると、
Yahoo Japan の本社 (六本木ヒルズ) に飛ぶはずです。

次に body には、Yahoo! Map を表示する領域と、JavaFX スクリプトから生成されるアプレットを配置します。以下は Yahoo! Map を表示する領域です。


<div id="map" style="width:600px; height:300px"></div>

そして、アプレットは以下の通りです。JavaFX スクリプトをアプレットとして配備する方法の詳細は、櫻庭さんの「ついにベールを脱いだJavaFX:第13回 デプロイメントとアプレット を参照してください。


<script src="http://dl.javafx.com/1.1/dtfx.js"></script>
<script>
javafx(
{
archive: "JavaFXApplication5.jar",
draggable: true,
width: 200,
height: 200,
code: "javafxapplication5.Main",
name: "JavaFXApplication5"
}
);
</script>

この部分は、NetBeans が生成してくれる html (プロジェクトの dist ディレクトリに生成されます) をコピーしたものです。draggable は false でいいかもしれませんね。

この作成した HTML (ページの下部に最終的な HTML のリンクがあります) を dist に NetBeans で生成される HTML とは別の名前で保存しておきます。右クリックから、「表示」選ぶと、ブラウザから表示することができます。



その4: 再び JavaFX 側


呼び出す JavaScript ができあがったので、JavaFX 側に戻ります。
残りは簡単で、テキストフィールドと、ボタンを作成して、ボタンをクリックしたら、JSObject の call メソッドを使って JavaScript の Start() 関数を呼び出します。

var nsew = "latitude, longitude";
(略)
SwingTextField {
columns: 20
text: bind nsew with inverse
editable: true
},
SwingButton {
text: "Yahoo Map"
onMouseClicked: function( e: MouseEvent ):Void {
var args: String[] = [nsew];
window.call("Start", args);
}
}

テキストフィールドに入力された文字列 (緯度と経度)は、nsew 変数にバインドされています。
ボタンを押したときに、この nsew を配列として JavaScript 側に渡します。

JavaFX の完全なソースは、 ここ にあります。



その5: 引数(再び JavaScript)

これで完成かと思ったのですが、window.call("Start", args); で渡した引数 args がなかなかハンドルできませんでした。いろいろ探し回ったあげく、ここに回答が書いてありました。

http://chaichan.web.infoseek.co.jp/qa6000/qa6015.htm
argument[] に渡されているんですね。
なので、JavaScript の Start() 関数を下記のように変更しました。


function Start() {
ymap = new YahooMapsCtrl("map", String(arguments[0]));
}

これで完成です!

作成した HTML を ここ においておきました。ただしリンクをクリックすると html として表示してしまうので、ファイルにセーブしてから参照してください。

最後に一点だけ誤解の無いように付け足しておきます。この方法では、あくまで JavaScript の関数を呼び出しているだけなので、Yahoo! Map 自体を JavaFX 側で操作することはできません。つまり、表示させたマップを回転させたり、拡大させたりはできないです。これは Yahoo Japan に対応していただくしか方法はないですかね...


Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.