Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Drag and Drop using Javascript

3.64/5 (7 votes)
6 Nov 20073 min read 1   626  
This is an article that talks of an approach to drag and drop elements in an HTML page

Introduction

With people pushing towards user centric development, the drag and drop feature is just one of the many such features that is commonly seen across the web pages that stress on user-centric development.This article discusses an approach to achieve such a feature keeping in mind the issues of browser compatibility.

Using the code

I have used an OOP approach for this( it surely can be done without the OOP). The main class that is responsible for drag and drop is Drag. All we need to get it going is call the Init() function. What this simply does is determine the kind of browser and set the corresponding variables.

With drag and drop what comes to my mind is

  1. Mouse button goes down,
  2. Mouse moves,
  3. Mouse button goes up.

We will control the location of the 'element' by retrieving the current (x,y) co-ordinates of the mouse and setting the left,top attributes of the element.

Class declaration:

function Drag()
{
    this.id=""
    this.beginDrag=""
    this.browserType=""
    this.eventObj=""
    this.bodyID=""

    Drag.prototype.SetBrowserType=SetBrowserType
    Drag.prototype.Init=InitDragClass
    Drag.prototype.GetBrowserType=GetBrowserType
    Drag.prototype.BeginDrag=BeginDrag
    Drag.prototype.GetDragState=GetDragState
    Drag.prototype.EndDrag=EndDrag
    Drag.prototype.GetCurrentCoOrdinates=GetCurrentCoOrdinates
    Drag.prototype.Move=Move
    Drag.prototype.SetId=SetId
    Drag.prototype.GetId=GetId
    Drag.prototype.SetEventObj=SetEventObj
    Drag.prototype.GetEventObj=GetEventObj
    Drag.prototype.RemoveChild=RemoveChild

}

function Position()
{
        this.x=""
        this.y=""
}

Do not be intimidated by the number of the functions,most of them are just getters and setters and are self explanatory.Here are some of which deserve an explanation:

  • this.id -> This will hold the id of the 'element' that we would be dragging.
  • this.eventObj -> Considering the cross browser discrepencies, I have used 'eventObj' to denote the 'event' object of different browsers.
  • this.beginDrag -> This is a flag that is used to indicate the status of the drag operation.
    function Move(obj,pos)
    {
            obj.style.position="absolute"
            obj.style.zIndex="999"
            obj.style.left=pos.x+"px"
            obj.style.top=pos.y+"px"
    }

    function GetCurrentCoOrdinates()
    {
        var pos=new Position()

        if(this.GetBrowserType()=="MOZILLA")
        {
            pos.x=(typeof this.GetEventObj().pageX =="undefined") ? 0 : this.GetEventObj().pageX
            pos.y=(typeof this.GetEventObj().pageY =="undefined") ? 0 : this.GetEventObj().pageY
        }
        else if(this.GetBrowserType()=="IE")
        {
            pos.x=(this.GetEventObj().x < 0 || typeof this.GetEventObj().x=="undefined")? 0 : this.GetEventObj().x
            pos.y=(this.GetEventObj().y < 0 || typeof this.GetEventObj().y=="undefined")? 0 : this.GetEventObj().y
        }

        return pos
    }

function RemoveChild()
{
    try
    {
        var obj=document.getElementById(this.GetId())
        var objParent=obj.offsetParent
        var objBody=document.getElementById(this.bodyID)
        objParent.removeChild(obj)
        objBody.appendChild(obj)
    }
    catch(err)
    {
    }
}

As show in the class declaration, Move() is responsible for actually moving the element in question. GetCurrentCoOrdinates() as the name suggests, returns the Position object. I will not be explaining the implementation of the rest of the functions as the name suggests their functionality and they are included in the sample source code.

RemoveChild is a bug fix. Prior to this, the elements were bounded by the area of their parent(they were unable to go left beyond their parent's area). To circumvent this problem, I remove the target element from its parent and append it to the body of the page. The body has the full page area. The old restrictions of being bounded still exist, but since the body is the page, we do not experience this bound. And since we are appending it to the body, we need to give the body an id. I set the id when calling Init().

We need to handle the onmousedown, onmousemove, onmouseup events, we need to specify explicitly that we are interested in doing so.

document.onmousemove=function(e) //e for Mozilla Firefox
{
        HandleMouseMove(e)
}

document.onmouseup=function(e)
{
        if(dragObj.GetId()!=null && dragObj.beginDrag==true)
        {
            HandleMouseUp(dragObj.GetId())
        }
}

Note: There seems to be a bug in Internet Explorer because it doesn't call the 'onmouseup' event when specified in the declaration of the 'element' so I had to write it down explicitly. To handle mouse down there I have used a function HandleMouseDown(id).

function HandleMouseUp(id)
{
    dragObj.EndDrag() //set the beginDrag flag to false
    dragObj.SetId("") //clear the id, since we stopped dragging the 'element'
}

function HandleMouseDown(id)
{

        dragObj.BeginDrag() //set the beginDrag flag to true
        dragObj.SetId(id)   //set the id to denote the 'element' we are interested to drag.
}

function HandleMouseMove(eventObj) //this would accept the parameter for event, which is a local object for Firefox.
{                                  //Since it is a global object in Internet Explorer, we don't have to worry about it.

        if(typeof eventObj!="undefined")  //this means browser is Firefox
        {

            if(dragObj.GetId()!=null && dragObj.beginDrag==true)
            {
                dragObj.SetEventObj(eventObj)
                dragObj.RemoveChild()
                dragObj.Move(document.getElementById(dragObj.GetId()),dragObj.GetCurrentCoOrdinates())
            }
        }
        else    //this means browser is Internet Explorer
        {
            if(dragObj.GetId()!=null && dragObj.beginDrag==true)
            {
                    dragObj.SetEventObj(event)
                    dragObj.RemoveChild()
                    dragObj.Move(document.getElementById(dragObj.GetId()),dragObj.GetCurrentCoOrdinates())
            }
        }

}

When the drag ends the zIndex would be set back to null.Setting zIndex brings the element in question in the foreground. Finally you would have to add this piece of code while declaring the element :

onmousedown="javascript:HandleMouseDown(this.id)" onmouseup="javascript:HandleMouseUp(this.id)" onmousemove="HandleMouseMove(this.id)"

We are now ready to drag. I have attached a sample for reference.

History

v 1.0 Added

v 1.1 A bug fix,elements now aren't bounded by their parent's area.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here