マウスドラッグイベントについて
マウスでDOMの要素をドラッグするイベントを試してみます。
DOMの要素をドラッグするイベントは、documentやHTMLElementのdragイベントを使う方法がありますが、
ここではシンプルな例として、DOM要素をクリックした際のonmousedownイベントを使い、
その中でDOM要素の座標を制御する方法を試してみます。
下記のHTMLを用意しました。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style type="text/css">
#test1 {
position:absolute;
height:100px;
width:150px;
top:10px;
left:10px;
background-color:rgb(0 74 207 / 15%);
}
</style>
</head>
<body>
<div id="test1">
ドラッグテスト
</div>
<script type="text/javascript">
let element_test1 = document.getElementById("test1");
element_test1.onmousedown = function(event) {
// DOM要素の表示順をあげる (他のDOM要素がある場合、考慮する)
element_test1.style.zIndex = 999;
// マウスダウン時、マウスアップ時のイベントハンドラを登録する
document.addEventListener('mousemove', mousemovehandler, false);
document.addEventListener('mouseup', mouseuphandler, false);
// マウスダウン時 (マウス移動時) のイベントハンドラ
function mousemovehandler(event)
{
// イベントオブジェクトから座標情報を取得し、移動に使用する
element_test1.style.left = event.pageX - element_test1.offsetWidth / 2 + 'px';
element_test1.style.top = event.pageY - element_test1.offsetHeight / 2 + 'px';
}
// マウスアップ時のイベントハンドラ
function mouseuphandler(event)
{
// DOM要素の表示順を下げる
element_test1.style.zIndex = 0;
document.removeEventListener('mousemove', mousemovehandler, false);
document.removeEventListener('mouseup', mouseuphandler, false);
}
};
</script>
</body>
</html>
実際に画面にアクセスすると、画面上に「ドラッグテスト」というDOM要素が見えます。
このDOMをマウスでクリックすると、mousemovehandler のイベントハンドラが実行され、
DOM要素の座標がマウス位置の座標に代入され、DOM要素がドラッグできるようになります。
課題としては、マウスクリック時の座標が、DOM要素の座標の2分の1の箇所を指しているので、
要素内のどの位置をクリックしても常にDOM要素の中心をドラッグする動きになる点があります。(この制御は別途、計算処理を入れると解消できます)
また、マウスをドラッグした後、マウスをアップすると mouseuphandler のイベントハンドラが実行され、
それまでドラッグしていたDOM要素の座標の計算、およびマウスアップ時のイベントをそれぞれ 削除(remove)しています。
こうすることでDOM要素をドロップした位置にその要素を固定することができます。
この簡単な例の他、documentやHTMLElementのdragイベントを使った例については、別途書いてみようと思います。
マウスクリック時の座標を計算し、修正
上記の例で課題としてあげた「マウスクリック時のDOM要素の位置がずれる」という点に対して、
修正版のHTMLを用意しました。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style type="text/css">
#test1 {
position:absolute;
height:100px;
width:150px;
top:10px;
left:10px;
background-color:rgb(0 74 207 / 15%);
}
</style>
</head>
<body>
<div id="test1">
ドラッグテスト
</div>
<script type="text/javascript">
let element_test1 = document.getElementById("test1");
element_test1.onmousedown = function(event) {
// DOM要素の表示順をあげる (他のDOM要素がある場合、考慮する)
element_test1.style.zIndex = 999;
let margin_x = event.pageX - element_test1.getBoundingClientRect().left;
let margin_y = event.pageY - element_test1.getBoundingClientRect().top;
// マウスダウン時、マウスアップ時のイベントハンドラを登録する
document.addEventListener('mousemove', mousemovehandler, false);
document.addEventListener('mouseup', mouseuphandler, false);
// マウスダウン時 (マウス移動時) のイベントハンドラ
function mousemovehandler(event)
{
// イベントオブジェクトから座標情報を取得し、移動に使用する
element_test1.style.left = event.pageX - margin_x + 'px';
element_test1.style.top = event.pageY - margin_y + 'px';
}
// マウスアップ時のイベントハンドラ
function mouseuphandler(event)
{
// DOM要素の表示順を下げる
element_test1.style.zIndex = 0;
document.removeEventListener('mousemove', mousemovehandler, false);
document.removeEventListener('mouseup', mouseuphandler, false);
}
};
</script>
</body>
</html>
画面にアクセスして「ドラッグテスト」のDOM要素のどこをドラッグしてもマウス位置がずれないようになります。
ポイントとしては、マウスクリック時の座標をあらかじめマージンのx座標、y座標として取得しておき、
let margin_x = event.pageX - element_test1.getBoundingClientRect().left; let margin_y = event.pageY - element_test1.getBoundingClientRect().top;
それを、移動時の座標として計算に入れている点です。
element_test1.style.left = event.pageX - margin_x + 'px'; element_test1.style.top = event.pageY - margin_y + 'px';
pageX、pageY、を使わずに、clientX、clientY、でも同様の動きになりますが、
画面上での座標計算と、DOM上での座標計算の違いがあり、ページをスクロールした上でドラッグする際(つまり、画面の初期表示外へドラッグする際)に挙動が違ってきます。
実際の開発シーンでは、どんなDOM上で何をどこまでドラッグするのか、という設計次第で使うプロパティを分けるとよいと思います。