I want all the DOM elements (which can be overlapped by others too) to be listed out which falls under the selection. The thing I tried giving me at a fixed coordinate (with overlapped ones) but I need it to give me for full rectangle.
https://jsfiddle.net/mantrig/3tqqy0gt/
var flag=0;
$("#enable-show").click(function(){
if(flag==0) {
$(document).bind('mousemove', function(e){
$('#tail').css({
left: e.pageX - 80,
top: e.pageY-50,
});
var $elements = GetAllElementsAt( e.pageX , e.pageY);
var html="";
$elements.each(function() {
html += $(this)[0].id + "<br />";
$("#result").html(html);
});
$("#tail").show();
});
flag++;
}
else {
$(document).bind('mousemove', function(e){
$("#tail").hide();
});
flag=0;
}
});
function GetAllElementsAt(x, y) {
var $elements = $("body *").map(function() {
var $this = $(this);
var offset = $this.offset();
var l = offset.left;
var t = offset.top;
var h = $this.height();
var w = $this.width();
var maxx = l + w;
var maxy = t + h;
$("ul").append("<li>" + $this[0].id + " (" + $this[0].tagName + ")" + " [l:=" + l + ",t:=" + t + ",h:=" + h + ",w:=" + w + ",maxx:=" + maxx + ",maxy:=" + maxy + "]</li>");
return (y <= maxy && y >= t) && (x <= maxx && x >= l) ? $this : null;
});
return $elements;
}
Can anyone help with it?
I have 3 elements with background images that I want to scale from x to 1. I want it to begin when the top of the element is just inside the viewport (this may vary a little).
I have achieved this effect the long way:
function animatePanelBackgrounds() {
var $toolsBG = $('#js-tools-bg'),
$dennysBG = $('#js-dennys-bg'),
$verizonBG = $('#js-verizon-bg'),
$llbeanBG = $('#js-llbean-bg');
var dennysTop = Math.floor( $("#js-dennys").offset().top );
var dennysGo = dennysTop - window.innerHeight;
var llbeanTop = Math.floor( $("#js-llbean").offset().top );
var llbeanGo = llbeanTop - window.innerHeight;
var verizonTop = Math.floor( $("#js-verizon").offset().top );
var verizonGo = verizonTop - window.innerHeight;
var toolsTop = Math.floor($toolsBG.offset().top);
var toolsGo = 0;
var ratio, $that;
if ( thisWindows.offsetY() >= toolsGo ) {
ratio = toolsTop/(thisWindows.offsetY()*10);
$that = $toolsBG;
$that.css({
"transform": "scale(" + (1.0 + thisWindows.offsetY()*.0002) + ")",
"-webkit-transform": "scale(" + (1.0 + thisWindows.offsetY()*.0002) + ")",
"-moz-transform": "scale(" + (1.0 + thisWindows.offsetY()*.0002) + ")"
})
}
if ( thisWindows.offsetY() >= dennysGo ) {
ratio = dennysTop/thisWindows.offsetY()*.8;
$that = $dennysBG;
if ( ratio <= 1 ) {
$that.css({
"transform": "scale(1)",
"-webkit-transform": "scale(1)",
"-moz-transform": "scale(1)"
})
} else {
$that.css({
"transform": "scale(" + ratio + ")",
"-webkit-transform": "scale(" + ratio + ")",
"-moz-transform": "scale(" + ratio + ")"
})
}
}
if ( thisWindows.offsetY() >= verizonGo ) {
ratio = verizonTop/thisWindows.offsetY()*.8;
$that = $verizonBG;
if ( ratio <= 1 ) {
$that.css({
"transform": "scale(1)",
"-webkit-transform": "scale(1)",
"-moz-transform": "scale(1)"
})
} else {
$that.css({
"transform": "scale(" + ratio + ")",
"-webkit-transform": "scale(" + ratio + ")",
"-moz-transform": "scale(" + ratio + ")"
})
}
}
if ( thisWindows.offsetY() >= llbeanGo ) {
ratio = llbeanTop/thisWindows.offsetY()*.8;
$that = $llbeanBG;
if ( ratio <= 1 ) {
$that.css({
"transform": "scale(1)",
"-webkit-transform": "scale(1)",
"-moz-transform": "scale(1)"
})
} else {
$that.css({
"transform": "scale(" + ratio + ")",
"-webkit-transform": "scale(" + ratio + ")",
"-moz-transform": "scale(" + ratio + ")"
})
}
}
}
$(window).on('scroll', function() {
animatePanelBackgrounds();
}
I have also achieved this with a function that take a couple simple parameters:
function scaleBackground(element, multiplier) {
var $el = $(element),
elTop = Math.floor( $el.offset().top),
startPosition = elTop - window.innerHeight;
$win.on('scroll', function() {
if(thisWindows.offsetY() >= startPosition) {
var ratio = elTop/thisWindows.offsetY()*multiplier;
if ( ratio <= 1 ) {
$el.css({
"transform": "scale(1)",
"-webkit-transform": "scale(1)",
"-moz-transform": "scale(1)"
})
} else {
$el.css({
"transform": "scale(" + ratio + ")",
"-webkit-transform": "scale(" + ratio + ")",
"-moz-transform": "scale(" + ratio + ")"
})
}
}
})
}
scaleBackground('#js-dennys-bg', '.8');
scaleBackground('#js-llbean-bg', '.8');
scaleBackground('#js-verizon-bg', '.8');
I feel like this should be handled in a loop of some sorts, but I haven't had any luck. Here's my basic attempt, I've tried tweaking little things in it along the way with 0 success:
var panels = $('.panel__bg');
for ( i = 0; i < panels.length; i++ ) {
var $that = $(panels[i]),
begin = $that.offset().top;
if ( begin <= window.scrollY ) {
var ratio = begin/(window.scrollY * 10);
if ( ratio <= 1 ) {
$that.css({
"transform": "scale(1)",
"-webkit-transform": "scale(1)",
"-moz-transform": "scale(1)"
})
} else {
$that.css({
"transform": "scale(" + ratio + ")",
"-webkit-transform": "scale(" + ratio + ")",
"-moz-transform": "scale(" + ratio + ")"
})
}
}
}
My question, finally, is simply: What is the best way to do this. By "best way", I am extremely concerned with performance and secondly concerned with readability/fewest lines of code.
Here is some critique for your code. It's untested, but hopefully it addresses some of your concerns.
// .each is easier to understand, and cleaner looking than a for loop
$('.panel__bg').each(function(i, panel){
// name this something that makes more sense than "$that", e.g. "$panel"
var $panel = $(panel),
begin = $panel.offset().top;
if ( begin <= window.scrollY ) {
// caps to ratio=1. no need for if/else block
var ratio = Math.min(1, begin/(window.scrollY * 10));
// on SO, it helps to only show code relevant to the issue
$panel.css({"transform": "scale(" + ratio + ")" });
}
});
I assume this code is being run every time the scroll event is fired. You might run into trouble on ios because js execution is blocked during scroll. See this issue.
Not sure if this is really THE BEST way to do it, but here are some of the things I would do:
1 - as suggested already, using CSS and toggle class is probably better than using jQuery CSS method. And since all your elements share same styles instead of IDs you can use common class (as you already did in second snippet), so we have something like this:
.panel__bg {
transform: scale(0.8);
}
.panel__bg.is-visible {
transform: scale(1);
}
2 - This is small jQuery plugin used to check elements visibility:
(function($) {
/**
* Copyright 2012, Digital Fusion
* Licensed under the MIT license.
* http://teamdf.com/jquery-plugins/license/
*
* #author Sam Sehnert
* #desc A small plugin that checks whether elements are within
* the user visible viewport of a web browser.
* only accounts for vertical position, not horizontal.
*/
$.fn.visible = function(partial) {
var $t = $(this),
$w = $(window),
viewTop = $w.scrollTop(),
viewBottom = viewTop + $w.height(),
_top = $t.offset().top,
_bottom = _top + $t.height(),
// if partial === false, visible will be true when 100% of element is shown
compareTop = partial === true ? _bottom : _top,
compareBottom = partial === true ? _top : _bottom;
return ((compareBottom <= viewBottom) && (compareTop >= viewTop));
};
})(jQuery);
3 - since you are listening for scroll events you should probably look into requestAnimationFrame and include this polyfill if you need support for IE9 or less and Android 4.3 or less.
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
4 - utilizing rAF you can optimize scroll events or even avoid them. I didn't test for performance difference between two linked examples, but I choose latter for brevity
5 - finally, your scaleBackground function is now basically just class toggler thingy that accepts element class and modifier class
(parts 4 & 5 are wrapped inside IIFE to avoid global variables)
(function() {
var scaleBackground = function(element, triggerClass) {
var $element = $(element);
$element.each(function(i, el) {
var el = $(el);
// check if it's shown
if (!el.hasClass(triggerClass) && el.visible(true)) {
el.addClass(triggerClass);
}
});
};
var lastPosition = -1;
var loop = function() {
// Avoid calculations if not needed
if (lastPosition == window.pageYOffset) {
requestAnimationFrame(loop);
return false;
} else {
lastPosition = window.pageYOffset;
}
// do stuff you need to do
scaleBackground(".panel__bg", "is-visible");
requestAnimationFrame(loop);
};
loop();
})();
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
})();
(function($) {
/**
* Copyright 2012, Digital Fusion
* Licensed under the MIT license.
* http://teamdf.com/jquery-plugins/license/
*
* #author Sam Sehnert
* #desc A small plugin that checks whether elements are within
* the user visible viewport of a web browser.
* only accounts for vertical position, not horizontal.
*/
$.fn.visible = function(partial) {
var $t = $(this),
$w = $(window),
viewTop = $w.scrollTop(),
viewBottom = viewTop + $w.height(),
_top = $t.offset().top,
_bottom = _top + $t.height(),
// if partial === false, visible will be true when 100% of element is shown
compareTop = partial === true ? _bottom : _top,
compareBottom = partial === true ? _top : _bottom;
return ((compareBottom <= viewBottom) && (compareTop >= viewTop));
};
})(jQuery);
(function() {
var scaleBackground = function(element, triggerClass) {
var $element = $(element);
$element.each(function(i, el) {
var el = $(el);
// check if it's shown
if (!el.hasClass(triggerClass) && el.visible(true)) {
el.addClass(triggerClass);
}
});
};
var lastPosition = -1;
var loop = function() {
// Avoid calculations if not needed
if (lastPosition == window.pageYOffset) {
requestAnimationFrame(loop);
return false;
} else {
lastPosition = window.pageYOffset;
}
// do stuff you need to do
scaleBackground(".panel__bg", "is-visible");
requestAnimationFrame(loop);
};
loop();
})();
.panel__bg {
transform: scale(0.8);
transition: transform .3s ease;
width: 200px;
height: 200px;
position: absolute;
background: hotpink;
}
.panel__bg.is-visible {
transform: scale(1);
}
.one { top: 800px; }
.two { top: 1600px; }
.three { top: 3200px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="panel__bg one">test 1</div>
<div class="panel__bg two">test 2</div>
<div class="panel__bg three">test 3</div>
references:
http://codepen.io/chriscoyier/pen/DjmJe
https://css-tricks.com/using-requestanimationframe/
https://gist.github.com/paulirish/1579671
http://www.html5rocks.com/en/tutorials/speed/animations/
https://gist.github.com/Warry/4254579
codepen demo
Hi i want to calculate the position of the Div. Pardon me if i am not able to explain it properly but i will try to explain everything in the simplest way. I am creating sidepanel ad and to place the panels i want the position of the width. When i upload the script on my server then i get a small script which we place on the publisher website and where our script runs inside the iframe. I want to get the position of the div which has a class 'content'. Here is the screen shot.
in the above screenshot the yellow highlighted script is calculating the position of the div class="content" which is in red box. My code was working fine but on the publisher site it was not working fine and i was only able to get only two Divs whose id is like ebDiv..... (these divs are above the yellow highlighted js).
Then i found out to read the parentDiv in order to get the content positions.
i wrote this code.
var parentDoc = window;
while (parentDoc !== parentDoc.parent) {
parentDoc = parentDoc.parent;
}
parentDoc = parentDoc.document;
var parentDiv = parentDoc.getElementsByTagName('div');
var divs = [];
for (var i = 0; i < parentDiv.length; i++) {
if (parentDiv[i].className == "content") {
alert(parentDiv[i].offsetWidth);
alert(parentDiv[i].offsetLeft);
}
The width is calcuated as 1010 which is fine but i am just missing left positioning which i am getting using parentDiv[i].offsetLeft is 2.
Above the screenshot has width 1010 which is fine but left positioning is not correct.
i had this code to calculate the width.
function ReadDivPos(selector) {
var _divPos = "";
$(selector).each(function() {
var p = $(this).offset();
var w = $(this).width();
console.log("Top " + p.top) //top
console.log("left " + p.left) //left
console.log("right " + p.left + w) //right
console.log("offsetWidth " + w); //width
_divPos += "Left " + p.left + ",Width " + w + ",Avail Width " + window.screen.availWidth + ",Right " + (p.left + w) + "\\n";
});
return _divPos;
}
console.log(ReadDivPos(".content"));
when i am using the same code to calculate the positioning then it is not working .
var parentDoc = window;
while (parentDoc !== parentDoc.parent) {
parentDoc = parentDoc.parent;
}
parentDoc = parentDoc.document;
var parentDiv = parentDoc.getElementsByTagName('div');
var divs = [];
for (var i = 0; i < parentDiv.length; i++) {
if (parentDiv[i].className == "content") {
$(parentDiv[i]).each(function() {
var p = $(this).offset();
var w = $(this).width();
console.log("Top " + p.top) //top
console.log("left " + p.left) //left
console.log("right " + p.left + w) //right
console.log("offsetWidth " + w); //width
_divPos += "Left " + p.left + ",Width " + w + ",Avail Width " + window.screen.availWidth + ",Right " + (p.left + w) + "\\n";
}
}
Can someone me explain me how to fix this. Jquery/Javascript anythingwould be fine. I am not good in the frontend things so i am sorry if i could not explain it better. Thanks in advance
Here is a function used to get the position on the page of an element:
function getPosition(element) {
var xPosition = 0;
var yPosition = 0;
while (element) {
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
Used like this:
var pos = getPosition(element);
var x = pos["x"];
var y = pos["y"];
I'm not sure if this is exactly what you need, but if not maybe you can tweak it to fit your situation
got the following problem. i need the following just to be drag/dropable in the green area.
should be something like that:
limit($(this).parent());
but thats not working, im using this for dnd:
$('#dragThis').draggable({
drag: function () {
var offset = $(this).offset();
var xPos = Math.abs(offset.left);
var yPos = Math.abs(offset.top);
$('#posX').val('x: ' + xPos);
$('#posY').val('y: ' + yPos);
},
stop: function (event, ui) {
// Show dropped position.
var Stoppos = $(this).position();
var left = Math.abs(Stoppos.left);
var top = Math.abs(Stoppos.top);
$('#posX').val('x: ' + left);
$('#posY').val('y: ' + top);
}
});
hope someone can help me with that ;) thx so far
http://jsfiddle.net/DGbT3/1850/
///////////////
Update - getting correct x/y Position and just allow inside green area:
http://jsfiddle.net/DGbT3/1858/
You can use containment option for this which constrains dragging to within the bounds of the specified element or region.:
$('#dragThis').draggable({
drag: function() {
var offset = $(this).offset();
var xPos = Math.abs(offset.left);
var yPos = Math.abs(offset.top);
$('#posX').val('x: ' + xPos);
$('#posY').val('y: ' + yPos);
},
stop: function(event, ui) {
// Show dropped position.
var Stoppos = $(this).position();
var left = Math.abs(Stoppos.left);
var top = Math.abs(Stoppos.top);
$('#posX').val('x: ' + left);
$('#posY').val('y: ' + top);
$('#info').val('x: ' + left + ' y: ' + top);
},
containment: $("#content")
});
Example
If you want to get the position according to its parent then use .position(), then check if the xPos and yPos are bigger than 0 and smaller that its parent's width..
$('#dragThis').draggable({
drag: function() {
var offset = $(this).position();
var xPos = offset.left;
var yPos = offset.top;
$('#posX').val('x: ' + xPos);
$('#posY').val('y: ' + yPos);
if(xPos < 0 || xPos > $(this).parent().width())
console.log("outside");
},
stop: function(event, ui) {
// Show dropped position.
var Stoppos = $(this).position();
var left = Stoppos.left;
var top = Stoppos.top;
$('#posX').val('left: ' + left);
$('#posY').val('top: ' + top);
if(xPos < 0 || xPos > $(this).parent().width())
console.log("outside");
}
});
NOTE: there is a typo in your #content css position..
Ok, so I am trying to use jQuery to get the innerWidth() of an element #preview. I want to create a conditional that says IF x offset LEFT + #preview width is greater than page width, give it style right: z where z = #preview width + xOffset.
I apologize my code below is a mess and the syntax for .css ("right", (rightFloat + xOffset) + "px") (line 125) is off, but that's part of my problem.
<script>
$(document).ready(function(){
//append "gallery" class to all items with "popup" class
imagePreview();
$(".popup").addClass("gallery");
});
//The overlay or pop-up effect
this.imagePreview = function() { /* CONFIG */
xOffset = 40;
yOffset = 40;
// these 2 variable determine popup's distance from the cursor
// you might want to adjust to get the right result
/* END CONFIG */
$("a.preview").click(function(e) {
return false;
});
$("a.preview").hover(function(e) {
this.t = this.title;
this.title = "";
var c = (this.t != "") ? "<br/>" + this.t : "";
var rightFloat = e.pageX + ("#preview").innerWidth;
$("body").append("<p id='preview'><img src='" + this.href + "' alt='Image preview' />" + c + "</p>");
$("#preview").hide().css("top", (e.pageY - yOffset) + "px").css("left", (e.pageX + xOffset) + "px").fadeIn("2000");
while ((left + 400) > window.innerWidth) {.css("right", (rightFloat + xOffset) + "px")
}
}, function() {
this.title = this.t;
$("#preview").remove();
});
$("a.preview").mousemove(function(e) {
var top = e.pageY - yOffset;
var left = e.pageX + xOffset;
var rightFloat = e.pageX + ("#preview").innerWidth;
//flips the image if it gets too close to the right side
while ((left + 400) > window.innerWidth) {.css("right", +(rightFlaot + xOffset) + "px")
}
$("#preview").css("top", top + "px").css("left", left + "px");
});
};
</script>
Try using http://api.jquery.com/offset/
if($('#preview').offset().right<0){
var right = parseInt($(window).width()) - e.pageX + xOffset;
$("#preview").css("top", top + "px").css("right", right + "px");
}else{
var left = e.pageX + xOffset;
$("#preview").css("top", top + "px").css("left", left + "px");
}
I made these fixes because I couldn't get your code to work in jsfiddle:
var xOffset = 40;
var yOffset = 40;
$("a.preview").bind('mouseover',function(e){
var rightFloat = parseFloat(e.pageX)+$("#preview").innerWidth();
var ptop = parseFloat(e.pageY) - yOffset;
var pleft = parseFloat(e.pageX) + xOffset;
$("#preview").css({"top":ptop + "px","left":pleft + "px"});
});
There's the fixes for the top half but I have no idea what you're trying to do with the bottom part (with the while loop). Can you explain what functionality you want?