How to detect if any divs are overlapping/'touching' a specific div? - javascript

Background Summary
I have a toggle menu that moves and slides down upon document load. However the web page is responsive. So on bigger screen sizes there is empty room for the menu to unroll but some pages contain IMG, DIV, or SPAN tags that rearrange themselves via media queries and take up the needed space for the menu.
Thus one of two things can happen (that are not desired):
a) The page loads, the menu begins to slide open but there is already one of the aforementioned HTML objects already located in its path so the menu unrolls over it, making things look ugly.
b) A mobile visitor enters the site using landscape view and the menu unrolls with nothing in its path, but then the user changes to portrait view causing (sometimes) an HTML tag to overlap the menu.
Desired Result:
I would like the menu to react to its environment so that if some other DIV encroaches on its space, the menu would automatically trigger the click event on itself which would cause it roll back up and sit on its perch on top of the screen.
This would also mean that as it unrolls initially , the menu should be either 'aware' of what is below it and in the case something is there, to not unroll in the first place; or unroll until it touches some other html object in its way, and immediately reverse course and roll back up to its perch.
One quick look is worth a thousand sentences, so please take a look at jsfiddle below.
JSFiddle Setup of Current Code
http://jsfiddle.net/Nick_Wordpress/jLeGq/1/
Current Working Code
jQuery(window).load(function() {
if (jQuery(".toggle").is(":hidden")) {
jQuery(".toggler").trigger("click");
}
});
jQuery(".toggler").on("click touchstart", function() {
toggler = jQuery(this);
room_navigation_top = 150;
pos = 20;
room_navigation_left = 80;
toggler.next(".toggle").is(":visible") ? toggler.next(".toggle").slideUp(function() {
toggler.addClass("minimized").removeClass("maximized").find(".indicator").text("+");
toggler.parent().animate({top:pos + "px", left:pos + "px"});
}) : ("object" == typeof event.originalEvent && (lock_room_navigation = !0), toggler.parent().animate({top:room_navigation_top + "px", left:room_navigation_left + "px"}, function() {
toggler.addClass("maximized").removeClass("minimized").find(".indicator").text("-");
toggler.next(".toggle").slideDown();
}));
});
Thanks in advance for any input towards solving this issue.

Decide whether to expand the menu or not after you've calculated whether it would overlap any other elements. (Expanding first and then checking if you need to collapse it again would be an ugly solution)
Check for potential overlapping by calculating where the menu would be positioned on expansion, and compare that position to the elements which it could overlap.
You should be able to figure out the expanded size if you know the number of menu items and the size of each menu item. Use the top, bottom, left and right properties together with the height and width to figure out the position.
Compare the calculated position of the positions of the elements that risk being overlapped.
Here's some example code for calculating overlap (not written by me): http://jsfiddle.net/98sAG/
function getPositions( elem ) {
var pos, width, height;
pos = $( elem ).position();
width = $( elem ).width();
height = $( elem ).height();
return [ [ pos.left, pos.left + width ], [ pos.top, pos.top + height ] ];
}
function comparePositions( p1, p2 ) {
var r1, r2;
r1 = p1[0] < p2[0] ? p1 : p2;
r2 = p1[0] < p2[0] ? p2 : p1;
return r1[1] > r2[0] || r1[0] === r2[0];
}

Related

How to find exact draggable grid line position in rulerguides.js?

I am currently working in rulerguides.js. And i customized into particular div for rulers and grid line.REFER THIS FIDDLE. Rulers are working fine for me but drag-gable create div (GRID LINES) calculated from body element only , that means top of window and left edges of window.Here In my code i can send particular div for rulers
var evt = new Event(),
dragdrop = new Dragdrop(evt),
rg = new RulersGuides(evt, dragdrop,document.getElementById('workarea'));
I need to start from particular div
(For example : ruler h unselectable class will create horizontal grid line and ruler v unselectable class will create vertical grid line in my working area.)
How to get draggable starting element ? And i need to start in particular div just like image
.
I am struggle for more than 2 days.How to solve this issues?
Actually RulersGuides.js is not intended to be used in containers other than document body, so I would think about placing it in an iframe.
If you really need to have it a in a div, here are some adjustments needed:
Update getWindowSize, getScrollPos and getScrollSize functions to calculate container dimensions.
Instead of using vBound and hBound in mousedown handler you need to introduce vLowBound, vHighBound, etc., where container's left and top offsets will be taken in account, like this:
if (vLowBound === 0) {
vLowBound = container.offsetLeft;
vHighBound = vRuler.offsetWidth + vLowBound;
hLowBound = container.offsetTop;
hHighBound = hRuler.offsetHeight + hLowBound;
}
with appropriate checks
if (
(
(x > vLowBound && x < vHighBound) ||
(y > hLowBound && y < hHighBound)
) && rulerStatus === 1
)
and then
if (y > hLowBound && y < hHighBound) {
and
} else if (x > vLowBound && x < vHighBound) {
accordingly
Update removeInboundGuide accordingly in the same way.
Other than that, I think there'll be needed some changes in dom dimensions calculations, dialogs etc.
Please refer to the following jsfiddle for the details.

How can I determine how many squares are needed to fill a browser window, dynamically?

I'm making colored squares to fill a browser window (say, 20px by 20px repeated horizontally and vertically).
There are 100 different colors, each link to a different link (blog post relevant to that color).
I want to fill the browser window with at least 1 of each colored square, and then repeat as necessary to fill the window, so that there are colored squares on the whole background, as the user drags the window smaller and larger.
If these were just images, setting a repeatable background would work. But, I would like them to be links. I'm not sure where to start on this. Any ideas, tips?
Here's the link to the site I'm working on: http://spakonacompany.com/
I think the most specific piece I need here is this: how can I determine the number of squares needed to repeat to fill the background, using jQuery that dynamically calculates that using the size of the browser window, including when dragged, resized, etc?
Many thanks. :)
To get browser's window width and height I use this function ->
//checking if the browser is Internet Explorer
var isIEX = navigator.userAgent.match(/Trident/);
var doc = isIEX ? document.documentElement : document.body;
function getwWH() {
var wD_ = window;
innerW = wD_.innerWidth || doc.clientWidth;
innerH = wD_.innerHeight || doc.clientHeight;
return {iW:innerW, iH:innerH}
}
There is also a native method of detecting when the browser's window is being resized which works in all major browsers (including IE 8, if you're planning on supporting it) ->
window.onresize = function(){
//here goes the code whenever the window is getting resized
}
So, in order to define how many squares are required to fill the window, you can get the window's width and divide it by the width of the square you are going to fill the window with ->
//getting total number of squares for filling the width and the height
width_ = getwWH().iW; //the width of the window
height_ = getwWH().iH; //the height of the window
If your square's width and height are static 20 by 20, than we can calculate total number of squares per window by dividing our width_ variable by 20 (the same for the height_) ->
squaresPerWidth = width_/20;
squaresPerHeight = height_/20;
So every time our browser window is getting resized we do this ->
window.onresize = function(){
width_ = getwWH().iW;
height_ = getwWH().iH;
squaresPerWidth = width_/20;
squaresPerHeight = height_/20;
//and the rest of the code goes here
}
Haven't tested it but this should work.
Here's something I whipped up. It uses a fixed number of resizable squares, but if you need squares of a fixed size, you just set the window to overflow: hidden and generate an unreasonably large number of squares.
var fillGrid = function(getColor, onClick) {
var tenTimes = function(f){
return $.map(new Array(10),
function(n, i) {
return f(i);
});
};
var DIV = function() {
return $('<div></div>');
};
var appendAll = function(d, all) {
$.map(all, function(e) {
d.append(e);
});
return d;
};
appendAll($('body'),
tenTimes(function(col) {
return appendAll(DIV().css({ height : "10%" }),
tenTimes(function(row) {
return DIV().css({
height : "100%",
width : "10%",
backgroundColor: getColor(row, col),
'float' : "left"
}).click(function() { onClick(row, col); });
}));
}));
};
You have to supply two functions, one to specify the color, the other to be invoked when the user clicks.

Cleaning up a SerialScroll Resize Function

Greeting's
I'am still relatively new to JavaScript and Jquery and I know there has got to be a better method than the one I'am using.
I'am working on a serialScroll implementation. There is a master scrollTo that controls the left/right movement of a number of slides. Each slide contains it's own implementation of a vertical serialScroll. I have the resize on the scrollTo working great and the resize on the vertical works but I can't figure an elegant method for ensuring that on resize the current position remains centered, My current method works but is very inefficient.
$(function(){
var $up = $('#sec1_nav a.up').hide();//up button -- each slide needs it's own unique nav buttons
var $down = $('#sec1_nav a.down');//down button -- each slide needs it's own unique nav buttons
$('#screen1').serialScroll({
target:'#section1',
items:'.item',
prev:'#sec1_nav a.up',
next:'#sec1_nav a.down',
axis:'y',
duration:1000,
force:true,
cylce: false,
onBefore:function( e, elem, $pane, $items, pos ){
$up.add($down).show();
if( pos == 0 )$up.hide();
else if( pos == $items.length -1 )
$down.hide();
// Here's where it get ugly, I'am adding a unique class for each slide to the item's
$('.item').removeClass('pos1'); //Each slides need's it's own class i.e. slide1 = pos1, slide2 = pos2 etc.
$(elem).addClass('pos1');
}
});
$(window).bind("resize", function(){
resize1(); // Same goes for the resize function, each slide need's it's own function.
});
});
function resize1() {
height = $(window).height();
width = $(window).width();
mask_height = height * $('.item').length; // sets the new mask height
// Resize Height of the area
$('.sections').css({height: height, width : width});
$('.item').css({height: height, width : width});
$('#mask').css({height : mask_height, width : width});
$('.sections').scrollTo('.pos1', 0 ); // This issue is where it all fall apart, instead of using serialScroll, i'am stuck using scrollTo to maintain the current slide position.
}

Getting Coordinates of an element on page scroll

I am having this problem where i have a set of 6 UL's having a common class x.Each of them consist of a specific section of the page.Now i have 6 menus that are related to each of the section.What i have to do is highlight the menu when its related section is in users view.
For this i thought that may be jQuery position(); or offset(); could have helped but they give the top and left of the element.I also tried using jQuery viewport plugin but apparently view port is big it can show more than one UL at a time hence i cant apply element specific logic here.I am not familliar to this but does anything changes of an element on scrolling?If yes then how to access it?
Please share your views.
Regards
Himanshu Sharma.
Is very easy to do it using jQuery and a dummy fixed HTML block that helps you find the current position of the viewport.
$(window).on("scroll load",function(){
var once = true;
$(".title").each(function(ele, index){
if($(this).offset().top > $("#viewport_helper").offset().top && once){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
once = false;
}
});
})
Check out a working example: http://jsfiddle.net/6c8Az/1/
You could also do something similar with the jQuery plugin, together with the :first selector:
$(window).on("scroll load",function(){
$(".title:in-viewport:first").each(function(){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
});
})
You can get the viewport's width and height via $(document).width() and $(document).height()
You can get how many pixels user scrolls via $(document).scrollTop() and $(document).scrollLeft
Combining 1 and 2, you can calculate where the viewport rectangle is
You can get the rectangle of an element using $(element).offset(), $(element).width() and $(element).height()
So the only thing left to you is to determine whether the viewport's rectangle contains (or interacts) the elements's rectangle
So the whole code may look like:
/**
* Check wether outer contains inner
* You can change this logic to matches what you need
*/
function rectContains(outer, inner) {
return outer.top <= inner.top &&
outer.bottom >= inner.bottom &&
outer.left <= inner.left &&
outer.right >= inner.right;
}
/**
* Use this function to find the menu related to <ul> element
*/
function findRelatedMenu(element) {
return $('#menu-' + element.attr('id'));
}
function whenScroll() {
var doc = $(document);
var elem = $(element);
var viewportRect = {
top: doc.scrollTop(),
left: doc.scrollLeft(),
width: doc.width(),
height: doc.height()
};
viewportRect.bottom = viewportRect.top + viewportRect.height;
viewportRect.right = viewportRect.left + viewportRect.width;
var elements = $('ul.your-class');
for (var i = 0; i < elements.length; i++) {
var elem = $(elements[i]);
var elementRect = {
top: elem.offset().top,
left: elem.offset().left,
width: elem.width(),
height: elem.height()
};
elementRect.bottom = elementRect.top + elementRect.height;
elementRect.right = elementRect.left + elementRect.width;
if (rectContains(viewportRect, elementRect)) {
findRelatedMenu(elem).addClass('highlight');
}
}
}
$(window).on('scroll', whenScroll);
Let's see if i understood well. You have a page long enough to scroll, and there is an element that when it appears in the viewport, you wanna do something with it. So the only event that's is triggered for sure on the time the element gets in the viewport is the 'scroll'. So if the element is on the page and the scroll is on the viewport, what you need to do is bind an action to the scroll event to check if the element is in the view each time the event is trigger. Pretty much like this:
$(window).scroll(function() {
check_element_position();
});
Now, in order for you to know if the element is in the viewport, you need 3 things. The offset top of that element, the size of the viewport and the scroll top of the window. Should pretty much look like this:
function check_element_position() {
var win = $(window);
var window_height = win.height();
var element = $(your_element);
var elem_offset_top = element.offset().top;
var elem_height = element.height();
var win_scroll = win.scrollTop();
var pseudo_offset = (elem_offset_top - win_scroll);
if (pseudo_offset < window_height && pseudo_offset >= 0) {
// element in view
}
else {
// elem not in view
}
}
Here, (elem_offset_top - win_scroll) represent the element position if there was no scroll. Like this, you just have to check if the element offset top is higher then the window viewport to see if it's in view or not.
Finally, you could be more precise on you calculations by adding the element height (variable already in there) because the code i just did will fire the event even if the element is visible by only 1 pixels.
Note: I just did that in five minutes so you might have to fix some of this, but this gives you a pretty darn good idea of what's going on ;)
Feel free to comment and ask questions

Find DOM elements at top and bottom of scrolling div with jQuery

I have a scrolling div containing list items. I have this boilerplate scroll event defined
$("#scrollingDiv").scroll(function(e) {
});
Inside of this scroll event function, how can I figure out which elements are at the top and bottom of the currently visible area?
You could try computing the positions of the list items with respect to the scrolling <div> and then scan the positions to see which ones match up with the scrollTop of the <div>.
Something like this perhaps:
var base = $('#scrollingDiv').offset().top;
var offs = [ ];
$('li').each(function() {
var $this = $(this);
offs.push({
offset: $this.offset().top - base,
height: $this.height()
});
});
$("#scrollingDiv").scroll(function() {
var y = this.scrollTop;
for(var i = 0; i < offs.length; ++i) {
if(y < offs[i].offset
|| y > offs[i].offset + offs[i].height)
continue;
// Entry i is at the top so do things to it.
return;
}
});
Live version (open your console please): http://jsfiddle.net/ambiguous/yHH7C/
You'd probably want to play with the fuzziness of the if to get something that works sensibly (1px visible hardly makes an element the top one) but the basic idea should be clear enough. Mixing in the height of #scrollingDiv will let you see which <li> is at the bottom.
If you have a lot of list items, then a linear search might not be what you want but you should be able to solve that without too much effort.

Categories

Resources