I need to calculate the width between two elements but I'm not sure how I would go about this. Say I have the following:
<ul id="foo">
<li style="width:10px;">1</li>
<li style="width:20px;">2</li>
<li style="width:30px;">3</li>
</ul>
How would I calculate the distance between 1 and 3 (answer being 20px)? The width can be variable as can the number of list items? (I'm using the Prototype framework)
Thanks
If you mean the horizontal distance between two elements, you need the difference between the top right coord of the left element and the top left coord of the right element. The top right coord of an element is just the top left coord plus its width, as given in Pekka's answer.
To get the top left position an element, you can use the javascript method offsetLeft(). This returns the offset in the x dimension between an element and its parent. You iterate up the DOM tree adding successive offsetLeft's until you get to the document root. The resulting sum is your x position. The excellent Quirksmode shows you how to do this.
Edit: for completeness, I include example javascript to find an element's position:
function getNodePosition(node) {
var top = left = 0;
while (node) {
if (node.tagName) {
top = top + node.offsetTop;
left = left + node.offsetLeft;
node = node.offsetParent;
} else {
node = node.parentNode;
}
}
return [top, left];
}
If you mean the horizontal distance, I would say it's something like:
X position of element 2
minus
x position of element 1 plus width of element 1
to get the width, use getWidth()
to get the position, positionedOffset() might be the right thing, I'm not 100% sure and it depends on your elements' positioning.
And a general caveat, if your elements have padding, it will depend on the browser (IE / FF) whether the padding is calculated into the width or not. This may also apply to the border. You will have to play around and see.
Related
I am trying to make a draggable map. I found how to limit a draggable child for left and top sides but couldn't figure out how to make same thing for right and bottom sides.
How can I limit a draggble child with right and bottom value of parent?
var uright = ui.position.left + 960; /* 960 is map height*/
var pright = parentPos.left + 700; /* 500 is container height*/
if (ui.position.top > parentPos.top) {
ui.position.top = parentPos.top; // works fine
}
if (ui.position.left > parentPos.left) {
ui.position.left= parentPos.left; // works fine
}
if (uright > pright) {
uright = pright; // that doesnt work
}
Here is my jsfiddle
You can try using getBoundingClientRect method instead of using position method.The Element.getBoundingClientRect() method returns a text rectangle object that encloses a group of text rectangles.
rectObject = object.getBoundingClientRect();
The returned value is a TextRectangle object which is the union of the
rectangles returned by getClientRects() for the element, i.e., the CSS
border-boxes associated with the element.
The returned value is a TextRectangle object, which contains read-only
left, top, right and bottom properties describing the border-box in
pixels. top and left are relative to the top-left of the viewport.
You can then get top,left,right,bottom values of the element i.e. rectObject.right,rectObject.top,rectObject.bottom,
Reference: https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect
Alternatively, why don't you try containment option in jquery draggable.
Link : http://api.jqueryui.com/draggable/#option-containment
I'm writing some javascript code to move all absolutely positioned elements down 60 pixels (below a 60 pixel heigh div I'm displaying at the top of other pages on my proxy). Here's the code I have right now (mostly borrowed from another question on stackoverflow):
function getStyle(el, prop)
{
var doc = el.ownerDocument;
var view = doc.defaultView;
if (view && view.getComputedStyle)
{
return view.getComputedStyle(el, '')[prop];
}
return el.currentStyle[prop];
}
function runAfterLoad()
{
var all = document.getElementsByTagName('*');
var i = all.length;
while (i--)
{
var topOffset = parseInt(all[i].offsetTop, 10);
if (getStyle(all[i], 'position') === 'absolute')
{
all[i].style.top = isNaN(topOffset) ? '60px' : (topOffset + 60) + 'px';
}
}
}
Unfortunately this moves all absolute positioned elements down 60 pixels. As it turns out, I found out that absolute positioning isn't actually absolute to the browser window, but absolute to a parent that meets some specific rules. Here's a quote from another answer on here:
This works because "position: absolute" means something like "use top, right, bottom, left" to position yourself in relation to the nearest ancestor who has "position: absolute" or "position: relative"."
So I'm looking for help on how to adjust my current code to only find the elements with absolute position that don't have a parent that is also absolute or relative positioned. Any help is highly appreciated.
Another option would be to use that fact to your advantage. If you were to wrap your entire page in a div which you positioned absolutely (or relatively) with top: 60px, you would essentially move the entire page down 60px at once.
This would also move non-absolute elements. If this is not desired then this won't work.
This effort is in response to my previously un-answered question: Resizable div doesn't stay within containment parameter
Since my resizable div, which is referred to as a pocket, is not the direct child of the container that I want it contained in, I supplied a callback in the resize method that should contain it within the container.
Fiddle here: http://jsfiddle.net/dKuER/12/
My Problem
When you re-size the resizable div to the left (which affects its left position) past the grid boundary, it does not always respect my logic in the callback function. As you drag to the left, you'll notice a blinking action, where the div will switch between its hard-coded left position to the left position determined by the mouse.
Depending on when you discontinue dragging, the left position of the div may either be at the hard-coded position or wherever the mouse stopped dragging.
How do I make sure the callback function's logic is ALWAYS respected?
// Relevant Code
// No blinking action when dealing with the width
//Re-sizing to the right works
if ( (pocketLeft + currentWidth) > (gridLeft + gridWidth) ) {
var deltaWidth = (gridLeft + gridWidth) - (pocketLeft + originalWidth);
ui.size.width = originalWidth -deltaWidth;
}
// This should force the position if the div is re-sized
// past the grid's left boundary
if (pocketLeft < gridLeft) {
ui.position.left = -120;
}
Using the mouse coordinates, and the width attained through the resizable div's object methods ( so obvious! ), rather than deriving it from some obscure calculations, I was able to achieve the correct effect
http://jsfiddle.net/dKuER/16/
var x = event.pageX - $('#grid').offset().left;
var y = event.pageY - $('#grid').offset().top;
if (x < 0)
{
ui.size.width = $(this).width();
ui.position.left = $(this).position().left;
}
I achieved this solution trying to understand the core of the jquery.ui.resizable code. However, I maintain there is more acceptable answer than mine.
I'm having a beyond frustrating problem which I have no idea how to tackle.
My question: How do I determine how many elements exist between two positions in a viewport (a scrollable div in this occasion)?
Say I have a scrollable <div> that has a height of 150 px, but has a viewport at 450px with the majority of it being hidden. The div has children that are 30px high, 15 of them.
Question 2: How could I find out how many first children exist between n1 and n2, it seems pretty easy but it's proving not to be.
I've created a jsFiddle where I have partly solved the solution, it works if the top value is set to 0, but it doesn't work if it's anything else. For example, with this solution I am able to determine that there are 7 visible divs between 0 and 200px. But if I change it to determine how many are between 30px and 230px it tells me 0, when again it should be 7.
Help please!
Try this instead:
var $this = $(this),
topOffset = $this.offset().top;
if (topOffset >= top && topOffset <= bottom) {
elements++;
}
This checks to see if the current element's (in the each()) top offset is greater than the top variable's value and increases the elements only then. This way, you don't need to be constantly updating the height variable.
And this works, as you can see here.
Change it so that the 'height' starts equal to the top value.
Your javascript should be:
var container = $('div#container'),
top = 30,
bottom = 230,
height = top,
elements = 0;
container.find('div').each(function(n)
{
if (top <= height && height < bottom)
{
height = height + $(this).height();
elements++;
console.log(top, bottom, height, elements);
}
});
$('span.top').text(top);
$('span.btm').text(bottom);
$('span.num').text(elements);
That worked for me, Good luck!
Is it possible to change DIV position from absolute to relative (and from relative to absolute)?
DIV should remain on same place.
Because formatting in comments is not work I will publish solution here
$(object).css({position: 'absolute',top: dy, left:dx});
// dy, dx - some coordinates
$(object).css({position: 'relative'});
Does not work: element position after changing to relative is different.
But when I stored offset and set it again after changing to relative, position is the same:
$(object).css({position: 'absolute',top: dy, left:dx});
var x = $(object).offset().left;
var y = $(object).offset().top;
$(object).css({position: 'relative'});
$(object).offset({ top: y, left: x });
you can change that attribute with
$(object).css({position: 'absolute'});
For instance:
You could use jQuery's methods .position() or .offset() to set "top" and "left"
css attribute aswell, that way your object should stay at it's position changing
from relative -> absolute.
I don't think that works vice versa.
demo code: http://jsbin.com/uvoka
If you really want to get the total top offset of an element that is a child of elements with absolute and relative positions you could use this function
function calcTotalOffsetTop(elm)
{
var totalOffsetTop = 0,
curr = elm;
while( curr.parent().is(':not(body)') )
{
curr = curr.parent();
totalOffsetTop += curr[0].offsetTop;
}
return totalOffsetTop;
}
this is the basically the code for the solution given by plodder above.
You can quite easily change it from relative to absolute by using it's offsetLeft and offsetTop values as left and top styles.
The other way around is harder. You would basically have to change it to relative and see where it ended up, then calculate new offset values from the current offset and the desired location.
Note that when the positioning is relative, the element is part of the page flow and may affect other elements. When the position is absolute, the element is outside the page flow and doesn't affect other elements. So, if you change between absolute and relative positioning, you may need to do changes to other elements also if you don't want them to move.
prototype.js has element.absolutize() and element.relativize which work very well.
The problem with going from relative to absolute is that
element.offsetTop and offsetLeft
only give the offset of your element to its parent.
You need to measure the cumualtive offset (i.e.
the offset of your element to its parent +
the offset of the parent to its parent +
the offset of its parent to its parent +
etc.)