드래그 앤 드롭과 마우스 이벤트 (step 25)

50754 단어 js-studyjs-study

Position:absolute

HTML의 태그를 절대 위치에 배치할 수 있다.
절대 위치는 left, top, bottom, right 프로퍼티 값으로 정하며, 이 값들은 부모 태그 안에서의 상대 좌표이다.


1. 기본적인 공 태그 구현

ball.onmousedown = function(event) {
  // (1) absolute 속성과 zIndex 프로퍼티를 수정해 공이 제일 위에서 움직이기 위한 준비를 합니다.
  ball.style.position = 'absolute';
  ball.style.zIndex = 1000;		//필수적이지는 않음

  // 현재 위치한 부모에서 body로 직접 이동하여
  // body를 기준으로 위치를 지정합니다.
  document.body.append(ball);

  // 공을 pageX, pageY 좌표 중앙에 위치하게 합니다.
  function moveAt(pageX, pageY) {
    ball.style.left = pageX - ball.offsetWidth / 2 + 'px';
    ball.style.top = pageY - ball.offsetHeight / 2 + 'px';
  }

  // 포인터 아래로 공을 이동시킵니다.
  moveAt(event.pageX, event.pageY);

  function onMouseMove(event) {
    moveAt(event.pageX, event.pageY);
  }

  // (2) mousemove로 공을 움직입니다.
  document.addEventListener('mousemove', onMouseMove);

  // (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
  ball.onmouseup = function() {
    document.removeEventListener('mousemove', onMouseMove);
    ball.onmouseup = null;
  };

};

ball.style.position = 'absolute';로 객체인 ball을 자유롭게 이동시킬수 있게 만든다.

ball.style.left = event.pageX ball.style.top = event.pageY의 경우 마우스가 위치하는 곳에 해당 그림의 왼쪽 위 부분이 나타난다.
이를 중앙으로 맞추기 위해서는 실제 lefttop을 위치보다 위로 그리고 오른쪽으로 (-하게) 만들어야 중앙으로 온다.
따라서 ball.style.left = event.pageX - ball.offsetWidth / 2 + 'px';
ball.style.top = event.pageY - ball.offsetHeight / 2 + 'px'; 로 위치를 위로 올려 마우스 위치가 해당 공의 중앙이 되도록 한다.

추가할 부분

브라우저 자체적으로 이미지나 요소에 대한 드래그 앤 드롭을 지원하기 때문입니다. 브라우저에서 제공하는 기능이 자동 실행되어 작성한 코드와 충돌되기 때문
(우리가 실행하려는 mousemove mouseup에 겹쳐서 dragstart가 실행되는것을 막기 위해서 dragstart를 return false처리한다.

ball.ondragstart = function() {
  return false;
};

1.1 공을 눌렀을때 바로 마우스의 중앙으로 공이 오는것을 막아보기

$ball.style.left = pageX - $ball.offsetWidth / 2 + 'px';
$ball.style.top = pageY - $ball.offsetHeight / 2 + 'px';

위의 내용을 수정해본다.

Element.getBoundingClientRect()

요소의 크기와 viewport를 기준으로 한 요소의 상대적인 위치 정보를 담은 DOMRect 객체를 반환하는 메서드

이를통해 새로운 코드로 바꾸면

// onMouseDown()
let shiftX = event.clientX - $ball.getBoundingClientRect().left;	//마우스를 대상으로 
let shiftY = event.clientY - $ball.getBoundingClientRect().top;


그림으로는 이와같다.

따라서 실제 마우스를 클릭하였을때 left,top의 위치가 맨끝점을 기준으로 각각 shiftX shiftY만큼을 빼야하므로

$ball.style.left = event.pageX - shiftX + 'px';
$ball.style.top = event.pageY - shiftY + 'px';

이렇게 수정된다. (기존값보다 shiftX,shiftY만큼 더 뺌으로써 마우스를 기준으로 오른쪽 아래에 그림이 있어야하나 더 위로올라가 마우스가 누르는 위치를 처음 클릭한 위치와 같게 만들어서 클릭시에도 갑자기 공이 움직이는 것을 막아준다.

2. ondrag 사용하는 예시

<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <style>
    div {
      width: 180px;
      height: 280px;
      margin: 10px;
      padding: 10px;
      border: solid 15px #8B4513;
      float: left;
    }
  </style>
</head>
 

<body>
  <div ondrop="drop(event)" ondragover="dragEnter(event)">
    <img id="monalisa" width="180" height="280" src="https://www.ilbe.com/file/download/11181795373" draggable="true" ondragstart="drag(event)">
  </div>
  <div ondrop="drop(event)" ondragover="dragEnter(event)"></div>
</body>
<script>
  function drag(event){
event.dataTransfer.setData("text", event.target.id);

  }


  //기본동작을 막은 후 
  function dragEnter(event){
    event.preventDefault();
  }

  // 해당 처리
  function drop(event){
      
      var data = event.dataTransfer.getData("text");

      event.target.appendChild(document.getElementById(data));
  }


</script>

</html>


위의 예시는 ondrag를 써서 해당 그림을 다른 그림으로 옮기는 작업을 수행하는 역할을 한다.

1.기본적인 공 태그 구현 VS 2. ondrag 사용하는 예시

1번의 경우 공을 드래그시 해당 그림이 유지된 채로 움직임을 진행한다. (보기에 공을 그상태로 움직인다는 느낌이 든다.)
그리고 충돌의 방지를 위해 기본적으로 작동되는 ondrag를 event.preventDefault()를 썼다.

2번의 경우 그림을 드래그시 기존형태가 아닌 작아진 형태로 드래그를 진행하게 된다. 기본적인 ondrag는 써야하기때문에 따로 event.preventDefault()를 쓰지는 않았다.

과제

실행코드 결과

<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
  div{
      position:absolute;
  }
  #bar {
    width: 1000px;
    height: 50px;
    border-radius: 50px;
    background-color: gray;
    margin-top :10px;
  }
  #drag{
      width:20px;
      height:80px;
      border-radius:50px;
      background-color: blue
  }
</style>
</head>


<body>
  <div id='bar'></div>
  <div id='drag'></div>
</body>
<script>
  let drag = document.getElementById('drag');

drag.onmousedown = function(event) {
// (1) absolute 속성과 zIndex 프로퍼티를 수정해 공이 제일 위에서 움직이기 위한 준비를 합니다.
event.preventDefault();
drag.style.position = 'absolute';
drag.style.zIndex = 1000;

// 현재 위치한 부모에서 body로 직접 이동하여
// body를 기준으로 위치를 지정합니다.
document.body.append(drag);

// 공을 pageX, pageY 좌표 중앙에 위치하게 합니다.
function moveAt(pageX, pageY) {
  if(pageX - drag.offsetWidth / 2 > 990 )
      drag.style.left = "990px";
  else if(pageX - drag.offsetWidth / 2 < 9 )
      drag.style.left = "9px"
  else
      drag.style.left = pageX - drag.offsetWidth / 2 + 'px';
  drag.style.top = pageY 
}

// 포인터 아래로 공을 이동시킵니다.
moveAt(event.pageX, event.pageY);

function onMouseMove(event) {
  moveAt(event.pageX, "6px");
}

// (2) mousemove로 공을 움직입니다.
document.addEventListener('mousemove', onMouseMove);

// (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
drag.onmouseup = function() {
  document.removeEventListener('mousemove', onMouseMove);
  document.removeEventListener('mouseup', onMouseMove);
};

drag.ondragstart = function() {
return false;
};
drag.ondragend = function(){
  return false;
}

};

</script>

</html>

해당 바 안에서의 움직임은 문제가 없으나 다른 문제가 발생

문제점

해당 마우스로 바를 클릭한상태로 흰색창부분에서 마우스를 띄면 진행이 계속된다. (바를 멈출수가 없다.)

해결법

<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <style>
    div{
        position:absolute;
    }
    #bar {
      width: 1000px;
      height: 50px;
      border-radius: 50px;
      background-color: gray;
      margin-top :10px;
    }
    #drag{
        width:20px;
        height:80px;
        border-radius:50px;
        background-color: blue
    }
  </style>
</head>
 

<body>
    <div id='bar'></div>
    <div id='drag'></div>
</body>
<script>
    let drag = document.getElementById('drag');

drag.onmousedown = function(event) {
  // (1) absolute 속성과 zIndex 프로퍼티를 수정해 공이 제일 위에서 움직이기 위한 준비를 합니다.
  event.preventDefault();
  drag.style.position = 'absolute';
  drag.style.zIndex = 1000;

  // 현재 위치한 부모에서 body로 직접 이동하여
  // body를 기준으로 위치를 지정합니다.
  document.body.append(drag);

  // 공을 pageX, pageY 좌표 중앙에 위치하게 합니다.
  function moveAt(pageX, pageY) {
    if(pageX - drag.offsetWidth / 2 > 990 )
        drag.style.left = "990px";
    else if(pageX - drag.offsetWidth / 2 < 9 )
        drag.style.left = "9px"
    else
        drag.style.left = pageX - drag.offsetWidth / 2 + 'px';
    drag.style.top = pageY 
  }

  // 포인터 아래로 공을 이동시킵니다.
  moveAt(event.pageX, event.pageY);

  function onMouseMove(event) {
    moveAt(event.pageX, "6px");
  }

  // (2) mousemove로 공을 움직입니다.
  document.addEventListener('mousemove', onMouseMove);
  document.addEventListener('mouseup', onMouseUp);

  // (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
  function onMouseUp() {
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseMove);

  };

  drag.ondragstart = function() {
  return false;
};
  drag.ondragend = function(){
    return false;
  }

};

</script>

</html>

이렇게 하니 정상적으로 문제가 없었다.

두 코드의 차이

  1. onmouseup사용
 document.addEventListener('mousemove', onMouseMove);

 // (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
 drag.onmouseup = function() {
   document.removeEventListener('mousemove', onMouseMove);
   document.removeEventListener('mouseup', onMouseMove);
 };
  1. addEventListener사용
  // (2) mousemove로 공을 움직입니다.
  document.addEventListener('mousemove', onMouseMove);
  document.addEventListener('mouseup', onMouseUp);

  // (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
  function onMouseUp() {
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseMove);

  };

느낀점

addEventListener를 많이사용하자??

혹시 한번 실험을 해주실 분들은 저 아래 두 코드를 실험해주시고 의견 남겨주시면 감사하겠습니다.

shiftX,shiftY를 잘 사용할수있게 만들기

// onMouseDown()
let shiftX = event.clientX - $ball.getBoundingClientRect().left;	//마우스를 대상으로 
let shiftY = event.clientY - $ball.getBoundingClientRect().top;

출처

마우스

좋은 웹페이지 즐겨찾기