프로그래밍/HTML+CSS+JavaScript

java script drag & drop

긴자손-1 2009. 10. 7. 11:37
반응형

출처 : http://gd452.springnote.com/pages/528849

Design

  1. 마우스 커서가 현재 어디 있는지
  2. 언제 사용자가 item을 클릭했는지
  3. 클릭한 아이템을 Drag 하는지
  4. Drag 하면, 그 아이템을 움직여야 한다.



마우스 좌표를 얻기


  1. document.onmousemove = mouseMove;

    function mouseMove(ev){
        ev           = ev || window.event;
        var mousePos = mouseCoords(ev);
    }

    function mouseCoords(ev){
        if(ev.pageX || ev.pageY){
            return {x:ev.pageX, y:ev.pageY};
        }
        return {
            x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
            y:ev.clientY + document.body.scrollTop  - document.body.clientTop
        };
    }


  • IE의 경우 event object는 global이다. 그리고 window.event에 저장된다. Firefox나 다른 브라우져의 경우 이 event는 그 action이 실행될때 수행되는 함수에 전달된다.
  • Firefox 나 기타 브라우져의 경우 document에 대한 상대좌표를 알기위해 pageX, pageY를 사용한다. 반면 MSIE의 경우 clientX, clientY를 사용한다.
  • 마우스 포인트가 500x500의 윈도우에서 중앙에 있을 경우, Firefox의 경우, pageX, pageY가 250, 250이고 scroll down을 500px 했을 경우, 750이 된다. 반면 IE는 scroll down했을 경우 250으로 유지된다. 그 결과 scrollLeft, scrollTop을 붙여야 한다.
  • IE의 경우 document의 원점이 0,0이 아니라 그것을 둘러싸고 있는 border(2px)만큼 크다. 이를 또한 빼주어야 한다.

==> 근데 막상 해보니 IE6.0에서는 Firefox랑 똑같다....


마우스 클릭 잡아내기

  • document.onmouseup, onmousedown에 우리가 원하는 함수를 붙이자. 이렇게 되면 모든 element에 대해 이벤트가 발생하니 Dragging을 원하는 Element에 함수를 붙이자.
  1. document.onmouseup = mouseUp;
    var dragObject     = null;

    function makeDraggable(object){
        object.onmousedown = function(){
            dragObject = this;
        }
    }

    function mouseUp(ev){
        dragObject = null;
    }


이동

  • 이동을 위해 item의 position style이 absolute 여야 한다. 그리고, style.top, style.left를 set 해야 한다. 모든 마우스의 움직임은 페이지의 좌상단이 기준이 된다.
  1. document.onmousemove = mouseMove;
    document.onmouseup   = mouseUp;

    var dragObject  = null;
    var mouseOffset = null;

    function getMouseOffset(target, ev){
        ev = ev || window.event;

        var docPos    = getPosition(target);
        var mousePos  = mouseCoords(ev);
        return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
    }

    function mouseCoords(ev){
        if(ev.pageX || ev.pageY){
            return {x:ev.pageX, y:ev.pageY};
        }
        return {
            x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
            y:ev.clientY + document.body.scrollTop  - document.body.clientTop
        };
    }

    function getPosition(e){
        var left = 0;
        var top  = 0;

        while (e.offsetParent){
            left += e.offsetLeft;
            top  += e.offsetTop;
            e     = e.offsetParent;
        }

        left += e.offsetLeft;
        top  += e.offsetTop;

        return {x:left, y:top};
    }

    function mouseMove(ev){
        ev           = ev || window.event;
        var mousePos = mouseCoords(ev);

        if(dragObject){
            dragObject.style.position = 'absolute';
            dragObject.style.top      = (mousePos.y - mouseOffset.y)+"px";
            dragObject.style.left     = (mousePos.x - mouseOffset.x)+"px";

            return false;
        }
    }
    function mouseUp(){
        dragObject = null;
    }

    function makeDraggable(item){
        if(!item) return;
        item.onmousedown = function(ev){
            dragObject  = this;
            mouseOffset = getMouseOffset(this, ev);
            return false;
        }
    }


  • mouseOffset 의 값은 선택한 item을 기준으로 어느 지점을 선택했느지를 알려준다. item 의 크기가 100x18이라면 내가 마우스를 클릭한 지점에 따라 mouseOffset이 달라진다.
  • offsetParent 는 offsetTop, offsetLeft속성들을 지정한 용기개체의 참조이다. 대부분의 경우 offsetParent는 body 개체를 반환한다. offsetTop과 offsetLeft는 현재 element가 offsetParent로 지정된 element에 대한 상대적인 위치를 나타낸다.



Dropping

  • 여태까지의 예제를 통해 원하는 element를 옮길 수 있었다. 하지만 실제로 원하는 곳에만 Drag Drop이 가능하게 하려면 어찌하면 좋은가? 불행히도 Drag를 하고 있는 동안은 다른 element에 대해 어떤 mouse action도 불가능하다.
  • 가능한 솔루션으로 우리가 Drag를 원하는 element와 Drop의 타겟이 되는 element에 영향을 주지 않는 방법을 살펴보자.
    • 첫째로 Drop 타겟이 되는 리스트를 얻는다.
    • 마우스가 release 된 순간, 마우스 포지션을 각각의 타겟 element위에 있는지 체크한다.
    • 타겟 위에 있으면 Drop 한다.


var dropTargets = [];

function addDropTarget(dropTarget){
    dropTargets.push(dropTarget);
}

function mouseUp(ev){
    ev           = ev || window.event;
    var mousePos = mouseCoords(ev);

    for(var i=0; i<dropTargets.length; i++){
        var curTarget  = dropTargets[i];
        var targPos    = getPosition(curTarget);
        var targWidth  = parseInt(curTarget.offsetWidth);
        var targHeight = parseInt(curTarget.offsetHeight);

        if(
            (mousePos.x > targPos.x)                &&
            (mousePos.x < (targPos.x + targWidth))  &&
            (mousePos.y > targPos.y)                &&
            (mousePos.y < (targPos.y + targHeight))){
                // dragObject was dropped onto curTarget!
        }
    }

    dragObject   = null;
}


반응형