問題は、規格の定義が曖昧で、ブラウザの実装が救いがたいぐらい異なっているということだ。ここでは、マウスの位置を取得する方法を、完璧に解説しようと思う。canvasを使うにあたっては、マウスカーソルの位置を取得することは重要だ。座標とは何かここで私の言う座標とは、ある点を(0,0)と置いた場合の、その点からの位置(x,y)のことである。これはコンピューターの世界では、一般的な座標系である。その基準となるべき「ある点」とはどこか。次のようなコードを考える。Eventに準拠するイベントリスナーの、Javascriptによる実装である。このコードをベースに、マウスカーソルの位置を取得したい。;スクリーン座標は、コンピュータのディスプレイの左上を原点とする座標系である。screenY属性で取得できる。Javascritpでは、同名のプロパティとして実装されている。これは、現実的には、何の役に立たない。ブラウザ自体がディスプレイのどの位置にいるのかがわからないので、画面上の位置を知ったところで、何にもならないからだ。;ウインドウ座標とは、現在のブラウザのウインドウの、ドキュメントを表示している部分の左上原点とした座標である。問題は、ウインドウは、必ずしもドキュメント全体を表示するとは限らない。スクロールと呼ばれるUIによって、ドキュメントの一部だけを表示しているかもしれない。ドキュメント座標これは、ドキュメント全体に対する座標である。ウインドウ座標が、ドキュメントをすべて表示している場合と考えてもいい。問題は、この座標を、クロスブラウザな実装で得るのが不可能に近いということだ。これについては最後に解説する。ある要素からの相対座標HTML5のcanvasを使う場合、そのcanvas要素の左上を原点とした座標での、マウスカーソルの位置が知りたい場合がよくある。いうのも、canvasを使う以上、通常のマークアップ言語を離れた、特殊な描画がしたいのだから、これ自体は不思議ではない。すれば、この座標を得られるのだろう。インターフェースには、offsetXとoffsetYが定義されている。これは、まさに欲している、イベント要素からの相対座標である。問題は、W3Cの規格では定義されていないことと、さらにひどいことに、ブラウザ間で、微妙に異なる実装をしている。そもそも、その要素からの相対座標といっても、具体的にどこを原点とした座標なのか、ということだ。boxの左上を原点としている。ところが、ブラウザによって、原点の取り方が異なる。IE8は、完璧な実装をしている。Firefoxでは、サポートしていない。boxの左上を原点としている。boxの左上を原点としている。ブラウザ間で差異があり、W3C規格で未定義で、Firefoxでサポートしていないことに目をつぶれば、一応この機能は使える。実際に使う際には、要素のpaddingを0pxに設定しておいたほうがいいだろう。;Firefoxのみがサポートしている独自規格で、offsetX、offsetYと機能は同じである。W3C規格には載っていないし、Firefox以外にサポートしているブラウザもない。ドキュメント座標から、要素への相対座標を得る今、何らかの方法で、マウスカーソルのドキュメント座標が得られたとする。ここから要素への相対座標を得ることは、可能である。イベントリスナーが登録されている要素からの相対座標を得たいとする。Eventインターフェースには、target属性があり、これを使えば、イベントリスナーが登録されている要素が得られる。Moduleに定義されているように、offsetLeftと、offsetTop属性を持っている。問題は、これは、親要素からのオフセットだということだ。ある要素の親要素には、さらに親要素が存在する可能性がある。したがって、body要素まで延々と親要素をたどっていかなければならない。yにドキュメント座標が入っているとすると、そのコードは以下のようになる。;}body要素のoffsetParentはnullを返すと規定されているので、このコードで、親要素を延々とたどって、相対座標を計算できる。ドキュメント座標を得る方法さて、いよいよ本題の、ドキュメント座標を得る方法について解説する。ドキュメント座標が得られれば、上記のoffsetを引くループで、相対座標が得られる。これがなかなか難しい。;これは、W3C規格では定義されていない。IE以外の主要なブラウザすべてでサポートされている。これはまさに、ドキュメント座標が得られる。一体body要素のElementインターフェースはどうやって取得すればいいのか。歴史的に、document.bodyが使われてきた。2では、document.documentElementが定義され、かなりのブラウザがそちらに移った。document.bodyが動かなくなった。modeかどうかで、この挙動を変えるブラウザが存在することも、頭を悩ませる。HTML5では、document.bodyが規格に入っている。2の定めるところにより、document.documentElementが正しいといえるのだろう。ブラウザでは、動かないだけで、実際にはどちらも定義されているので、未定義かどうかでブランチすることも出来ない。したがって、ウインドウ座標からスクロール分を加算してドキュメント座標を得る手法では、ブラウザのブランチが必要不可欠になってしまう。ところで、三番目のコードは、私としては、正しく動くと期待していたのだが、なぜかwebkit系のブラウザ(SafariとChrome)でしか動かない。ModuleのgetBoundingClientRect()を使う。基本的に理想主義者の私は、まず先に参考にするのは規格書なので、getBoundingClientRect()の存在は知っていたが、どうもその解説が複雑で、まじめに読む気にならなかった。思い直して読んでみたところ、これはなかなか面白いものだ。これをまじめに解説した日本語の情報がWebあるかどうか、ふとググってみたところ、なかった。そこで、解説してみることにする。getBoundingClientRect()の仕様を説明するには、まず、getClientRects()を説明しなければならない。3では、すべてのElementは、ElementViewインターフェースを実装していなければならない。getClientRects()は、その要素の子のボーダーボックス領域のリストを返す。getBoundingClientRect()は、getClientRects()の戻り値のリストから計算して、TextRectangleを返す。言い換えれば、その要素の領域だ。重要な事は、これがviewportに対する相対座標だということだ。event.clientX/Yとは、同じ座標系ということになる。これで、マウスカーソルの、その要素に対する相対座標が得られる。うれしいことに、これはほとんどのブラウザで動く。Viewによれば、IE7以前で、2ピクセルずれるとか、Firefoxは結果を丸めないとか、些細な違いがあるが、それはそのブラウザのバグで、私の知ったことではないし、他の悲惨な方法に比べれば、実に他愛ない違いである。;これで、この前のHTML5のCanvasの使ったデモは、規格を正しく実装しているどんなブラウザでも動くようになった。modeかどうかで、この挙動を変えるブラウザが存在するSafari以外の主要なブラウザは後方互換モードか標準準拠モードかでdocument.bodyとdocument.documentElementの挙動を変えます。こちらがスタンダードな実装です。(Operaは9.5より前はどちらも使えましたが、9.5以降からFirefoxやIEと合わせました)また、要素の絶対座標を求めるには、getBoundingClientRect(IE,Firefox3,Opera,Safari4)もあります。window.page[XY]OffsetもIE以外で使えるのでなかなか優秀です。said...getElementsByTagNameで一応、bodyのElementが返ってくるらしいのですが、そのScrollTopなどを見ても、OperaやFirefoxでは、0になっているのです。getBoundingClientRectの返す内容は、viewportからの相対座標ですか。すると、同じくウインドウ座標のevent.clientX/Yと組み合わせれば、要素からの相対座標が分かりますね。この方法が一番のようですね。W3C規格にもありますし。Eventに準拠するイベントリスナーの、Javascriptによる実装である。