PDA

View Full Version : Drag and Drop Script - Problem dragging an object over scrollbar



cristysy
01-28-2006, 07:57 AM
I have used your drag and drop script ... it's helpful ... I could drag and drop things already. I have a problem though, it doesn't drag over a scrollbar ... here's the scenario ... I have a 'div A' (whose style.overflow = auto) containing an item or obj to be dragged and dropped to another 'div B'. I can drag the item in 'div A' but when it comes across div A's scrollbar, I couldn't drag it anymore, hence I couldn't drop it to 'div B'. I disabled div A's vertical scrollbar by setting its overflow to blank dynamically, and I was able to drag it across and drop it in div B. But it's not the correct solution since disabling the scrollbar causes div A to expand, destroying the layer design and layout. How can I drag an object over a scrollbar? Pls. help. Thanks!

jscheuer1
01-28-2006, 08:25 AM
I really don't think you can but, I could be wrong. If you post a link to your page and the script, I will play with it and see what might be done. One thought, instead of disabling the scrollbar by setting overflow to blank, try disabling it by setting the overflow to 'hidden'. If you can do this just temporarily, during the dragging process, it will not throw off the layout so much and in fact, any distortions to the layout could be compensated for by temporarily adding a border, margin or padding perhaps, to the division.

whatever
.

Also, there is another drag and drop unit that might not have that problem:

http://www.walterzorn.com/dragdrop/dragdrop_e.htm

cristysy
01-28-2006, 11:40 AM
Hi, thanks for replying. I have tried using 'hidden' as overflow value but it didn't work coz the scrollbar was only hidden from view. I have attached dd_drag_drop.html.txt file ... pls. remove .txt extension (the file attachment tool here doesn't consider html as valid file type). I will also try the 'walter_zorn' link and see if it works. I would really appreciate your help. Thanks again.

jscheuer1
01-28-2006, 11:19 PM
The reason your demo has problems is twofold. In no particular order, the overflow:auto that initializes a scrollbar does cause problems for Mozilla based browsers because they then see the division as a mini page from which no element can escape. If you drag it beyond its borders, it scrolls to accommodate but the dragged item goes underneath the rest of the page. This was not a problem in IE. In both browsers however, using position absolute (or relative in tests here) for the scrolling (and/or potential destination areas) division caused problems because the dragged element was still tied to the absolutely positioned element. I found that by removing the draggable element from the document tree and appending it to the body took care of this problem but, I still cannot figure out how to initially position it at the start of drag. I'm currently using the click event's x/y coords minus half the object's width and height, respectively. This worked fairly well but, causes it to jump to a position where the pointer is at the object's center regardless of where the pointer was at drag start.

I also have been playing with Zorn's unit and find that it works well as long as the position property on other elements on the page is not set via css style. Zorn's unit has many options that I have not fully explored yet so, there may be a way to get it to work even with other elements on the page having a position property other than static.

Back to my method for a moment, once the element is freed from the DOM of its parent and attached to the body, it would be nice to find a way to 'dock' it to the element that it is released over. I will be looking into this and initializing its drag position more intuitively. Here is what I have so far (css position style is now set by the script so is not required in the element's tag):


/**************************************************
* dom-drag.js
* 09.25.2001
* www.youngpup.net
* Script featured on Dynamic Drive (http://www.dynamicdrive.com) 12.08.2005
**************************************************
* 10.28.2001 - fixed minor bug where events
* sometimes fired off the handle, not the root.
**************************************************/
var flag=1
var Drag = {

obj : null,

init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper)
{
o.onmousedown = Drag.start;

o.hmode = bSwapHorzRef ? false : true ;
o.vmode = bSwapVertRef ? false : true ;

o.root = oRoot && oRoot != null ? oRoot : o ;

if (o.hmode && isNaN(parseInt(o.root.style.left ))) o.root.style.left = "0px";
if (o.vmode && isNaN(parseInt(o.root.style.top ))) o.root.style.top = "0px";
if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right = "0px";
if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px";

o.minX = typeof minX != 'undefined' ? minX : null;
o.minY = typeof minY != 'undefined' ? minY : null;
o.maxX = typeof maxX != 'undefined' ? maxX : null;
o.maxY = typeof maxY != 'undefined' ? maxY : null;

o.xMapper = fXMapper ? fXMapper : null;
o.yMapper = fYMapper ? fYMapper : null;

o.root.onDragStart = new Function();
o.root.onDragEnd = new Function();
o.root.onDrag = new Function();
},

start : function(e)
{
var o = Drag.obj = this;
e = Drag.fixE(e);
var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom);
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
o.root.onDragStart(x, y);

o.lastMouseX = e.clientX;
o.lastMouseY = e.clientY;

if (o.hmode) {
if (o.minX != null) o.minMouseX = e.clientX - x + o.minX;
if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX;
} else {
if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
}

if (o.vmode) {
if (o.minY != null) o.minMouseY = e.clientY - y + o.minY;
if (o.maxY != null) o.maxMouseY = o.minMouseY + o.maxY - o.minY;
} else {
if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y;
if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y;
}

document.onmousemove = Drag.drag;
document.onmouseup = Drag.end;
document.onmousedown=function(e){
if (typeof e == 'undefined') e = window.event;
tempx=e.clientX
tempy=e.clientY
}

return false;
},

drag : function(e)
{
e = Drag.fixE(e);
var o = Drag.obj;
if (flag){
var tw=Math.floor(o.offsetWidth/2),
th=Math.floor(o.offsetHeight/2);
o.parentNode.removeChild(o);
o.style.position='absolute'
o.style.left=tempx-tw+'px'
o.style.top=tempy-th+'px'
document.getElementsByTagName('body')[0].appendChild(o)
flag=0
}

var ey = e.clientY;
var ex = e.clientX;
var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom);
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
var nx, ny;

if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);

nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));

if (o.xMapper) nx = o.xMapper(y)
else if (o.yMapper) ny = o.yMapper(x)

Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
Drag.obj.lastMouseX = ex;
Drag.obj.lastMouseY = ey;

Drag.obj.root.onDrag(nx, ny);
return false;
},

end : function()
{
flag=1;
document.onmousemove = null;
document.onmouseup = null;
Drag.obj.root.onDragEnd( parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]),
parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]));
Drag.obj = null;
},

fixE : function(e)
{
if (typeof e == 'undefined') e = window.event;
if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
return e;
}
};

cristysy
01-29-2006, 06:49 PM
Thanks for the explanation, John! I'm really learning a lot. I'll try attaching the draggable element to the body, and find a way as you said to 'dock' it to the element that it is released over. I'll also use the updated dom-drag script.

jscheuer1
01-30-2006, 06:37 AM
Well, I think I've got it, at least a tailor-made solution. I simplified your markup:


<html>
<head>
<style type="text/css">

.drag{
cursor:pointer;
z-index: 100;
}

</style>

<script type="text/javascript" src="dom_drag.js">

</script>
</head>
<body>
<div id="renderingCanvas" style="float:right;position:relative; width: 69.5%!important;width:70%; height: 344px; border: 1px solid black; background-color: gray;">
hello

</div>
<div id='folder_panel' style="position:relative; float:left; width: 30%; height: 344px; background-color: white; border: 1px solid black; overflow: auto; " >
<span>Test 1</span><br>
<span>Test 2</span><br>
<span>Test 3</span><br>
<span>Test 4</span><br>
<span>Test 5</span><br>
<span>Test 1</span><br>
<span>Test 2</span><br>
<span>Test 3</span><br>
<span>Test 4</span><br>
<div class="drag" style="width: 100px; height: 50px; border: 1px solid black; background-color: blue; color: white; font-size: 120%">Draggable DIV 111</div> <span>Test 5</span><br>
<span>Test 1</span><br>
<span>Test 2</span><br>
<span>Test 3</span><br>
<span>Test 4</span><br>
<span>Test 5</span><br>
<span>Test 1</span><br>
<span>Test 2</span><br>
<span>Test 3</span><br>
<span>Test 4</span><br>
<span>Test 5</span><br>
<div class="drag" style="width: 100px; height: 50px; border: 1px solid black; background-color: blue; color: white; font-size: 120%">Draggable DIV 222</div>
<div class="drag" style="width: 100px; height: 50px; border: 1px solid black; background-color: blue; color: white; font-size: 120%">Draggable DIV 333</div>
</div>
<!-- end of renderDiv -->

<script type="text/javascript">
var draggers=document.getElementsByTagName('div')
for (var i_tem = 0; i_tem < draggers.length; i_tem++)
if ( draggers[i_tem].className=='drag' )
Drag.init(draggers[i_tem])
</script>
</body>
</html>

and customized the script to it. The script will work with other markups but, the potential dock elements are currently limited to divisions:


/**************************************************
* dom-drag.js
* 09.25.2001
* www.youngpup.net
* Script featured on Dynamic Drive (http://www.dynamicdrive.com) 12.08.2005
**************************************************
* 10.28.2001 - fixed minor bug where events
* sometimes fired off the handle, not the root.
**************************************************/

function findPosX(obj)
{
var curleft = 0;
if (obj.offsetParent)
{
while (obj.offsetParent)
{
curleft += obj.offsetLeft
obj = obj.offsetParent;
}
}
else if (obj.x)
curleft += obj.x;
return curleft;
}

function findPosY(obj)
{
var curtop = 0;
if (obj.offsetParent)
{
while (obj.offsetParent)
{
curtop += obj.offsetTop
obj = obj.offsetParent;
}
}
else if (obj.y)
curtop += obj.y;
return curtop;
}

var Drag = {

obj : null,

init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper)
{
o.onmousedown = Drag.start;

o.hmode = bSwapHorzRef ? false : true ;
o.vmode = bSwapVertRef ? false : true ;

o.root = oRoot && oRoot != null ? oRoot : o ;

if (o.hmode && isNaN(parseInt(o.root.style.left ))) o.root.style.left = "0px";
if (o.vmode && isNaN(parseInt(o.root.style.top ))) o.root.style.top = "0px";
if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right = "0px";
if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px";

o.minX = typeof minX != 'undefined' ? minX : null;
o.minY = typeof minY != 'undefined' ? minY : null;
o.maxX = typeof maxX != 'undefined' ? maxX : null;
o.maxY = typeof maxY != 'undefined' ? maxY : null;

o.xMapper = fXMapper ? fXMapper : null;
o.yMapper = fYMapper ? fYMapper : null;

o.root.onDragStart = new Function();
o.root.onDragEnd = new Function();
o.root.onDrag = new Function();
},

start : function(e)
{
var o = Drag.obj = this;
e = Drag.fixE(e);
var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom);
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
o.root.onDragStart(x, y);

o.lastMouseX = e.clientX;
o.lastMouseY = e.clientY;

if (o.hmode) {
if (o.minX != null) o.minMouseX = e.clientX - x + o.minX;
if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX;
} else {
if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
}

if (o.vmode) {
if (o.minY != null) o.minMouseY = e.clientY - y + o.minY;
if (o.maxY != null) o.maxMouseY = o.minMouseY + o.maxY - o.minY;
} else {
if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y;
if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y;
}

document.onmousemove = Drag.drag;
document.onmouseup = Drag.end;
document.onmousedown=function(e){
if (typeof e == 'undefined') e = window.event;
var targ=e.srcElement? e.srcElement : e.target
var hAdj=wAdj=0
var tp=targ
while(tp.parentNode){
if (typeof tp.parentNode.tagName!=='undefined'&&tp.parentNode.tagName.toLowerCase()=='body')
break;
if (tp.parentNode.scrollTop)
hAdj+=tp.parentNode.scrollTop;
if (tp.parentNode.scrollLeft)
wAdj+=tp.parentNode.scrollLeft;
tp=tp.parentNode;
}
tempx=findPosX(targ)-wAdj
tempy=findPosY(targ)-hAdj
}

return false;
},

drag : function(e)
{
e = Drag.fixE(e);
var o = Drag.obj;
if (o.style.position!=='absolute'){
if (o.tagName.toLowerCase()=='img') {
var placeHolder=document.createElement('img')
placeHolder.src='../transparentpixel.gif'
placeHolder.width=o.offsetWidth;
placeHolder.height=o.offsetHeight;
}
else {
var placeHolder=document.createElement('div')
placeHolder.style.width=o.offsetWidth+'px';
placeHolder.style.height=o.offsetHeight+'px';
}
o.parentNode.insertBefore(placeHolder, o);
o.parentNode.removeChild(o);
o.style.position='absolute'
o.style.left=tempx+'px'
o.style.top=tempy+'px'
document.body.appendChild(o)
}

else if (o.parentNode.tagName&&o.parentNode.tagName.toLowerCase()!=='body'){
o.parentNode.removeChild(o);
o.style.left=tempx+'px'
o.style.top=tempy+'px'
document.body.appendChild(o)
}

var ey = e.clientY;
var ex = e.clientX;
var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom);
var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
var nx, ny;

if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);

nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));

if (o.xMapper) nx = o.xMapper(y)
else if (o.yMapper) ny = o.yMapper(x)

Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
Drag.obj.lastMouseX = ex;
Drag.obj.lastMouseY = ey;

Drag.obj.root.onDrag(nx, ny);
return false;
},

end : function()
{
var dockObj=0, x=findPosX(Drag.obj), y=findPosY(Drag.obj), xe=x+Drag.obj.offsetWidth, ye=y+Drag.obj.offsetHeight;
var dockers=document.getElementsByTagName('div')
for (var i_tem = 0; i_tem < dockers.length-1; i_tem++)
if (x>findPosX(dockers[i_tem])&&xe<findPosX(dockers[i_tem])+dockers[i_tem].offsetWidth-16&&y>findPosY(dockers[i_tem])&&ye<findPosY(dockers[i_tem])+dockers[i_tem].offsetHeight)
dockObj=dockers[i_tem]
if (dockObj){
document.body.removeChild(Drag.obj)
Drag.obj.style.left=x-findPosX(dockObj)-parseInt(dockObj.style.borderWidth)+'px'
Drag.obj.style.top=y-findPosY(dockObj)+dockObj.scrollTop-parseInt(dockObj.style.borderWidth)+'px'
dockObj.appendChild(Drag.obj)
}
document.onmousemove = null;
document.onmouseup = null;
Drag.obj.root.onDragEnd( parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]),
parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]));
Drag.obj = null;
},

fixE : function(e)
{
if (typeof e == 'undefined') e = window.event;
if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
return e;
}
};

Note: Acts a little oddly in Opera but not too bad, good in IE6 and modern Mozilla.

cristysy
02-03-2006, 09:02 AM
Hi John,

Thanks a lot for your help, I really appreciate it. I made use of the dom-drag.js that you customized. I learned a lot from your code too.