Absolute position element left or right depending where it is? - javascript

How can I assign absolute left 0px OR absolute right 0px depending on if the absolute positioned div will go outside of its container div.
I guess an easy example of what I mean is: right click in your browser, see it has that menu position to the right of where you click, well not go all the way to the right of the page, instead of going outside of the page, it stays inside of it so it's still visible.
example: (Hover over boxes)
http://jsfiddle.net/ueSNQ/1/

It sounds like you'll need to use script to work the "depending on if the absolute positioned div will go outside of its container div" bit, IE supports css expressions but you're probably after a cross browser solution.
that said it should be a simple matter of something like this
function isOverflow(parent, child){
var left = 0;
var op = child;
while(op && op != parent){
left += op.offsetLeft;
op = op.offsetParent;
}
return ((left + child.offsetWidth) > parent.offsetWidth);
}
function getHoverHandler(parent, child){
return function(){
if(isOverflow(parent, child)){
child.style.marginLeft = 'auto';
child.style.right = '0px';
child.style.left = '';
}
}
}
function attach(o,e,f){
if(o.addEventListener){
o.addEventListener(e, f, false);
}else if(o.attachEvent){
o.attachEvent('on'+e,f);
}
}
var yellowElement = document.getElementsByTagName('UL')[0];
var list= document.getElementsByTagName('LI');
for(var i = 0; i < list.length; i++){
var element = list[i];
var tip = element.getElementsByTagName('DIV')[0];
attach(element, 'mouseover', getHoverHandler(yellowElement,tip));
}

Well Friend,
Try the following steps
1. You have a container div and on right clicking on it you will need to display a div for example say div with list of menus.
2. Have the left position of the container div in a variable **contLeft** and width of the container in another variable **contWidth**
3. Assign the oncontextmenu event handler on the container div.
4. In the event handler function take the mouse x postion in a variable **mosX** and mouse y position in a variable **mosY** and you have to fix the top position of the div to be displayed as mosY and the left as mosX.
5. In order to maintain the div within the container you have to calculate the container's screen occupation as **totPos = (contLeft + contWidth)**
6. Calculate the screen occupation of the menu div as **posMenu = (mosX + width of the div)**
7. If the totPos greater than or equal to posMenu display the menu in the same top and left postion using the values of mosY and mosX
8. Else place the menu in position top = mosY and left = (mosX - width of menu div)
Hope this would solve your problem.

Well first of all if the container div has a position set than position: absolute, right: 0px or left: 0px will be positioned relatively to the container's position. Else it will be positioned to the first parentNode going up the tree from the desired div which has a position, if none is found it will be relative to the body. So you can search the first parent or grandparent container that has a position set. The question is hard to understand so if you would like to share some examples we would be glad to help.
EDIT:
In the example you posted it is exactley like in my comment, calculate the offsethWidth of the parent and the offsetWidth + left to not be overflowing if it is decrease the left or just remove left and set the right positioning. For the same effect on width and height you have to make some cases for the corners.

Related

Scroll to the Bottom of Dynamic Div

I have a div with id "page-content", it does not have height or width, it just have a blank div.
I'm filling that div with content dynamically, so the div height is growing constantly, I'm making a chat, and i want to detect if I am at the bottom of the div or in the last 10% of the div total height, If true, scroll to the bottom
var box = $('#page-content');
if (box.scrollTop() > (box.height*0.90))
box.scrollTop(25000); // This is the top bottom
What I'm trying to do is, check if you are in the last 10% or less top bottom height of "#page-content" div (not when I'm reading "old messages" at the beginning of the Div), I have a function that appends new messages but I need to scroll down manually to see new messages...so i want to automatically scroll to the New bottom so i can see the new message :)
UPDATE:
function getChat() {
$.ajax({
type: "GET",
url: "refresh.php?lastTimeID=" + lastTimeID
}).done( function( data )
{
var jsonData = JSON.parse(data);
var jsonLength = jsonData.results.length;
var html = "";
for (var i = 0; i < jsonLength; i++) {
var result = jsonData.results[i];
html += '<span class="color-'+result.color+'"><b>'+result.usrname+'</b></span> <i class="fa fa-angle-right"></i> '+result.chattext+'<br>';
lastTimeID = result.id;
}
$('#page-content').append(html);
if(html!="")
{
// Here i need to check if the scroll position is in the bottom or in the last 10%
//then this to scroll to the top bottom (25000 is height limit)
$('.page-content').scrollTop(25000);
}
}); }
The trick is that inside the container for your messages (in your case the #page-content DIV), you can have an invisible placeholder div with some id set on to it.
In this demo JSFiddle, as you click on the anchor .addItem, after the new item is added to the container, the placeholder div is moved to the end of the container. This ensures at the same time that clicking on the .addItem brings the bottom of the container DIV into view (as it refers the id of the placeholder in its href attribute).
function scrollToBottom(container) {
// get all the child elements of the container
var children = container.children('.item');
// move the placeholder to the end of the container
$('#contentBottom').insertAfter(children.eq(children.length - 1));
}
Update
In order to determine your current scroll position, you should listen to scroll events in the container. Meanwhile, you should take into account the updated height value of the container when new messages arrive.
Check out this updated fiddle in which I'm checking if the current scroll position is beyond 60 % from the top to easily see the effect.
Note: If a new message comes when you are not scrolling, you can simply do $('.container').scrollTop(25000) in the same function/block of code that appends it to the container.
there is a trick in scrolling the page to bottom of DIV, i tried implementing it in this fiddle.
See $(window).height()+$(window).scrollTop() will always be equal to the total height(including paddings,margins) of children of the window, in our case it is equal to the $('#page-content').height()+margin/padding.
CSS:
div#page-content {
height:600px;
border:solid 1px red;
}
in our situation:
$(window).height()+$(window).scrollTop()=$('#page-content').height()+(margin/padding)=600px
so whenever we scroll it, we can attach an scroll() event to the div and easily check whether we are in in the last 10% or less top bottom height of "#page-content"
$(window).on('scroll',function(){
if($(window).height()+$(window).scrollTop()>=($('#page-content').height()*(.9))){
$(window).scrollTop($('#page-content').height()-$(window).height())
}
})
Good luck.
Since I did not make this, I don't want to take credit for it.
There is a jQuery plugin that makes anything that has a scroll bar scroll to a specific location or to an element. Since you want to scroll to a dynamic div, you can call this after you created the div and it will scroll to that location.
You can find the plugin over here.
You can find a demo of the plugin in action over here.
Hope this was what you are looking for.
-W

Unable to calculate the hover element's exact position

I am just trying to get the mouse hover div's position at the right according to the space around. Somehow I am able to do this in first two columns but not for other columns. May be my calculations while writing the condition state are wrong.
Can anyone please help?
JS Fiddle URL:
http://jsfiddle.net/mufeedahmad/2u1zr11f/7/
JS Code:
$('.thumb-over-team li').find('.cover').css({opacity:0});
$('.thumb-over-team li').on('mouseenter', function(){
var $this = $(this),
thisoffset = $this.position().left,
openDivId = $(this).find('.cover'),
thumbContainer = '.thumb-over-team',
speedanim = 200;
if(thisoffset + openDivId.outerWidth() >= $(thumbContainer).outerWidth()){
//thisoffset = $(thumbContainer).outerWidth() - openDivId.outerWidth() - 212;
thisoffset = thisoffset - openDivId.outerWidth()+10;
openDivId.stop().css({'z-index':'9999'}).animate({'opacity':'1', 'left':-thisoffset}, 200);
}else{
openDivId.stop().css({'z-index':'9999'}).animate({'opacity':'1', 'left':'212px'}, 200);
}
}).on('mouseleave', function(){
$(this).find('.cover').stop().css({'z-index':'-1'}).animate({'opacity':'0', 'left':'200px'}, 200);
});
$('.close-parent').on('click', function(){
$(this).parents('.cover').stop().css({'z-index':'-1'}).animate({'opacity':'0', 'left':'200px'}, 200);
});;
In your first conditional, try to calculate the position of the offset as:
thisoffset = ($(thumbContainer).outerWidth() - openDivId.outerWidth() - thisoffset);
That way, you're adjusting the appearing square (.cover) when it doesn't fit inside the container, to be as close possible to its rightmost edge: (maximum width - appearing square width - current li position)
Calculated this way, you can animate it with the new offset in positive:
openDivId.stop().css({'z-index':'9999'}).animate({'opacity':'1', 'left':thisoffset}, 200);
See it working here.
For elements that "almost" fit, the current system isn't completely precise because of what I already pointed out in my previous comment: the appearing square, even if it were at 0 opacity, would still be inside the containing element (($(thumbContainer)) or .thumb-over-team) and it would add its width to the total width of the container.
So your conditional may think that there's enough available space in the container to make the expandable element fit, but that would go out of the screen. As an example, notice that there's a horizontal scrollbar from the very beginning, caused by this effect, where your containing .thumb-over-team element doesn't fit in the screen.
But I would say that more precision in this point would require a fresh new approach to your system where the appearing .cover elements were out of the containing ul .thumb-over-team
Fresh take on the problem, essentially based on the main issue: the expandable text block (.cover) used to add its width to the container (.thumb-over-team). This altered the calculations on available container space, and made the text containers go off screen.
The solution is to make sure the expandable .cover elements aren't contained inside the .thumb-over-team element, so they won't impact the calculations on available width.
Here is a JSFiddle containing this new approach: link.
Explanation of how it works:
The idea was to create a separate element called .cover-container and let's put all the expandable .cover elements in there.
We want to associate every image in the li elements in .thumb-over-team with their appropriate .cover (so the first image triggers the first .cover to show, the second image would show the second cover, and so on.) We achieve is by finding out the index of the element that triggered the event:
thisLiIndex = $this.index() + 1
And then selecting the cover in the matching position:
openDivId = $('.cover-container .cover:nth-child(' + thisLiIndex + ')')
The expandable covers shouldn't interfere with the mouseenter or mouseleave events of .thumb-over-team, so we make it to ignore mouse events via CSS:
.cover-container{pointer-events:none;}
Changing from one image to another would automatically trigger new events, so the expanding covers stay visible when the mouse stays on the images, but close automatically when the mouse exits them.
Since the covers are now outside of $(thumbContainer), openDivID.outerWidth() does not alter $(thumbContainer).outerWidth(), and we can use that safely in our positioning.
If I understand the placement that you want, for covers that fit, the position is the current offset (position of the li element that triggered the event) plus the width of the image and some subtle margin
imageWidth + rightSeparation + thisoffset
And for covers that won't fit inside of the screen, we keep them just inside of the screen
thisoffset = $(thumbContainer).outerWidth() - openDivId.outerWidth();

How can I position a div relative to a list item?

I have an unordered list of pictures, and when I hover over one I want the two pictures to the left to fade out, and a div to appear in their place with text. I've gotten this working, except for positioning the div - I've tried this:
div.position({my: 'left top', at: 'left top', of: other_list_item});
but that just returns an Object ( the new location ) of {left: 0, top: 0}.
I've also tried putting the div in another li element, but it's still a no-go. Here's the div HTML:
<div style="width: 255px; height: 110px; position: absolute;" id="name_popup"><p>Jon Jensen</p><p>Chief Technical Officer</p><p>London, England</p></div>
EDIT I'm working on a JSFiddle example, but there's kind of a lot to put in, so idk when it'll be ready. Anyways, I forgot to mention this bit of fun:
when I call .position() by itself on the element that I'm trying to anchor to, it returns the correct offsets, but when I try to use position() on the other element to match their positions, nothing happens.
I did not quite understand the question, but from my reasoning I get that you are trying to position new divs in place of the faded out images, so here is some code that could fit your situation
$('div').click(function(){
//get the positions of the divs to be faded out
var prev_position = $(this).prev('div').position();
var next_position = $(this).next('div').position();
//create and position new divs
$(this).insertBefore('<div style="position:absolute;top:' +prev_position.top+ 'px;left:' +prev_position.left+ 'px;">Replacing DIV</div>');
$(this).insertAfter('<div style="position:absolute;top:' +next_position.top+ 'px;left:' +next_position.left+ 'px;">Replacing DIV</div>');
//hide the divs
$(this).prev('div').fadeOut();
$(this).next('div').fadeOut();
});
Sometimes, if your parent element has a position set, then the .position() will get the position relative to the parent element, and depending in your needs this might throw off your design. So instead you could get the coordinates of the previous and next divs relative to the WINDOW and you could get those like these:
function getPosition($el){
//get the offset coordinates of the recently clicked link
var offset = $el.offset();
var top = offset.top;
var left = offset.left;
//get position of this link relative to the window
var rel_top = top - $(window).scrollTop();
var rel_left = left - $(window).scrollLeft();
}

How to fix the width of a DIV to its parent TD

Here's what I would like to see on my website. A table with the width of the body, and three columns: 20%, 70%, 10%. As the browser window resizes, so does the table, and so do the columns of the table change their respective width.
The left column (the 20% width one) contains a DIV element, and that contains some text:
<body style="width:100%;">
<table style="width:100%;">
<tr>
<td style="width:20%">
<div style="position:relative;">
Here goes some text. This is a lot of text and usually should wrap around inside of the DIV element.
</div>
...
</tr>
</table>
</body>
This all works just fine, wrapping and all. Now when the user scrolls the page down, the DIV element and its content scrolls up and out of the window.
What I want to do is to "fix" the DIV to the top of the browser before it leaves the visible area. When the user scrolls up again, the DIV should detach from the top of the browser and resume its normal position. The end effect is that the DIV either scrolls around inside of the visible area, or attach to the top of the browser otherwise. This is implemented with a simple Javascript callback that I attached to the onscroll event, which changes the position between fixed and relative. Works fine too.
Now the only thing that I noticed is that the width of the DIV changes! It is equal to the width of the parent TD as long as it scrolls along and as long as the DIV's position is relative. The moment the Javascript callback changes the position to fixed the width of the DIV changes and overflows into the neighboring table column.
How can I contain the dimensions of the DIV?
Thanks :)
Thanks #abelito for the hint :) Turns out that the solution is a little easier than this. I do need to change the width of the DIV element when I change its position, but since the TD has a 20% width, all I have to do is to toggle the width of the DIV between 20% and 100% depending on its position value. Here is the Javascript which works:
var div_is_sticky = false;
window.onscroll = function() {
var y = window.scrollY;
if (y >= 250) {
if (div_is_sticky) {
// Do nothing.
}
else {
var div = document.getElementById("submenudiv");
div.style.position = "fixed";
div.style.width = "20%";
div_is_sticky = true;
}
}
else if (y < 250) {
if (div_is_sticky) {
var div = document.getElementById("submenudiv");
div.style.position = "relative";
div.style.width = "100%";
div_is_sticky = false;
}
else {
// Do nothing.
}
}
}
Thanks!
Sounds like you're also going to have to take control of the width of the DIV once the position is changed to fixed. If you're using raw javascript, try changing the element.style.width to the parent's element.offsetWidth + 'px'. If you're using jquery, you should use the .width() method. Links:
https://developer.mozilla.org/en-US/docs/DOM/element.offsetWidth
http://api.jquery.com/width/
Don't forget to revert the width back to '100%' if the user scrolls back down.

JQuery Offset and ScrollTop Problems

I'm trying to fix a elements position based on the scroll position within the window.
I thought it would be as easy as getting the offset of the element where the fixed element should become fixed and then when the window.scrollTop is equal to it add CSS but it is weird.
It seems as though the offset of the element is larger than the scrollTop largest numeral.
Is there any other way of getting this to work?
I want it to have the same functionality as this with regards to the footer on scroll;
http://be.blackberry.com/
But I don't want to clone the element, I want to detect when it gets to near the bottom of the page and then change the position on the bottom of the element.
Thanks in advance.
B
This should help get you in the right direction:
var footer = $("#footer");
// min amount to show when not scrolled to the bottom of the page.
var minVisable = 25;
$(parent.document).scroll(function() {
// check position
if (window.scrollY + window.innerHeight + minVisable > $("html").height()) {
// if at the bottom of the page, stick the footer to it
footer.css("position","absolute").css("top", $("html").height() - footer.height());
} else {
// else keep top part of footer on the screen
footer.css("position","fixed").css("top", window.innerHeight - minVisable );
}
});

Categories