event.offsetX,Yの罠...どこが原点の座標値なのかを理解する (currentTargetとtarget)

# はじめに

記事のタイトルからして今更感満載ですが，mouse eventのoffsetX,Yに関して長年勘違いをしていたので備忘録を残しておきます．

# offsetX,Y は要素内でのカーソル座標．

javascriptで

```js
var el = document.getElementById("boxA");
el.onmousemove = function(event){
   event.offsetX;
};
```
のようにしてマウスベントを登録した場合，
event.offsetX,Yは下図のようにid=boxA要素の左上を原点とした座標値になります．

![offset_a1.png](https://qiita-image-store.s3.amazonaws.com/0/59864/5cd43e8c-965b-d4f1-81bf-20b87ebda09e.png)

## 要素ってどれのこと？

では下図のようにboxAの中にboxBがある状態で，boxAに対してmouseEventを付与した場合はどうなるでしょうか．

![offset_a3.png](https://qiita-image-store.s3.amazonaws.com/0/59864/9d2fd911-07de-b14b-abba-d5f4c9623174.png)

この場合，event.offsetX，Yで取得される座標値は，そのイベントハンドラが付与されている要素(boxA)の左上を原点としたもの**ではなく**，マウスが載っている要素(boxB)の左上を原点とした座標値になります．

![offset_a2.png](https://qiita-image-store.s3.amazonaws.com/0/59864/98eff2c8-de4c-a83d-911b-26a2c1da000c.png)

なぜでしょうか．

## event.curerntTargetとevent.target

重要な点は，**イベントを登録した要素とイベントが発火する要素は必ずしも一致しない**ということです．
targetは実際にイベントが発火した要素，currentTargetはイベントを登録した要素になります．
イベントは子から親へと伝播するようになっており，targetで発火したイベントがcurrentTargetにまで伝播してきています．

先の例では，イベントを登録したのはbox1に対してですが，実際はbox2で発火したために，offsetX,Yの基準がbox2左上原点になった，ということです．


上の例では，

```
var el = document.getElementById("container");
el.onmousemove = function(e){
	console.log("currentTarget: " + e.currentTarget.id);
	console.log("target: " + e.target.id);
};
```

等で確認してみれば，それぞれに何が入ってくるのかがわかると思います．

jQueryを使用する場合は基本的に`$(this)`で意図した要素を取得できるため，あまり意識する必要はありません．ただ，
最近はReact等が流行ってきてjQueryが不要な場面も増えてきているので今一度確認しておきました．

# 規定の要素からのカーソル座標値を求めるためには

では，カーソルがbox2に乗っていようといまいと，box1左上を原点としたカーソル座標値を求める方法を見ていきましょう．

### 1. getBoundingClientRect().left/topとevent.clientX/Yを使用

```
document.getElementById("id").getBounndingClientRect().left/top
```

でウィンドウ座標から見た要素の左上座標値を得ることができます．これとevent.clientX/Yを組み合わせて

```js
var el = document.getElementById("box1");
el.onmousemove = function(e){
	var target_rect = e.currentTarget.getBoundingClientRect();
	var x = e.clientX - target_rect.left;
	var y = e.clientY - target_rect.top;
	console.log("(x, y) = (" + x + "," + y + ")");
};
```

でid=box1要素座標系でのカーソル位置を求めることができます．

![offset_b1.png](https://qiita-image-store.s3.amazonaws.com/0/59864/590d367b-7307-3025-86ac-1022373e4d3d.png)


### 2. jQueryのoffset()とevent.pageX/Yを使用

```
$("#id").offset().left/top
```

でページ全体から見た要素の左上座標を得ることができます．これとevent.pageX/Yを組み合わせて

```js
$("#box1").on('mousemove',function(e){
    var offset = $(this).offset();
    var x = e.pageX - offset.left;
    var y = e.pageY - offset.top;
	console.log("(x, y) = (" + x + "," + y + ")");
});
```

でid=box1要素座標系でのカーソル位置を求めることができます．

![offset_b2.png](https://qiita-image-store.s3.amazonaws.com/0/59864/fbda24fa-6cad-cf1c-5138-656710c3ac2c.png)


#　サンプルで確かめる
[code.pen](http://codepen.io)に上記の値の違いが確かめられる[サンプル](http://codepen.io/yukiB/pen/gwGjrw)を置きました．気になる方は色々値をいじって確かめてみてください．
マウスイベントのカーソル座標取得についてはに記事をあげているので，興味のある方は[そちら](http://qiita.com/yukiB/items/31a9e9e600dfb1f34f76)も御覧ください．

# 参考文献

- 
What is the exact difference between currentTarget property and target property in javascript ([http://stackoverflow.com/questions/10086427/what-is-the-exact-difference-between-currenttarget-property-and-target-property](http://stackoverflow.com/questions/10086427/what-is-the-exact-difference-between-currenttarget-property-and-target-property))
- gsol-dev's blog ([http://gsol.hatenablog.com/entry/2013/12/04/event.curretTarget%E3%81%A8event.target%E3%81%AE%E9%81%95%E3%81%84](http://gsol.hatenablog.com/entry/2013/12/04/event.curretTarget%E3%81%A8event.target%E3%81%AE%E9%81%95%E3%81%84))
- uhyouhyo.net ([http://uhyohyo.net/javascript/3_5.html](http://uhyohyo.net/javascript/3_5.html))