views:

177

answers:

5

I have a .wall div with a some .toy divs inside it. I want to arrange the toys inside the wall just like http://goo.gl/4MqM. float:left property has done it for me nicely.

Now the problem is I want to add position:absolute for the toy divs to make it draggable later. How can I do this either via Javascript or via CSS?

Applying position:absolute, all toys will come to the top left corner of the wall overlying and hiding each other.

The width and height of the wall is constant but the width and height of the toys is variable, also the number of toy' divs is dynamic and as the number increasestoy`s need to arrange as rows see http://goo.gl/za1u

Any suggessions will be helpful, please note the I can not avoid the use of position:absolute for dragging.

<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
 <style>
  body{
   text-align:center;
  }
 .clearfix{
  clear:both;
 }
  .wall {
   border: 5px solid #cde;
  margin:auto;
  width:200px;
  padding:10px;
  }
 .toy{
  background-color: #BBCCEE;
  border:1px solid #8899BB;
  margin:5px;
  width: auto;
  padding:5px;
  float:left;
 }
 .tall{
  padding-top:10px;
 }
 </style>
 <script>
  $(document).ready(function() {
  $('.toy').each(function(index) {
   var position = $(this).offset();
   var prevPosition = $(this).prev().offset();
   $(this).css({
    //top: position.top,
    //left:position.left,
    //position:'absolute',
   });
  });
 });
 </script>
<div class='wall'>
 <div class='toy'>T1</div>
 <div class='toy'>T2</div>
 <div class='toy'>T3333333</div>
 <div class='toy'>T4</div>
 <div class='toy'>T5</div>
 <div class='toy tall'>T6</div>
 <div class='toy'>T7</div>
 <div class='toy'>T8</div>
 <div class='clearfix'></div>
</div>

Here is the code JS Bin

+4  A: 

Add

position:relative

To the wall div

mabwi
no@mabwi, adding `position:relative` will render like this http://goo.gl/Xdrn
Mithun P
A: 

the element in that the absolute should be positioned, must have the style position:relative. (must be a parent of the target element)

Moritz
Please understand that I'm using plug in http://plugins.jquery.com/project/drag for DnD, so `toy` divs must have set `position:absolute`
Mithun P
+1  A: 

This would be a lot easier if you just used the jQueryUI .draggable(). It doesn't require the elements to be positioned.

If you're dead set on using this plugin, then you have the right idea. Let the elements flow into place and then calculate their position and set position: absolute and whatever the left and top end up being at runtime.

Set the .wall to be position: relative. Then:

var tPos;

$('.toy').each(function(index) {
    tPos = $(this).position();
    $(this).css({
        left: tPos.left,
        top: tPos.top
    });
};
$('.toy').css({
    position: absolute
});

The height of the .wall and the width of each .toy collapse when the toys are absolutely positioned but you can just add a few more lines to get/set their width and height in the above .each loops.

This obviously doesn't work if new toys can be added dynamically without a page reload as you suggest. To handle that you could switch them back to position: relative, add the new one, get the position of the new one in the flow, then set the position and switch back to position: absolute. Any elements that had been dragged out of place would be gaps in the flow, but I don't see any easy way around that.

jasongetsdown
setting the left, top, and postion:absolute has no effect, see the output here http://goo.gl/60r1
Mithun P
Can you post the code to jsbin.com so I can see your implementation? All I can see from the screenshot is that it isn't working, not why.
jasongetsdown
Here is the code http://jsbin.com/idixe/edit
Mithun P
Ahh, if you insert `alert(position.top + ' ' + position.left);` before you change the CSS you'll see what's going on. When the previous element gets `position: absolute` it reflows the page so the current element now takes the position of the previous one. As a result they all get the same position. I'm updating my example to one that works, you seem to be on the right path already with the second `.each()` you commented out.
jasongetsdown
A: 

The container div for every .toy must have position:relative set. That way, the position 0 for its children elements becomes its top left corner. Like this:

<div class="parent">
    <div class="child">Blah.</div>
    <div class="child">Blah.</div>
</div>

And:

.parent {
  position: relative;
}
.child {
  position: absolute;
  left: 10px; /* This is 10 pixels from the parents left side */
  top: 10px; /* This is 10 pixels from the parents top side */
}

Good luck.

Alan Orozco
This will arrange all the child elements 10 pixels from the parents left side 0 pixels from the parents top side overlaping one on the top of another
Mithun P
@Mithun P: Yes, they will. I was just trying to illustrate my example. By the way, I think you mean "10 pixels from the parent's top side".
Alan Orozco
+1  A: 

I am working on a website that does exactly that (sorry for the non-english stuff):

http://moveit.canassa.com/cartao/4/

The "toy" div is using a position absolute:

.toy{
    width: 100px;
    height: 25px;
    position: absolute;
    z-index: 0;
}

The problem with the position absolute is that the toy will be relative to page and not the "wall" container, in order to fix that you must make the wall container relative:

#wall{
    position: relative;
    overflow: hidden;
}

The overflow:hidden is also a nice trick that I found. It makes the draggable objects go "under" the wall container.

There is no big secret to make it draggable, using jQuery:

// Creates a toy div inside the wall
$(MV.wallId).append('<div class="toy" id="' + this.getId() + '"></div>');

box = this.getBox(); // return the "toy" that I've just created.
$('#' + this.getId()).draggable();  // make it draggable
Cesar Canassa
This is what i exactly want, would be great if you could show me some code snippets
Mithun P
Edited the post in order to include the Javascript part
Cesar Canassa