Help with draggable layers javascript

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
hi every one, I needed a (java)script to make a division draggable and got the following code from dynamicdrive:
Code:
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 a = window.event ? window.event: e;
    this.targetobj = window.event ? event.srcElement: e.target;
    if (this.targetobj.className == "draggable")
       {       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 = a.clientX;
        this.y = a.clientY;
        if (a.preventDefault) a.preventDefault();
       
        document.onmousemove = dragobject.moveit;
       }
   }
, moveit: function(e)
   {var a = window.event ? window.event: e;
    if (this.dragapproved == 1)
       {this.targetobj.style.left = this.offsetx + a.clientX - this.x + "px";
        this.targetobj.style.top = this.offsety + a.clientY - this.y + "px";
        return false;
       }
   }
};
dragobject.initialize();

function ftoggle(id) //I added this myself...
   {document.getElementById(id).style.display = "";
    if (document.getElementById(id).style.visibility == "hidden")
       {document.getElementById('icon').style.display = "none";
        document.getElementById(id).style.visibility = "";
       }
    else 
       {document.getElementById(id).style.visibility = "hidden";
        document.getElementById('icon').style.display = "";
       }
   }
Now an html page with the following code:
HTML:
<style type="text/css">
#player {
background: url('m.png') no-repeat -1px 0;
cursor:move;
position:relative;
z-index:100;
height:250px;
width:192px;
}
#f {
height:260px;
position:absolute;
top:26px;
}
#c {
position:absolute;
right:7px;
top:7px;
}
</style>
<div id="player" style="display:none; visibility:hidden;" class="draggable">
<div id="c"><img style="cursor:pointer" src="min.png" onclick="ftoggle('player')"/></div>
<div id="f">
<iframe scrolling="no" frameborder="0" style="height:2580px; width:200px;" src="player/index.html"></iframe>
</div>
</div>
<div id="icon">
<a onclick="ftoggle('player')">click</a>
</div>
Now everything works fine as intended:On clicking the '<a onclick="ftoggle('player')">click</a>' , the visibility of the layers: "icon" and "player" toggles and the layer player is draggable and works smoothly.
But the problem begins when i add an iframe to the body, on doing so, the script slows terribly on firefox 3.6 and google chrome , but works well on ie.
here's the iframe code that i added:
HTML:
<div style="position:absolute; top:0px;width:100%;height:100%; z-index:0;">
<iframe id="frame" src="websiteurl" scrolling="auto" marginwidth="0" marginheight="0" frameborder="0" class="c1" name="frame" ></iframe>
</div>
Can someone help me modify the script so that it uses less memory load, and works smoothly?
(I have 1 gb of RAM and am not experiencing any other speed troubles)
- I am using the IM script from fleaim.com and the script used to drag the IM box in that page works fine even with iframes.
So it would be even fine if someone can get me some script like that since For some reason or the other I cant figure out how that one works!
Thanx in advance.
 
Last edited:

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
I somewhat changed the javascript and ended up with this:
The html:
HTML:
<!DOCTYPE html PUBLIC"-// W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <style type="text/css">body{margin:0px;overflow:hidden;}iframe.c1{position:absolute;top:0px;z-index:0;overflow:visible;height:100%;width:100%}
    </style>
    <title>  </title>
    <style type="text/css">#player{position:absolute;z-index:100;height:250px;width:192px;}#f{position:absolute;height:249px;width:192px;left:1px;z-index:100;top:26px;}#c{position:absolute;z-index:110;height:250px;width:192px;cursor:move;}
    </style>
  </head>
  <iframe id="frame" src="http://blog.cyberflare.co.cc/index.php" scrolling="auto" marginwidth="0" marginheight="0" frameborder="0" class="c1" name="frame">
  </iframe>
  <div id="player" style="display:none;visibility:hidden;top:0;left:0">
    <div onmousedown="dragOBJ(document.getElementById('player'),event);fhide('hidden');return false" onmouseup="fhide('')" id="c">
      <img alt="" src="m.png">
      <img alt="" style="position:absolute;right:7px;top:7px;z-index:100;cursor:pointer" src="min.png" onclick="ftoggle('player')">
    </div>
    <iframe id="f" scrolling="no" frameborder="0" src="http://google.com">
    </iframe>
  </div>
</html>
and the javascript:
HTML:
$(v);
   {return (document.getElementById(v));
   }

function agent(v)
   {return (Math.max(navigator.userAgent.toLowerCase().indexOf(v), 0));
   }

function xy(e, v)
   {return (v ? (agent('msie') ? event.screenY + document.body.scrollTop: e.pageY): (agent('msie') ? event.screenX + 
      document.body.scrollTop: e.pageX));
   }

function dragOBJ(d, e)
   {
   function drag(e)
       {if ( ! stop)
           {d.style.top = (tX = xy(e, 1) + oY - eY + 'px');
            d.style.left = (tY = xy(e) + oX - eX + 'px');
           }
        return false;
       }
    var oX = parseInt(d.style.left), oY = parseInt(d.style.top), eX = xy(e), eY = xy(e, 1), tX, tY, stop;
    document.onmousemove = drag;
   
    document.onmouseup = function()
       {stop = 1;
        document.onmousemove = '';
        document.onmouseup = '';
       };
   }

function ftoggle(id)
   {document.getElementById(id).style.display = "";
    if (document.getElementById(id).style.visibility == "hidden")
       {document.getElementById(id).style.visibility = "";
       }
    else document.getElementById(id).style.visibility = "hidden";
   }

function fhide(s)
   {document.getElementById('f').style.visibility = s;
   }
Now this speeded up things a lot in google chrome and it works well, but with firefox it's still the same, can anyone help?
 
Last edited:

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
hey, You wont believe this! I just found out that it happens only if the iframe links to my page! If you give something like google.com as the source(for the background iframe), it just works fine. i dunno if I am going crazy, can someone check it out here?
 
Last edited:

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
But i don't need the entire functionalities of jquery, and including jquery and the ui for just that would be just make my site bigger...
 

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
Can someone at-least tell me the cause of the problem?
('coz I'm not so experienced with js)
 
Last edited:

farscapeone

Community Advocate
Community Support
Messages
1,165
Reaction score
27
Points
48
jQuery-min is 56KB na you can use some other <20KB plugin to do what you need. I don't think that's too big considering that jQuery code is much smaller than plain JavaScript (like they say "Write Less, Do More") and that you will end up with less code overall. Not to mention how much easier it is to work with it instead of plain JavaScript.

56KB is the price I'm alway ready to pay when it comes to jQuery.

Off-topic:
And please don't double post. It's against the rules of this forum. Use Edit button instead.
 
Last edited:

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
56 kb for just dragging an object is a bad price leviathon, Jquery is very small compared to all the features it encloses and I even have to add the ui, so while most web developers can write a drag code in bytes when you are talking about 56 kb. If someone is experienced enough to tell me what exactly causes the problem, you are greatly welcome because it would also help me learn javascript.
Sorry for the double post, I was in a hurry.
BTW, can u experience the same problem with the test page?
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
56 kb for just dragging an object is a bad price leviathon
It costs less than you think, since browsers will cache the script. Even without caching, 56 KiB won't notably reduce response time on anything other than a dial-up connection, and how many of your users have one of those? At the same time, I understand the desire to avoid waste. In the end, however, your time is just as important as the computer's; reducing development time is as important as reducing runtime.

As for debugging the script, it'd be easier if it were properly indented, according to your indent style of choice.

When it comes to Firefox, I'm not seeing slow performance. What I see is that the draggable object stops moving when the mouse is moved quickly enough to exit the draggable titlebar while over a frame. The reason for this is that when the mouse moves across an iframe, the iframe gets the mousemove event. There are many reasons it works in some browsers and not others:
  • in some browsers, inline event handlers fire during the capture phase, thus the top-level document gets the event before the (descendant) iframes.
  • some browsers might take into account domains when bubbling events; if the child and parent windows have different domains, the event won't bubble.
  • some browsers simply won't bubble events up from a child frame to its parent window. This seems to be the case for Firefox.
The fix is to add 'mousemove' handlers for each frame (iterate over window.frames to get them all), and fire the mousemove event on the parent frame or call the moveit method. There are many pitfalls to avoid:
  • you won't be able to subscribe to events across domains. Within the loop over the frames, enclose the loop body in a try block to catch security exceptions.
  • if you use the 'onmousemove' property of the child frame's document, you'll overwrite any other mousemove handler. Also, the child frame can overwrite your handler. Use addEventListener/attachEvent, wrapped in a suitable API to provide cross-browser consistency, instead.
  • depending on how you bind things, "this" within the child window mousemove handlers may not refer to the same object as in the parent handler. Best to explicitly bind (via a call to "apply") within an anonymous handler.
  • The coordinates of the mouse event will be within the child window's coordinate system. Unless the child window shares an origin with the parent window, you'll need to translate the coordinates. You might need to create a new event, rather than passing along the old one.
 
Last edited:

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
Can you implement the fix in the code(if its simple to do so), misson? Cause I just suck at javascript!
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
If you're not very skilled at JS, the first thing you should do is see if someone has already written a script that does what you want.

Alternatively, I did think of another, simpler approach that will work for all but iframes in the object being dragged: when dragging, bump up the z-index of the dragged object and enable a transparent, full-screen div behind the draggable and in front of everything else:

HTML:
<style type="text/css">
#mousetrap {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: none;
  z-index: -10;
  background: transparent;
}

#mousetrap.armed {
  display: block;
  z-index: 999;
}

.dragging {
  z-index: 1000 ! important;
}
</style>
<body>
  <div id="mousetrap"></div>
  ...
Code:
function hasClass(elt, className) {
    return (new RegExp('\\b'+className+'\\b')).test(elt.className);
}
function addClass(elt, className) {
    if (! hasClass(elt)) {
        elt.className += ' ' + className;
    }
}
function removeClass(elt, className) {
    elt.className = elt.className.replace(new RegExp('\\s*\\b' + className + '\\b\\s*'), ' ');
}

var dragobject = (function() {
  var targetObj, mousetrap, 
      x=0,y=0, offsetx=null, offsety=null;
  function moveit(evt) {
      ...;
  }
  function startDragging (evt) {
      targetobj = evt.target;
      if (hasClass(targetObj, 'draggable')) {
          addClass(targetObj, 'dragging'); // raise draggable
          addClass(mousetrap, 'armed'); // arm mousetrap
          ...
          evt.preventDefault();
          addEventListenerTo(document, 'mousemove', moveit);
      }
  }
  function stopDragging() {
      removeEventListenerFrom(document, 'mousemove', moveit);
      removeClass(mousetrap, 'armed'); // disarm mousetrap
      removeClass(targetObj, 'dragging'); // lower draggable
  }
  function initialize() {
      mousetrap = document.getElementById('mousetrap');
      if (! mousetrap) {
          mousetrap = document.createElement('div');
          mousetrap.id='mousetrap';
          document.body.appendChild(mousetrap);
      }
      addEventListenerTo(document, 'mousedown', startDragging);
      addEventListenerTo(document, 'mouseup', stopDragging);
  }
  addEventListenerTo(document, 'load', initialize);
  return {}; // there's nothing really public about dragobject, so return an empty object.
})();
You'll need to implement addEventListenerTo and removeEventListenerFrom. They provide a consistent event interface based on W3C events. Lotus is down right now, but when it comes back up, I'll post a link to an example implementation for IE (which is the only major browser that needs anything other than a trivial implementation). You could also use any JS library that provides DOM event support.

To deal with iframes in the dragged element, you could take basically the same approach: add a transparent div that covers everything else in the element. This is a little trickier to do, however.
 
Last edited:

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
Thanx for the reply ,misson.
I added the code but its not working right, the error console in firefox reports a syntax error after
"
function moveit(evt) {
...;
}
"
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
As it says in the sig,
Any posted code is intended as illustrative example, rather than a solution to your problem to be copied without alteration. Study it to learn how to write your own solution.
Did you fill out the body of moveit()?
 
Last edited:

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
No, but what am i supposed to add there?
And,
Code:
addClass(mousetrap, 'armed'); // arm mousetrap...
...
What about here?
And 1 more doubt, instead of playing around with addclass and remove class, isn't it possible to use document.object.zIndex ?
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
No, but what am i supposed to add there?
The same thing that was there originally, though you can cut the dragapproved and other unnecessary stuff.

And 1 more doubt, instead of playing around with addclass and remove class, isn't it possible to use document.object.zIndex ?
It's possible, but using the class is more extensible. Should you wish to add additional style or test whether an object is currently being dragged, it's much easier with the class. Setting/removing a class also properly separates style from behavior (read "Separation of CSS and Javascript").

You could also define armMousetrap, raiseDraggable &c. functions to abstract out the way the dragged object and mousetrap are handled, which would be more readable.

Lotus still seems a little wonky, so here's the sample code (untested) posted on Pastebin: DOMEvent_IE_lite.js, DOMEvent_DOM.js

To include the DOMEvent scripts, use conditional comments:
Code:
    <![if ! lte IE 8]>
        <script type="text/javascript" src="/js/DOMEvent_DOM.js"></script>
    <![endif]>
    <!--[if lte IE 8]>
        <script type="text/javascript" src="/js/DOMEvent_IE_lite.js"></script>
    <![endif]-->
 

ciril tomy

New Member
Messages
53
Reaction score
1
Points
0
Are you looking for something similar like this ハプニングバー pop-up?

If so contact me I will help you. I have got this idea from lightbox it works on every browser. and no problem for loading even on IE6!!!

This is NOT an ADULT SITE though the pop-up looks so.
 
Last edited:
Top