前回の第8回「オブジェクトの位置と大きさをランダムにする」では、真ん中のオブジェクトの周りに、ランダムな位置と大きさで複数のオブジェクトを置いて、カメラで回り込んだ。今回は、これらのオブジェクトへのマウスインタラクションを加えよう。オブジェクトのマウスイベントをどう扱うかが課題だ。
オブジェクトへのマウスクリックでURLを開く
まず、立方体をクリックしたとき、そのオブジェクトに割り当てたURLを開きたい。それぞれが開くURLは、あらかじめオブジェクトに定める。扱いやすいように、URLの文字列は配列にまとめて変数(urls)に納めておくとよい。初期設定の関数(initialize())が真ん中のオブジェクトにURLをプロパティ(url)として加えたうえ、オブジェクトを複製する関数(cloneMesh())でも同じ名前のプロパティに配列エレメントのURLを与えた。
さて、マウスによるクリックはイベント定数MouseEvent.CLICKで扱う。お約束どおり、EventDispatcher.addEventListener()メソッドでリスナー関数を加え、その中にオブジェクトがクリックされたときの処理を書けばよい。
オブジェクトをつくる関数(createCube())と複製する関数(cloneMesh())が定めたリスナー(onClick())は、クリックしたオブジェクトに割り当てられたURLを開く。マウスイベントの起こったオブジェクトは、リスナー関数が引数に受取ったイベントオブジェクト(eventObject)のobjectプロパティから得られる[1]。そこで、オブジェクトのプロパティ(url)に定めておいたURLを、window.open()メソッドで開けばよい。
これで、オブジェクトをクリックすると、それぞれに定められたURLのサイトが開く(図1)。まとめたスクリプトは、以下のコード1のとおりだ。
ロールオーバーとロールアウトでオブジェクトの大きさを変える
つぎに扱うマウスイベントは、ロールオーバーとロールアウトだ。ポインタの重なったオブジェクトは大きくして、マウスインタラクションを示したい。ロールオーバーとロールアウトは、それぞれ定数MouseEvent.MOUSE_OVERとMouseEvent.MOUSE_OUTのイベントにリスナー関数を加えて扱う(表1)。
表1 マウス操作を扱うMouseEventクラスのイベント
マウス操作 | イベント |
クリック | MouseEvent.CLICK |
ロールオーバー | MouseEvent.MOUSE_OVER |
ロールアウト | MouseEvent.MOUSE_OUT |
立方体のオブジェクトそれぞれに3つのイベントリスナーを加えるので、そのための関数(setMouseListener())を別に定めることにしよう。引数は立体のオブジェクトに続けて、つぎのように3つのマウスイベントのリスナー関数を渡す。
オブジェクトにマウスポインタがロールオーバーしたら大きさを5割増し、ロールアウトでもとに戻るようにしたい。すると、前掲コード1をつぎのように書き替えればよさそうに思うかもしれない。しかし、これでは望む動きにはならない。
オブジェクトの大きさを定める関数(setScale())は、DisplayObject.transformプロパティから参照したTransformオブジェクトのTransform.scaleプロパティを操作している。このとき、定める大きさの比率(scale)は、複製もとにした真ん中の立体が1となる。つまり、1を与えれば真ん中の立体と同じ大きさになり、1.5はさらにその5割増しだ。
ランダムに定めたそれぞれのオブジェクトの大きさをもとにしようとするなら、その比率を覚えておかなければならない。そこで、オブジェクトの大きさは、つぎのようにふたつの関数に分けて扱うことにする。ひとつはオブジェクトに与えた大きさの比率をプロパティ(scale)に定める関数(setScale())だ。そして、さらにそこから呼び出すもうひとつの関数(changeScale())が、そのプロパティ値にもとづいて、オブジェクトの大きさを引数の比率に変える。
これでランダムな大きさでちりばめた立方体のオブジェクトが、ロールオーバーすると大きくなり、ロールアウトでもとに戻る(図2)。マウスインタラクションが示されるため、クリックへと導きやすくなった。
これでできたと思いきや、しばらく試していると気になるふるまいがある。マウスポインタを動かさずに、オブジェクトの方から重なってきたときには、大きさが変わらない。また、マウスをロールオーバーさせてオブジェクトが大きくなっても、ポインタをそのまま動かさずにオブジェクト側が外れると、大きさは戻らない。つまり、マウスを動かさないと、ロールオーバーやロールアウトのイベントが起こらないということだ。
これは、おそらくマウスポインタとオブジェクトとの重なりを調べる手間は、なるべく減らそうとしたことによる仕様だ。もし、オブジェクトは動かないコンテンツだったら、その方が負荷は軽い。だが、今回のお題はそれでは困る。その場合は、マウスが動かなくても重なりを調べさせるプロパティView.forceMouseMoveを、つぎのようにtrueに定めればよい。
これで、クリックおよびロールオーバーとロールアウトのマウスインタラクションが加わった。ここまでのJavaScriptはコード2にまとめた。また、サンプル2をjsdo.itに掲げてある。次回はこのお題の締めとして、回り込むカメラもマウスの動きに合わせたい。