How to calculate where an element should be without moving it? - javascript

I need to change the horizontal position of an element. To do this I change its left attribute with .css('left', value). That would move the element relative to where it should be if there was no left value defined.
Now I need to recalculate the position to move the element somewhere else, to do that I need the position where the element should be if I had not changed its left attribute.
I could remove the left value and ask for its position but then the element would also move and would like to avoid that since I may make the element jump between positions.
How could I get the position where the element would be?

The element doesn't jump between position if you change the left style multiple times. As long as your function is running, there are no updates in the browser. You can safely reset the left style, get the positon, and then set a new left value.

One way would be to read the default left value of the element on DOM-ready and add it to the element as a data-* attribute on the element - let's call it data-default-left or something similar. You could then always refer to that value when you need the default value further on.
The data-* are easy to work with using jQuery's .data() method.

Setting left to 0, recalculating, and setting left to the new position would be the easiest change in your case. In my experience the browser will not repaint between css updates.
Some other options:
Use absolute positioning instead of relative. Then you're origin is consistent.
Use the jQuery UI position plugin. It lets you set the position of an element relative to another. Very useful.

how about use .data() to store this info before starting moving it? Then u just gather it back there everytime u need.

Simple. Store the initial left amount in a variable on dom load and then reference it later when you do your other calculations:
$(function () {
var $element = $("#ME_ELEMENT_ID");
var initialLeft = $element.offset().left;
// Change your left here
$element.css('left', '200px');
// initialLeft still contains the old value
});

Related

JQuery - Improper recalculate on window resize

I wrote a CSS class to create relative position related to the document instead of the parent element. To do this I use jQuery to set the "left" property.
$(function() {
var popoutPosition = $('.lw-popout').offset();
$(".lw-popout").css("left", "-" + popoutPosition.left + "px" );
});
This works great. The problem is it breaks when the window is resized. I have tried the code below, but it does not work. It runs on resize, but the value it calculates is not correct. Anyone have any ideas?
$(window).resize(function () {
var popoutPosition = $('.lw-popout').offset();
$(".lw-popout").css("left", "-" + popoutPosition.left + "px" );
});
your code is only going to work for a single element. If you have multiple elements of that class, they are all going to use the offset of the first element.
offset gives an offset from the document, which is affected by css styles such as left. So once you set it, your technique won't work again until you set left back to the original value.
It might be better to use the offset of the parent instead of its own offset.
More clarity:
Say that in the DOM, the element starts out 100 pixels from the left, which is determined by calling offset().
You then set the left style to "-100px".
Calling offset() again will result in 0, because that is the new position relative to the document.
If you resize the window, the element may move. Perhaps it should now be at 200 pixels from the left, but because the left attribute is set to '-100px', offset() actually gives you a left value of 100. It will always be off.
Possible solutions:
Use translatex instead of left. That moves where the element appears, but doesn't change the actual position in the dom. it will not affect future calls to offset: ie: transform: translateX(-200px)
Set left to 0px before calling offset. That will reset to the default and it can then be calculated properly.
Use position: fixed and set left to 0.
Use the parent position to determine where to position the element. If it has a fixed position within the parent it would work.

Top property is not honored in table row

Is it possible to keep the top row moving like we move the first column in a table using jQuery?
The code I used to keep the first column moving during scroll is something like this.
$('#table-name').scroll(function () {
var _left = $(this).scrollLeft();
$('.firstTd').css('left', _left);
});
when I use the same technique to top property to a table row...through the CSS gets applied it is not honored by the browsers.
P.S: I used left property on td element and want to apply the same technique to a tr tag
Demo here: https://jsfiddle.net/8w4qac30/7/
EDIT
Oops, understood the question bad. I'll keep the info below, but actually my answer is this.
As trs are quite picky, the only thing I can think of is to select all the tds and move them, like you do with the first one, like this: https://jsfiddle.net/8w4qac30/9/
Old answer
left, top, right and bottom are positioning attributes, and for them to work you should set the position attribute too.
position attributes come in different flavors:
relative means to position the element relative to itself, so if you add, for example, left: 20px to a relative positioned element, it simply will shift its position 20 pixels to the left.
absolute means to position the element relative to the first parent that is also relative or absolute positioned.
fixed means to position the element relative to the browser window and will keep fixed during scrolls without additional code. I think that you should go this way.
Check this:
Check the positions here: https://www.w3schools.com/cssref/pr_class_position.asp

How to know if my element is overflowed

I have a slider that contains N elements. Each element will by translated by N pixels when the user click on the next button. When the element is out of the wrapper div, it disappears because it is overflowed by another element.
My plugin does not use any margins, just the transform property.
I would like to know if there is a way to know if my element is out of the div. :visible does not work for my problem because the element is already visible but overflowed.
If I understand correctly, one way to do it would be to compare the position of this element to the size (width/height or both) of his parent.
With Jquery you could do it this way:
<script>
//This is the position of the right side of the element
//relative to his parent
var rightPos = $("#element").position().left + $("#element").width();
//And bottom side
var botPos = $("#element").position().top + $("#element").height();
if (rightPos > $("#element").parent().width()) {
//The element is outside the right limit of the the parent block
} else if (botPos > $("#element").parent.height()) {
//It's outside the bottom limit of the parent block
}
</script>
If it's not the parent you could then adapt this code to compare the position to the width of the correct div, preferably by using the jquery offset() method instead of position().
By determine parent width and get child width then use if condition
if($('span').width() > divWidth){
alert('Overflowed!');
// do something!
}
jsFiddle Demo
if you update your question with your html then I can update with your codes.
You could give the wrapper div the CSS property of overflow: hidden
This would mean that any elements inside of it are not visible when they leave the bounds of the wrapper.
Otherwise you could check whether your element is outside of the wrapper div using jQuery to compare the position to that of the parent.
There is a nice tool for testing if an element is visible on the screen.
Detect if a DOM Element is Truly Visible
It looks at an object and checks each of its parents to see if it’s still visible to the user.

Calculate element-position

I would like to calculate the vertical position of a <div> with jQuery.
How would I do this?
Here's an illustration describing what I mean:
I think you're looking for its offset from the top of the page, right?
$('#div').scrollTop();
If that's not it, maybe the offset would work:
$('#div').offset().top;
Okay, now that it needs to be relative to the parent, try this:
$('#div').position().top;
$('#innerDiv').position()
Get the current coordinates of the
first element in the set of matched
elements, relative to the offset
parent.
jQuery Manual for position()
I think you're looking for
$(elem).offset();
http://api.jquery.com/offset/
If you want it relative to it's container, then you're after http://api.jquery.com/position/ instead.
jQuery has several functions to help you find the offset that you are looking for.
var element = $("#your_element");
// Get the current coordinates of the first element in the set of matched elements, relative to the document.
element.offset()
// Get the closest ancestor element that is positioned.
element.offsetParent()
// Get the current coordinates of the first element in the set of matched elements, relative to the offset parent.
element.position()
// Get the current horizontal position of the scroll bar for the first element in the set of matched elements.
element.scrollLeft()
// Get the current vertical position of the scroll bar for the first element in the set of matched elements.
element.scrollTop()
For more information read about these at the jQuery offset api page.
I reckon that the jQuery API "position()" isn't what you are looking for, since it is defined as "the current position of an element relative to the offset parent" (basically it corresponds to element.offsetTop)
Therefore if you want the top position of the element relative to its parent (not necessary the offset parent), use this instead:
var top = (element.parentNode == element.offsetParent) ? element.offsetTop : element.offsetTop - element.parentNode.offsetTop;

How to get the bounding box of a wrapping inline element with prototype

I used to use cumulativeOffset() and getDimensions() to calculate the bounding box of elements, but just realized that cumulativeOffset returns the top left corner oft the start of an element. Meaning: if an inline element wraps, and the next line is more to the left than the start, I get a displaced bounding box.
After researching a bit, I found that I can use getClientRects() to get all rects. I could then go through, and just take the left position of the rect that's most to the left.
I was wondering if there is a better way of doing this... I just didn't find a boundingBox() prototype function. Did I overlook it?
Edit: I also just found out that getClientRects() is not supported by all browser, so this is no solution.
I don't see a boundingBox() function either, but I wonder if using the same technique (cumulativeOffset() and getDimensions()) on the parent via: getOffsetParent() would do what you want. getOffSetParent():
"Returns element’s closest positioned
ancestor. If none is found, the body
element is returned."
Which should account for word-wrapping where the second line is further left.
I've never heard of a way to do this. You could set it position:relative, drop a 1x1 absolutely positioned div into it, position it right:0, get that div's LEFT + WIDTH, and subtract the offset width of the original inline item from that value.
Saying that, total hack, maybe you need to rethink the reason you want to do this!
The solution given by dfitzhenry seems not working in the case of multiline inline elements.
Here's my Javascript solution : get your inline element nextSibling, check if it is an inline element, otherwise create a new inline element, add it to your inline element's parent and then get its offsetLeft:
var parentContainer = inline_elm.parentNode;
var nextsib = inline_elm.nextSibling;
var remove_next_sibling = false;
if(!nextsib || nextsib.clientWidth != 0){
remove_next_sibling = true;
var temp= document.createElement('span');
parentContainer.insertBefore(temp, nextsib);
nextsib = temp;
}
var inline_bounding_right = nextsib.offsetLeft;
if(remove_next_sibling) parentContainer.removeChild(nextsib);
This is an old post, but the standard method now to get a bounding box is getBoundingClientRect(), which is supported in all major browsers and has had at least partial support since 2009 in most browsers. Enjoy!
P.S. getClientRects() is also very useful for getting the individual bounding boxes of the wrapped text. It seems to have the same browser support as getBoundingClientRect(), since the one depends on the other, and this source suggests that it's well supported.

Categories