Check if element is off right edge of screen - javascript

How can I write an if condition that will run if an element is 60% of the window's width worth off the screen?
I've tried using style.left > '40%' but that doesn't seem to work. Or be right.

You can use javascript and jQuery to do this pretty easily.
To find the right edge of your object (stored in memory as f here), use this code:
var rightEdge = f.width() + f.offset().left;
To find the screen width, you can use this code:
var screenWidth = $(window).width();
The amount of object that is "off screen" is calculated by subtracting screenWidth from rightEdge, therefore this boolean expression describes when the object is more than 60% off the screen:
rightEdge-screenWidth > f.width()*.6
Here's a working demo:
http://jsfiddle.net/YeyFj/

This isn't directly answering your question, but I created this fiddle that might make it easier to play with the math that you need to do.
http://jsfiddle.net/5ucbX/
var w = $('#container').width();
var el = $('#el');
el.draggable({
stop: function () {
var ew = el.width();
//this is your "formula"
var l = el.offset().left + (ew * .6);
if (l > w) {
el.addClass('over')
}
else {
el.removeClass('over')
}
}
});

Related

Is there any good way to determine the "actual content width" of a web page?

Here's what StackOverflow looks like on my (huge) work monitor:
That is a lot of white space on either side of the site's actual content.
I get that this is how a very large percentage of websites are designed—so I'm not singling out SO here—but that's actually exactly why I'm asking this question. I'm thinking it'd be really nice if I had some reliable way (say, via JavaScript) of determining the "actual" width of a website, which I could then use to write a quick script that would auto expand any site I'm browsing to fill the available width on my monitor. As it is, I find it absurd that sometimes I still squint before reading tiny text before realizing/remembering to zoom in to take advantage of my enormous screen.
Ahh... much better.
I suspect this is possible, at least to a reasonable degree via some heuristic, as my Android phone appears to do something a lot like this when I double-tap on the screen while browsing the web.
This will do something sorta like that. Though probably misses all kinds of edge cases.
// Assuming jQuery for simplicity
var drillIn = function(node) {
var max = 0;
var windowWidth = $(window).width();
var result = 0;
$(node).children().each(function() {
var $this = $(this);
if ($this.width() > max) {
max = $this.width();
}
});
if (0 < max && max < windowWidth) {
return max;
} else {
$(node).children().each(function() {
var childMax = drillIn(this);
if (childMax > result) {
result = childMax;
}
});
return result;
}
};
drillIn(document.body);
Working Fiddle: http://jsfiddle.net/bdL5b/1/
On SO, I get 960 which is right. Basically it drills into the DOM tree to find the widest node closest to the root which is not 0 or the window width. Because usually, close to the root node there is a container node which holds the site content. Usually.
Not sure you will get a 100% reliable solution though. This is a tricky thing because there are a TON of ways to style websites. I bet crazy stuff like horrible use of absolute positioning could be a serious thorn in your ass.
If you use Firefox, Greasemonkey is awesome. It will run Javascript that you write on any page (I have used it on Stack Overflow's site before).
Just use the browser's built-in "inspect element," to get the id of whatever you want to expand and do this:
document.getElementById("content").style.width = "100%"; // content is just an example
I think the class name of the middle boxes is .container so you could do this:
var boxes = document.getElementsByClassName("container");
for(var i = 0; i < boxes.length; i++)
{
boxes[i].style.width = "100%";
}
As far as a heuristic for doing this arbitrarily, there's probably no good way to do it to all web pages in an unbiased way, without significantly messing up the site's appearance.
That being said, this or something similar might work ok:
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++)
{
divs[i].style.minWidth = "90%";
}
Ha! I've got something close (though I'm also going to try Alex's approach):
The following relies on jQuery and is arguably inefficient (it inspects, I believe, every element in the DOM); but it doesn't take any time on my machine and at least works with SO:
(function($) {
function text($element) {
return $.trim($element.clone().children().remove().end().text());
}
function hasContent($element) {
return $element.is(":visible") && text($element).length > 0;
}
function getExtremeEdges($elements) {
var extremeLeft = null;
var extremeRight = null;
$.each($elements, function(i, el) {
var $element = $(el);
var offset = $element.offset();
if (!extremeLeft || offset.left < extremeLeft) {
extremeLeft = offset.left;
}
if (!extremeRight || (offset.left + $element.width()) > extremeRight) {
extremeRight = offset.left + $element.width();
}
});
return [extremeLeft, extremeRight];
}
var $elementsWithContent = $("*").filter(function(i, el) {
return hasContent($(el));
});
var extremeEdges = getExtremeEdges($elementsWithContent);
var width = extremeEdges[1] - extremeEdges[0];
var desiredWidth = $(document).width() * 0.95;
if (width < desiredWidth) {
$("body").css("zoom", (desiredWidth / width));
}
}(jQuery));
Minified (to use as a bookmarklet):
(function(a){function b(b){return a.trim(b.clone().children().remove().end().text())}function c(a){return a.is(":visible")&&b(a).length>0}function d(b){var c=null;var d=null;a.each(b,function(b,e){var f=a(e);var g=f.offset();if(!c||g.left<c){c=g.left}if(!d||g.left+f.width()>d){d=g.left+f.width()}});return[c,d]}var e=a("*").filter(function(b,d){return c(a(d))});var f=d(e);var g=f[1]-f[0];var h=a(document).width()*.95;if(g<h){a("body").css("zoom",h/g)}})(jQuery);
Time to dogfood this puppy for a while...
I think each website will be too different to have a standard was of auto resizing their content. I belive CSS is the key, by using user defined style sheets. Or something like Stylish. See https://superuser.com/questions/128666/custom-per-site-stylesheet-extension-for-firefox
or https://addons.mozilla.org/en-us/firefox/addon/style-sheet-chooser-ii/
Not much progress but I'm putting what I tried up in case it inspires anyone else:
Works much worse than you would think
Make a bookmarklet that makes all children of body have 100% width. Then, if you click the bookmarklet again, it makes all children of children of body have 100% width. This way, the user can just click until the site becomes more pleasing to them :)
var levels = levels ? levels + 1 : 1;
$('body *:nth-child(' + levels + ')').css({ width: '100%' });
.
First approach to try and figure out where the first meaningful content is
Cool puzzle, I'm employing the awesomeness of jQuery. So I'm approaching it by trying to find the first element which has more non-empty .contents() than .children() because contents also fetches text nodes. Here's what I have so far. It's close, but not quite right because it seems to be searching a bit too deep:
$('body *:visible').filter(function(){
return moreNonEmptyContentThanChildren($(this));
}).first();
function moreNonEmptyContentThanChildren(el) {
var contentCount = 0;
var contents = el.contents();
for (c = 0; c < contents.length; c++) {
elc = contents[c];
if (elc.nodeType != 3 || (elc.nodeType == 3 && $.trim($(elc).text()) != '')) {
contentCount ++;
}
}
return contentCount != el.children().length;
}

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

How to change the left attribute on page resize (jQuery)

I'm having slight troubles with my code. What I'm trying to do is make these element's css property 'left' update according to the difference of it's current left value, and the amount the page resizes. This way, when the page resizes and the background moves over, the elements will move too. Take a look at the code below and I'll describe the issue:
$(window).resize(function() {
var docWidth = $(window).width();
if (docWidth < 1000) {
var difference = 1000-docWidth;
$('#headNav a,#icons div').each(function() {
var left = $(this).position().left;
var newLeft = left - difference;
$(this).css({ 'left' : newLeft });
});
}
});
So the issue that I'm getting is the elements are being given left values of wild numbers, while the value of the variable 'newLeft' is the reasonable, desired value. The each function I think is collecting the sums of these values and running them for each element x amount of times that the elements found exist (so if there's 5 elements it runs 5 times, I mean.) What I want is this code to execute uniquely for each element, but just once each, not each element 10 times! (that's how many elements are in the html).
So my question is, how can this be achieved? I hope I explained myself well enough, this was tough to iterate. Any help is extremely appreciated. Thank you!
Here's a fun trick: Include += in your .css() call:
$(this).css({left: "+=" + difference});
jQuery does the math for you to get the new value.
Try this:
$(window).resize(function() {
var docWidth = $(window).width();
if (docWidth < 1000) {
var difference = 1000-docWidth;
$('#headNav a,#icons div').each(function(iconInst) {
var left = $("#" + iconInst).position().left;
var newLeft = left - difference;
$("#" + iconInst).css({ 'left' : newLeft });
});
}
});

how do i get the x and y position directly under the left bottom side of the input rectangle?

I'm thinking of implementing a custom auto-complete feature so basically my idea now is that i will make an abs positioned div and give it the position here:
(image) http://i.stack.imgur.com/3c5BH.gif
So my question is with a variable referencing the textbox, how do i get the x and y position directly under the left bottom side of the input rectangle?
My script must work in latest versions of IE / FF / Safari / Opera / Chrome
I know i can use a library to do it, but no i'm interested in learning how do they do it (or maybe better ways)?
This question is a lot more complicated than it seems and involves getting the position of the element relative to the document. The code to do so can be pulled from the jquery source (http://code.jquery.com/jquery-1.6.1.js -- search for "jQuery.fn.offset")
in jQuery:
var node = $('#textbox'),
pos = box.offset(); // the complicated piece I'm using jQuery for
node.top += node.height(); // node.offsetHeight without jQuery
node.left += node.width(); // node.offsetWidth without jQuery
The answer can be extremely simplified if you don't care about FF2 or Safari3:
var box = document.getElementById('yourTextBox').getBoundingClientRect(),
left = box.left,
bottom = box.bottom;
x = x offset
y = y offset - ( textbox height +
padding-top + padding-bottom )
Good comments! For my scenario, there is always an offset parent (which is why I use position - http://api.jquery.com/position/). In hopes that it might help someone else wanting a quick fix, here's the code:
// I have a parent item (item) and a div (detail)
// that pops up at the bottom left corner of the parent:
var jItem = $(item);
var pos = jItem.position();
var marginTop = parseInt(jItem.css('margin-top'));
if (isNaN(marginTop)) {
marginTop = 0;
}
$(detail).css("top", pos.top + jItem.outerHeight() + marginTop)
.css("left", pos.left);
$(detail).show();
Just give the box a defined width and height. Then, get its top and left property and add it with the width and height. Simple. I am gonna give you Pseodocode.
<STYLE>
object{width: 100px; height: 20px;}
</STYLE>
<SCRIPT>
x = object.left;
y = object.top;
x = x + object.width;
y = y + object.height;
</SCRIPT>

Javascript for preventing "burn-in" problem on lcd screen

I'm building a non-public web app that will be used as info-monitor. As such, it will be running 24/7 on one LCD TV display.
Since this could produce a "burn-in color" error on the LCD I'm looking for a Javascript that will prevent/reduce this problem. I want to use something similar to those they use on airport displays (a line periodically moving from left to right and top to bottom and switching color).
Do you know any Javascript doing this? Thank you!
In case you were still interested: (uses jQuery)
var $burnGuard = $('<div>').attr('id','burnGuard').css({
'background-color':'#FF00FF',
'width':'1px',
'height':$(document).height()+'px',
'position':'absolute',
'top':'0px',
'left':'0px',
'display':'none'
}).appendTo('body');
var colors = ['#FF0000','#00FF00','#0000FF'], color = 0, delay = 5000, scrollDelay = 1000;
function burnGuardAnimate()
{
color = ++color % 3;
var rColor = colors[color];
$burnGuard.css({
'left':'0px',
'background-color':rColor,
}).show().animate({
'left':$(window).width()+'px'
},scrollDelay,function(){
$(this).hide();
});
setTimeout(burnGuardAnimate,delay);
}
setTimeout(burnGuardAnimate,delay);
Working example found here: http://www.jsfiddle.net/bradchristie/4w2K3/3/ (or full screen version)
I used Brad's script but unfortunately my page had a large HTMl table that extend outside the parent container. This made it so the pixel bar would only travel part way across the screen. Instead of altering my table I added a bounding box script to find the actual width of the html table and then used that to set the width in Brad's script.
var div = document.getElementById ("HtmlTable-ID");
if (div.getBoundingClientRect) {
var rect = div.getBoundingClientRect ();
w = rect.right - rect.left;
// alert (" Width: " + w );
}
var $burnGuard = $('<div>').attr('id','burnGuard').css({
'background-color':'#FF00FF',
'width':'1px',
'height':$(document).height()+'px',
'position':'absolute',
'top':'0px',
'left':'0px',
'display':'none'
}).appendTo('body');
var colors = ['#FF0000','#00FF00','#0000FF'], color = 0, delay = 5000, scrollDelay = 1000;
function burnGuardAnimate()
{
color = ++color % 3;
var rColor = colors[color];
$burnGuard.css({
'left':'0px',
'background-color':rColor,
}).show().animate({
'left': w +'px'
},scrollDelay,function(){
$(this).hide();
});
setTimeout(burnGuardAnimate,delay);
}
setTimeout(burnGuardAnimate,delay);

Categories

Resources