PDA

View Full Version : Draggable elements script -- acting strange when positioned.



shachi
12-07-2006, 07:01 PM
1) Script Title: Draggable elements script

2) Script URL (on DD): http://www.dynamicdrive.com/dynamicindex4/image3.htm

3) Describe problem: Whenever I try to position any element with top/left properties(with css, not javascript) the element jumps back to top: 0px and left: 0px

Does anyone have any idea why it is acting so strange??

Thank you for your time and interest in this post.

shachi
12-11-2006, 06:09 PM
Hello?? Any help here??

jscheuer1
12-11-2006, 06:31 PM
Any idea, yes. The script itself relies upon absolutely positioning the dragable elements, which it needs total control over in most cases. Style properties in css stylesheets become an element's new defaults, this could often confuse the script, both stylesheet and inline style would distort how the script understands the element's original position on the page.

shachi
12-12-2006, 04:32 PM
Thanks a lot for telling me what was happening but how do I fix this?

jscheuer1
12-12-2006, 05:14 PM
Well, I did say:


Any idea, yes.

It would be easiest if you just used the script as intended. If there is any way you can have it do what you want without using whatever styles mess it up, that would be easiest. Often, designers resort to placing elements on a page with absolute or relative positioning when simple margins or padding would suffice.

There is a mod of this script in the forums here that can pluck a dragable item out of a scrollable div but the item itself is still positioned normally, allowing the script to take full control of its position properties. That's what dragging is, taking full control of an element's position. If you could write a routine that would cancel out the element's style after determining what its static position would have been, you could probably use that. Getting stylesheet style is problematic though.

shachi
12-12-2006, 05:51 PM
jscheuer1: I tried changing it's position to absolute, but still it is behaving same. I tried to change it's stylesheet declarations but unfortunately I have no idea how to do that. Any other fixes for this?

Should I create a sub-division for each element and position the sub-division?

jscheuer1
12-12-2006, 05:57 PM
Don't use any position property, either inline or in its stylesheet entry(s) (if any) for the element to be dragged other than that (if any) required by the script.

Also, as I recall, without modification this script cannot handle elements that are within other elements that have absolute or relative positioning.

shachi
12-12-2006, 07:01 PM
Thanks jscheuer1, I finally fixed it by simply adding these line:



this.targetobj.style.left = parseInt(this.targetobj.offsetLeft);
this.targetobj.style.top = parseInt(this.targetobj.offsetTop);


Thanks again.

jscheuer1
12-13-2006, 05:39 AM
Cool.

shachi
12-13-2006, 04:23 PM
jscheuer1: ok the problem is fixed but is there anyway that I can set limits to the element?

jscheuer1
12-13-2006, 04:35 PM
I think you are one of those people who thinks better sometimes when they put their questions to themselves into writing.

Anyways, yes there must be at least a few ways to do that if you mean preventing the element from moving beyond certain coordinates on the page. A 'if this (top) value is < whatever {stop the drag}' type of thing will put a limit upon how high up the page that you can drag the thing. Similar routines could be worked out for bottom, left and right limits, as desired (respectively):

if this (top) value is > whatever {stop the drag}
if this (left) value is < whatever {stop the drag}
if this (left) value is > whatever {stop the drag}

You may or may not want to take into account the scroll state of the page in these calculations, if that would be important in your scenario.

shachi
12-14-2006, 07:44 PM
I think you are one of those people who thinks better sometimes when they put their questions to themselves into writing.


I didn't get you.


Anyways, yes there must be at least a few ways to do that if you mean preventing the element from moving beyond certain coordinates on the page. A 'if this (top) value is < whatever {stop the drag}' type of thing will put a limit upon how high up the page that you can drag the thing. Similar routines could be worked out for bottom, left and right limits, as desired (respectively):

if this (top) value is > whatever {stop the drag}
if this (left) value is < whatever {stop the drag}
if this (left) value is > whatever {stop the drag}

You may or may not want to take into account the scroll state of the page in these calculations, if that would be important in your scenario.

I already tried that and when I stop the drag(setting the drag flag to false), the object doesn't get dragged when onmousedown is triggered next time.

jscheuer1
12-15-2006, 03:44 AM
Isn't there an entire function for that? If so, use that instead of just changing the flag.

shachi
12-16-2006, 10:14 AM
Nope, there is an anonymous function:



document.onmouseup = function(){
this.dragapproved = 0;
}


But it does just the same thing.

jscheuer1
12-16-2006, 05:58 PM
I see, I was thinking of the DOM Drag script. I wouldn't call that an anonymous function though, technically it may be one. In any event, it is part of a property and prototype function of the dragobject object variable. Any limits that you set on the dragobject should be set as properties (and perhaps as a prototype function or functions) of this dragobject object variable - OR - as modifications to existing one. I like the prototype function:

moveit:function(e)

as a likely candidate for these modifications.

jscheuer1
12-16-2006, 07:00 PM
Working from the default script, I came up with these modifications for moveit:function(e):


moveit:function(e){
var evtobj=window.event? window.event : e;
var xlimit=this.targetobj.xlimit? this.targetobj.xlimit : 500;
var ylimit=this.targetobj.ylimit? this.targetobj.ylimit : 500;
if (this.dragapproved==1){
if (this.offsetx+evtobj.clientX-this.x<xlimit)
this.targetobj.style.left=this.offsetx+evtobj.clientX-this.x+"px"
else
this.dragapproved=0;
if(this.offsety+evtobj.clientY-this.y<ylimit)
this.targetobj.style.top=this.offsety+evtobj.clientY-this.y+"px"
else
this.dragapproved=0;
return false
}
}

Which allows this type of thing to be set just before the closing body tag, if desired:


<body>
<img id="test" src="car.gif" class="drag"><br>
<img src="car2.gif" class="drag"><br>
<h1><b class="drag">Hi there</b></h1>
<script type="text/javascript">
document.getElementById('test').xlimit=300;
document.getElementById('test').ylimit=300;
</script>
</body>

Otherwise, the limit defaults to 500. It could also be written to have no limit if the element's limits were not set and/or to have top and/or left side limits. In fact, as with most scripts, many other things can be done.

shachi
12-17-2006, 08:12 AM
I am having the same problem again, it is partially done but the problem is that the element loses it's drag when it exceeds that limit, it "jumps" and gives a jerky movement. Here's my document so far.



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

.drag{
position:relative;
z-index: 100;
}

/*#test {
width: 100px;
height: 100px;
border: 1px solid;
left: 100px;
top: 100px;
}*/

</style>

<script type="text/javascript">
var dragobject={
z: 0,
x: 0,
y: 0,
offsetx : null,
offsety : null,
targetobj : null,
dragapproved : 0,
initialize : function(){
document.onmousedown = this.drag;
document.onmouseup = function(){
this.dragapproved = 0;
}
},
drag : function(e){
var evtobj = window.event? window.event : e;
this.targetobj = window.event ? event.srcElement : e.target;
if(this.targetobj.className == "drag"){
this.targetobj.style.left = parseInt(this.targetobj.offsetLeft);
this.targetobj.style.top = parseInt(this.targetobj.offsetTop);
this.dragapproved = 1;
if(isNaN(parseInt(this.targetobj.style.left))){
this.targetobj.style.left = 0;
}
if(isNaN(parseInt(this.targetobj.style.top))){
this.targetobj.style.top = 0;
}
this.offsetx = parseInt(this.targetobj.style.left);
this.offsety = parseInt(this.targetobj.style.top);
this.x = evtobj.clientX;
this.y = evtobj.clientY;
if(evtobj.preventDefault)
evtobj.preventDefault();
document.onmousemove = dragobject.moveit;
}
},
moveit : function(e){
var evtobj=window.event ? window.event : e;
var xlimit=this.targetobj.xlimit ? this.targetobj.xlimit : 500;
var ylimit=this.targetobj.ylimit ? this.targetobj.ylimit : 500;
if(this.dragapproved == 1){
if(this.offsetx+evtobj.clientX-this.x < xlimit)
this.targetobj.style.left=this.offsetx+evtobj.clientX-this.x+"px";
else
this.dragapproved = 0;
if(this.offsety+evtobj.clientY-this.y < ylimit)
this.targetobj.style.top=this.offsety+evtobj.clientY-this.y+"px";
else
this.dragapproved = 0;
return false;
}
}
}

dragobject.initialize();
window.onload = init;

function init(){
// document.getElementById("test").style.left = "100px";
}
</script>
</head>
<body>
<!--<div id="test" class="drag"></div>-->
<img id="test" src="http://www.dynamicdrive.com/dynamicindex4/tn00607a.gif" class="drag"><br>
<img src="http://www.dynamicdrive.com/dynamicindex4/tn00738a.gif" class="drag"><br>
<h1><b class="drag">Hi there</b></h1>
<script type="text/javascript">
document.getElementById('test').xlimit=300;
document.getElementById('test').ylimit=300;
</script>
</body>
</html>

jscheuer1
12-17-2006, 08:31 AM
I played around with the script a bit more. I remembered what you had said about using absolute positioning so, I tried that out. My solution was coded slightly differently than yours but, I think, has the same net effect. Let me know if this test page has the jumpiness you were talking about:

http://home.comcast.net/~jscheuer1/side/3col/drag.htm

I had it working with relative positioning too. The only problem I saw in either version was that when drag was stopped in IE 7 over a text object, the portion of the text that the mouse continued to move over got selected. That could probably be easily fixed by setting the element's onselectstart attribute/event to "return false;". This event is unavailable in other browsers but, it wasn't a problem to begin with in FF or Opera, a good sign.

shachi
12-17-2006, 10:54 AM
Works great!! Thanks jscheuer1. But it has one more problem(sorry if I am being too demanding). How can I make the element continue dragging once the mouse get out of the limit and back again? What is happening now is that once the mouse gets out of the limit it needs to pick up the element again to drag it.

jscheuer1
12-17-2006, 06:52 PM
That can be done but, that would be where jumpiness would come into it. You basically have a choice between:

1 ) Forcing the user to reacquire the dragable object after it has been dropped due to moving the mouse cursor outside of the limit region.

and:

2 ) Living with the dragable object jumping to the mouse cursor if it reenters the limit region at a different location than it exited it.

shachi
12-19-2006, 05:35 PM
Why can't it be as easy as others do?(like dnd libraries)

jscheuer1
12-19-2006, 06:53 PM
Why can't it be as easy as others do?(like dnd libraries)

Libraries are written to be extensive and to hold functions for all sorts of eventualities. From that name, I'm not sure which lib you are talking about. And, I'm certainly not sure what their solution is. A sub-routine could be written to smooth the movement back to the mouse cursor in situations like these but, if there is a lib out there that already does this, use that. Is that the sort of solution they use, or did they come up with a different approach?

Could you provide a link to an example?

What would you expect to have happen in cases like that? I think the user should simply have to reacquire the object, they dragged it too far, let them pick it up again.:)

shachi
12-19-2006, 06:58 PM
I guess I will use some other library. I am so sick and tired of all this. An example could be the youngpup's DOM Drag library. I lets you add limits and it acts as smootly too. And I have seen other libraries too that even let you add advance limits(like circular and others).

jscheuer1
12-19-2006, 09:54 PM
I didn't mean to say it cannot be done. However, at the rate we are going, we will end up practically rewriting from scratch one of these other routines and/or libraries. I don't mind doing something like that as a project when I have the time but, it is much more than just a bit beyond the scope of a simple Dynamic Drive scripts help section thread.

shachi
12-20-2006, 11:50 AM
Yea, that's why I give up. I would be more than happy to use a readily available library. Thanks again.

jscheuer1
01-07-2007, 06:27 AM
I know this is sort of a dead thread but, I was working on a couple of other drag scripts recently and discovered a different approach to drag limits using the Math.min() method. I've put up a demo of it:

http://home.comcast.net/~jscheuer1/side/3col/drag_2.htm

This way the object is not dropped and if the mouse remains down can be reacquired at the same point it was left off with no jumpiness because the dragged item follows the mouse in the other dimension when possible. When the mouse returns to the drag area, the drag object is there to greet it.

djr33
01-07-2007, 07:39 AM
Works well.

Two slight issues, though:

1. it continues to go in the opposite direction as how it went off the zone.
Ex: if you drag off the right, then are way outside the zone and move down, it'll still go down with you.
this is true of some desktop things too, but I don't like it. Just adding the same if to the up and down as with the left/right would fix that. (And vice versa.)

2. The area seems to be defined on the right/bottom, but not on the right/top, and you can just drag the objects almost off (though not quite, since the mouse won't go further). Is there a way to limit that as well?