[HTML5] 드래그 앤 드롭 (Drag & Drop)

Posted in 모바일/HTML5 // Posted at 2010/08/10 17:27

끌어다 놓기(드래그 앤 드롭, Drag & Drop)
끌어다 놓기는 사용자 편의성을 고려한 편리한 UI 기능이라 할 수 있는데,
아래 그림에서 보는 바와 같이 영역 A -> 영역 B로 특정 콘텐트를 마우스로 이동하는 것을 말한다



아래 그림은 구글 캘랜더에서 할일목록을 드래그 앤 드롭을 통해 다른 날짜로 이동하고 있는 모습이다


이러한 UI의 사용자 액션은 직관적이며 편리한 기능이다. 
윈폼 닷넷과 같은 윈도우 응용프로그램에서는 드래그 앤 드롭과 관련된 API 가 이미 제공되고 있다
그러나 웹 환경에서는 지금까지 전용 API는 제공되지 않고 유사 구현을 위해 복잡한 자바스크립트
이벤트(mouse 관련 이벤트를 직접 구현함)를 다루어야 했다

HTML 5 의 Drag & Drop API
HTML 5 에는 드래그 앤 드롭을 위한 전용 API 가 제공된다
이 API는 기존 윈도우 응용프로그램의 드래그 앤 드롭 API와 개념적으로 상당히 유사하다
과거처럼 자바스크립트의 마우스 관련 이벤트와는 전혀 상관이 없으며 
드래그 대상, 드롭 대상, 이동 콘텐트 등의 정보를 기반으로 동작한다

또한 웹 페이지 내 콘텐트의 이동 뿐만 아니라 웹 페이지 간, 웹 페이지와 다른 응용프로그램 간
드래그 앤 드롭이 가능
하기 때문에 이전 웹 환경과는 완연히 구분되는 기능이라 할 수 있겠다


지원되는 브라우저 현황
아래 표는 http://caniuse.com/ 에서 제공하는 브라우저(버전)별 Drag & Drop 지원 표이다
(데스크탑 용 브라우저 기준이다)




위 표를 보면 파이어폭스, 사파리, 크롬은 지원한다고 나와 있는 반면,
막상 테스트를 해 보니 파이어폭스를 제외하고는 제대로 동작하지 않았다
(크롬, 사파리 최선 버전 브라우저에서 Drag & Drop 정상 동작 하지 않음)
(표에서는 지원된다고 나와 있으니 조금 더 확인이 필요 할 것 같다)

그리고 아이폰의 사파리도 지원하지 않는 것으로 보인다
아이폰 사파리 브라우저에서 테스트를 해 봤지만 전혀 동작하지 않았다


Drag & Drop API
대부분의 HTML 5 스크립트 API들은 고도로 추상화 되었기 때문에 매우 사용하기가 쉽다
드래그 앤 드롭 API 역시 이용하는 데 어려움이 없으며 기존 윈도우 응용프로그램의 API 개념과
상당부분 유사하다. 드래그 앤 드롭 API 이해를 위해서는 다음의 것들을 이해하면 된다

- 드래그 대상(Source)
드래그 대상은 말 그대로 끌어올 것에 해당한다.
HTML 요소에 draggable 속성 값을 true로 설정하면 드래그 대상이 될 수 있다

- 드롭 대상(Target)
드롭 대상은 말 그대로 끌어다 놓을 곳에 해당한다
HTML 요소들의 기본 값은 드롭을 받아 들이지 않게 되어 있다
따라서 드롭이 가능하도록 설정하려면 이벤트의 preventDefault() 함수로 기본 값을 취소해야 한다

- 드래그 데이터(Data)
드래그 데이터는 말 그대로 이동할 대상 콘텐트에 해당한다.
이동할 데이터는 DataTransfer 객체를 통해 이루어 지는데
드래그 대상에서 이 객체에 값을 저장하고 드롭 대상에서 이 객체의 값을 꺼내어 오는 방식이다

- 드롭 이벤트들
드래그 앤 드롭과 관련해 총 7가지 이벤트가 존재한다
이 이벤트들은 드래그 앤 드롭 과정에서 (거의) 순차적으로 발생하며 드래그,드롭 대상에서
자신에게 맞는 이벤트 처리를 해 주면 된다

: dragstart 이벤트
드래그 대상에서 정의해야 하는 이벤트 이다
드래그가 시작될 때 발생하며 드래그 대상에서는 이 이벤트를 수신하여 이동할 데이터를 DataTransfer 객체에 채우게 된다

: dragenter 이벤트
드롭 대상에서 정의해야 하는 이벤트이다
이동할 데이터를 마우스로 끌어서 드롭 대상에 들어 오는 순간 발생한다

: dragover 이벤트
드롭 대상에서 정의해야 하는 이벤트이다
이동할 데이터를 마우스로 끌어서 드롭 대상에 올려 놓는 동안 계속해서 발생하는 이벤트이다

: drop 이벤트
드롭 대상에서 정의해야 하는 이벤트이다
마우스로 끌어서 놓는 순간 발생한다. 드롭 대상에서는 이 이벤트르 수신하여
DataTransfer 객체로부터 데이터를 꺼내 오고 드롭 대상에 끼워 넣는 작업을 하게 된다

이외에도 drag 이벤트, dragleave 이벤트, dragend 이벤트 등이 추가로 존재하지만
위에 설명한 4가지 이벤트로 기본적인 드래그 & 드롭 구현이 가능하다


Drag & Drop 데모 만들어 보기
이제 간단한 드래그 앤 드롭 데모를 만들어 보자
문서 내에서 select 박스 간 데이터를 이동하는 예제이다
(아래 코드는 시라이시 슌페이의 HTML5 & API 입문 책의 소스코드를 기반으로 했음을 밝힌다)

<!DOCTYPE html>
<html>
  <head>
  <script type="text/javascript">
 
    function onDragStart(event){
      document.getElementById("msg").innerHTML += "onDragStart->";
     
      //드래그 대상 요소가 option 일 경우에만 가능토록 함
      if(event.target.tagName.toLowerCase() == "option"){
     
        //dataTransfer 객체에 이동할 요소의 ID를 "selectOption"라는 이름으로 등록함
        event.dataTransfer.setData("selectOption", event.target.id);
      }
      else{
        //만일 드래그 대상 요소가 option이 아닐 경우 취소함
        event.preventDefault();
      }
    }       
   
    function onDragEnter(event){
      document.getElementById("msg").innerHTML += "onDragEnter->";
     
      //드래그 대상이 selectOption 일 경우에만 드롭 가능토록 설정함
      var types = event.dataTransfer.types;
      for(var i = 0; i < types.length; i++){
        if(types[i] == "selectOption"){
          event.preventDefault();
          return;
        }
      }
    }
   
    function onDragOver(event){
      document.getElementById("msg").innerHTML += "onDragOver->";
     
      //드롭이 가능하도록 기본 상태를 취소함
      event.preventDefault();
    }       
   
    function onDrop(event){  
      document.getElementById("msg").innerHTML += "onDrop";  
     
      //dataTransfer 객체로 부터 데이터를 꺼내옴
      var id = event.dataTransfer.getData("selectOption");
     
      //현재 문서객체에서 해당 요소를 가져옴
      var optionElement = document.getElementById(id);
     
      //데이터가 존재하고 드래그 대상과 드롭 대상이 같지 않을 경우 드롭 실행
      if(optionElement && optionElement.parentNode != event.currentTarget){
        //드래그 대상에서 이동할 데이터 삭제
        optionElement.parentNode.removeChild(optionElement);
       
        //드롭 대상에 데이터 추가
        event.currentTarget.appendChild(optionElement);
      }
           
      //드롭 완료 후 이벤트 버블링을 막기 위해 호출           
      event.stopPropagation();
           
    }
   
  </script>
  </head>
 
  <body>
         
    <!-- 드래그 대상 요소 -->
    <select size= 4 id="select1" ondragstart="onDragStart(event)">
      <option id="option1_1" draggable="true">옵션1-1</option> <!-- 드래그 데이터 -->
      <option id="option1_2" draggable="true">옵션1-2</option> <!-- 드래그 데이터 -->
      <option id="option1_3" draggable="true">옵션1-3</option> <!-- 드래그 데이터 -->
    </select>
   
    <!-- 드롭 대상 요소 -->
    <select size= 4 id="select2"
       ondragenter="onDragEnter(event)"
      ondragover="onDragOver(event)"
      ondrop="onDrop(event)"
>
      <option id="option2_1">옵션2-1</option>
      <option id="option2_2">옵션2-2</option>
      <option id="option2_3">옵션2-3</option>
    </select>
   
    <br><br><div id="msg"></div>
   
  </body>
</html>

소스코드의 주석에 상세히 설명을 달았지만 간단히 전체적인 흐름을 설명하자면,
드래그 대상(Source)은 왼쪽 select 박스의 option 항목들이며,
드롭 대상(Target)은 오른쪽 select 박스이다

드래그 대상인 option 요소에 draggable="true" 속성을 부여해 드래그 가능한 상태로 설정하였다
그리고 dragstart 이벤트를 구현하여 드래그 액션이 시작될 때 dataTransfer 객체에
드래그 데이터(여기서는 option 의 ID)를 저장하고 있다

드롭 대상인 오른쪽 select 박스에는 dragenter, dragover, drop 이벤트를 구현하여
preventDefault 함수 호출로 select 박스가 드롭이 가능하도록 설정하였으며
dataTransfer 객체에서 드래그 데이터(여기서는 option 의 ID)를 꺼내온다
이렇게 꺼내온 드래그 데이터를  문서객체에서 조회하여 드래그 대상에서는 제거하고 드롭 대상에
추가하는 로직으로 구성되어 있다

그리고 추가로 드래그 관련 이벤트의 호출 순서를 보기 위한 코드가 각 이벤트에 추가되어 있다

아래는 데모의 실행 화면이다. 먼저 드래그가 중에 캡쳐한 화면이며,



아래는 드래그, 드롭이 완룐된 화면이다.
select 박스 하단을 보면 드래그 관련 이벤트의 호출 흐름을 나타내고 있다



본 예제에서는 문서내 요소간 드래그&드롭을 구현해 봤지만, 문서간 문서와 다른 응용프로그램 간
드래그&드롭도 가능하다. 이는 관련 자료를 살펴 보기 바란다

마지막으로 아래 사이트에서 드래그 & 드롭 관련 데모를 추가로 확인해 보자
http://ljouanneau.com/lab/html5/demodragdrop.html
http://html5demos.com/drag


 

'모바일 > HTML5' 카테고리의 다른 글

[HTML5] 오프라인 웹 어플리케이션  (0) 2010/08/12
[HTML5] Web Storage  (1) 2010/08/11
[HTML5] 드래그 앤 드롭 (Drag & Drop)  (2) 2010/08/10
[HTML5] Geolocation  (0) 2010/08/09
[HTML5] Web Workers (웹 워커)  (1) 2010/08/05
HTML5 Demo, A Look At HTML5 and its Canvas Tag  (0) 2010/07/29