I have the following js which is basically to find the x and y origin of the top left of the tag. This however, doesn't always work, for some reason, and some times it work. Not sure why, but some of the offsetLeft and offsetTop are 0. Do you have any other alternative to this?
function f() {
var el = document.elementFromPoint(%f, %f);
var pos = [el.offsetLeft, el.offsetTop];
var parent = el.offsetParent;
if (parent != el) {
while (parent) {
pos[0] += parent.offsetLeft;
pos[1] += parent.offsetTop;
parent = parent.offsetParent;
}
}
return pos.toString();
} f();
I am also trying to get the width and height of the image by doing element.clientWidth and element.clientHeight. Why is this giving me 0 as well?
First Problem, I think you missed the offset of the node itself.
This function I wrote I use often.
Try it out and tell me the scenario where it doesn't work...
/**
* Returns an Object with an x and an y value giving the current top and
* left of the DOM element.
*
* #param {HTMLElement}
* element
* #return
* #type Object
*/
function getElementPosition(node) {
try {
var xy = {
x : 0,
y : 0
};
var parent = node.offsetParent;
while (parent) {
xy.x += parent.offsetLeft;
xy.y += parent.offsetTop;
parent = parent.offsetParent;
}
xy.x += node.offsetLeft;
xy.y += node.offsetTop;
return xy;
} catch (e) {
console.error("getElementPosition(", arguments, ") >", e);
}
}
I'm not exactly sure what you are trying to do but I think you might want to look into getBoundingClientRect()
EDIT this gets the position relative to the viewport to you need to control for scrolling. EG:
myDiv.getBoundingClientRect().top + window.scrollY
myDiv.getBoundingClientRect().left + window.scrollX
more here: https://developer.mozilla.org/en/DOM/element.getBoundingClientRect
Related
So I want to add a class on a specific screen height. So I've done:
window.onscroll = function() {scrollPost()};
function scrollPost () {
var x = window.screen.width;
var i = window.scrollY;
var a = i / x;
animator (a);
slide(a);
}
function slide(x){
var a = (x * 100);
var i = Math.round(a);
console.log(i);
var slideIn = document.querySelector(".slide-in-right");
var slideOut = document.querySelector(".slide-out-left");
if (i >= 90){
slideOut.classList.add("animate");
slideIn.classList.add("animate");
slideIn.style.display = ("block");
}
The problem however. Is that on different screens, the value will be different. Thus therefore on different screens it will toggle at a different time. I could probably make ifstatements, based on screen width. But then I'd need a whole lot of them.
I want the animation to be added only after the container is 100% in the screen height. How would you do this?
You are going to have to get users viewport (window height).
Divide it by half
Add it towards your IF position.
I wrote a simular answer, how ever it was written jQuery, if you are considering it would be a better output.
How to trigger a class that is only in view with wapoints
However to implement that to plain js:
Get user screen height:
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
x = w.innerWidth || e.clientWidth || g.clientWidth,
y = w.innerHeight|| e.clientHeight|| g.clientHeight;
alert(x + ' × ' + y);
divide y by half, and then add to your current position that checks if element is scrolled.
I will add this just in case. To get element position.
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 };
}
Source: How to get the distance from the top for an element?
I am looking for a way to implement the exact functionality from this answer using angularjs: Specifically, for a box (div) to move randomly around a screen, while being animated. Currently I have tried
myApp.directive("ngSlider", function($window) {
return {
link: function(scope, element, attrs){
var animateDiv = function(newq) {
var oldRect = element.getBoundingClientRect();
var oldq = [oldRect.top, oldRect.left];
if (oldq != newq){
var dir = calcDir([oldq.top, oldq.left], newq);
element.moveTo(oldq.left + dir[0], oldq.top + dir[1]);
setTimeout(animateDiv(newq), 100);
}
};
var makeNewPosition = function() {
// Get viewport dimensions (remove the dimension of the div)
var window = angular.element($window);
var h = window.height() - 50;
var w = window.width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
};
function calcDir(prev, next) {
var x = prev[1] - next[1];
var y = prev[0] - next[0];
var norm = Math.sqrt(x * x + y * y);
return [x/norm, y/norm];
}
var newq = makeNewPosition();
animateDiv(newq);
}
};
});
There appears to be quite a bit wrong with this, from an angular point of view. Any help is appreciated.
I like to take advantage of CSS in situations like this.
absolutely position your div
use ng-style to bind top and left attributes to some in-scope variable
randomly change the top and left attributes of this in-scope variable
use CSS transitions on top and left attributes to animate it for you
I made a plnkr! Visit Kentucky!
This isn't so much a jQuery question as it is an overall conceptual question.
In my example I can populate a container with divs that have a top value set in a nonlinear fashion.
The top value of each one is calculated based on a formula that takes into account the top position of the one to its left as well as the height of the container (line 33 of fiddle).
//this formula sets the top value for each new child added to the container
//height is 100% of its parent which is 20% of the body
//newOne:last is the most recently added child and will have an initial top value of 10%
parseInt($(this).next().css('top'), 10) / $('#queue').height()) * 75 + (parseInt($('.newOne:last').css('top'), 10) * 2) + '%'
I more of less stumbled upon this by chance and it seems to work 'ok', but if an optimization is obvious to you, please point it out :)
What I'm having trouble coming up with is an elegant formula for how to adjust the children smoothly during a drag event. I'm thinking the top value needs to be adjusted based on some manipulation of the left offset, but after hours of experimenting, I haven't found anything that keeps the original position intact when I start dragging and continues adjusting the values smoothly during my drag. The children should gradually approach a minimum top value of 10% as I drag left (child with left offset of 0 will have a top value of 10%), and gradually move away from that top value back toward their initial position as I drag right.
$('#queue').draggable({
axis: "x",
scroll: false,
drag: function(){
//adjust values of each child
$('.newOne').each(function(){
var percentLeft = $(this).offset().left / $('footer').width() * 100
var thisLeft = parseInt($(this).css('left'), 10) / $(window).width() * 100;
var thisTop = parseInt($(this).css('top'), 10) / $('#queue').height() * 100;
if (percentLeft >= 0){
//top value of each one gradually decreases...
//as it gets closer to an offset value of 0 and minimum top value of 10%
//non-linear attempt but not even close
//$(this).css('top', $(this).css('top', 10 + (thisTop - 10 / thisLeft) + '%'));
//linear step
$(this).css({'top': 8 + (percentLeft/2) + '%'});
}
});
}
});
http://jsfiddle.net/5RRCS/17/
P.S. I know I'm asking a lot here, but hopefully someone is up to the challenge :)
Update:
Stumbled onto exp method and did something like this:
adjustTop = function(offset){
return 100 * (1.0-Math.min(0.98,(0.83 + ( 0.17/ (Math.exp(0.007*offset))) )) ) + '%';
};
$(this).css('top', adjustTop($(this).offset().left) );
Here's a version that I believe does what you are looking for.
The first thing I did was to refactor the top calculation so that both the initialization and the drag handlers would get the same results.
Rather than calculate the positions of the child divs based on their offset to the document, I changed the logic to use position relative to their container.
I also remove z-index as the child divs already being added the parent with the correct stacking order - the left most child is the last element in the container.
Calculating the height of each child depended on whether #queue's current position was to the left or right of its origin.
I also change the iteration logic to behave the same to simplify calculating the current elements starting offset:
$($('.newOne').get().reverse()).each(function (index) {
$(this).css({
'background': 'rgba(255,255,255,.80)',
'top': calcTop($(this), index)
});
});
Code for positioning the child elements:
function calcTop($ele, index) {
var elePositionLeft = $ele.position().left;
var queuePositionLeft = $('#queue').position().left;
var footerWidth = $('footer').width();
var queueHeight = $('#queue').height();
var distanceToTravel = queuePositionLeft < 0 ? elePositionLeft : footerWidth - elePositionLeft;
var percentTraveled = Math.abs(queuePositionLeft) / distanceToTravel;
var thisPercentLeft = (elePositionLeft + queuePositionLeft) / footerWidth;
var queuePercentLeft = queuePositionLeft / footerWidth;
var newTop;
var myStartOffset = (index + 1) * startOffset;
var topTravel = queuePositionLeft < 0 ? -myStartOffset + startOffset : (queueHeight - startOffset);
var linear = false;
if (linear) {
newTop = myStartOffset + (topTravel * percentTraveled);
newTop = newTop > startOffset ? Math.round(newTop) : startOffset;
return newTop;
} else {
if (queuePositionLeft >= 0) {
newTop = myStartOffset + (topTravel * thisPercentLeft * percentTraveled);
newTop = newTop > startOffset ? Math.round(newTop) : startOffset;
} else {
newTop = myStartOffset + (topTravel * (1+thisPercentLeft) * percentTraveled);
newTop = newTop < startOffset ? startOffset : Math.round(newTop);
}
return newTop;
}
}
There was also a minor bug in the reset function - it wasn't setting childCount back to zero:
$('#reset').click(function () {
$('#queue').empty().css('left', 0);
childCount = 0;
});
Demo Fiddle
Say I have a wrapper div with a overflow:hidden on it and a div inside that that spans far below the visible portion. How can I get the visible height of the internal div?
<div id="wrapper" style="overflow: hidden; height:400px;">
<div id="inner">
<!--Lots of content in here-->
</div>
<div>
Every method I try attempting to get the height of the inner div returns the complete height including the hidden parts, i.e. 2000px. I want to be able to get the height of only the visible portion, so 400px in this example case.
I know I could just get the height of the parentNode, but in production, the inner div might not be a first child. So there might be other divs separating them, and so the height of #inner would be 400 - whatever the offsets of the elements between it and #wrapper.
As basic algorithm this could work:
var offset = 0;
var node = document.getElementById("inner");
while (node.offsetParent && node.offsetParent.id != "wrapper")
{
offset += node.offsetTop;
node = node.offsetParent;
}
var visible = node.offsetHeight - offset;
But if you're doing these kinds of things, maybe you already use jQuery, which might be of service with its .height() and .offset() functions:
$("#wrapper").height()-
$("#inner").offset()['top']+
$("#wrapper").offset()['top'];
Quick algorithm that goes up the DOM tree looking at window.getComputedStyle for overflow: hidden
function visibleArea(node){
var o = {height: node.offsetHeight, width: node.offsetWidth}, // size
d = {y: (node.offsetTop || 0), x: (node.offsetLeft || 0), node: node.offsetParent}, // position
css, y, x;
while( null !== (node = node.parentNode) ){ // loop up through DOM
css = window.getComputedStyle(node);
if( css && css.overflow === 'hidden' ){ // if has style && overflow
y = node.offsetHeight - d.y; // calculate visible y
x = node.offsetWidth - d.x; // and x
if( node !== d.node ){
y = y + (node.offsetTop || 0); // using || 0 in case it doesn't have an offsetParent
x = x + (node.offsetLeft || 0);
}
if( y < o.height ) {
if( y < 0 ) o.height = 0;
else o.height = y;
}
if( x < o.width ) {
if( x < 0 ) o.width = 0;
else o.width = x;
}
return o; // return (modify if you want to loop up again)
}
if( node === d.node ){ // update offsets
d.y = d.y + (node.offsetTop || 0);
d.x = d.x + (node.offsetLeft || 0);
d.node = node.offsetParent;
}
}
return o; // return if no hidden
}
example fiddle (look at your console).
The only way I've found to do this in every circumstance, including when there's overflow, transform: translate()s are used, and there are other nested containers in between an element and the element that's hiding its overflow is to combine .getBoundingClientRect() with a reference to the ancestor that's hiding the element's overflow:
function getVisibleDimensions(node, referenceNode) {
referenceNode = referenceNode || node.parentNode;
var pos = node.getBoundingClientRect();
var referencePos = referenceNode.getBoundingClientRect();
return {
"width": Math.min(
node.clientWidth,
referencePos.left + referenceNode.clientWidth - pos.left,
node.clientWidth - (referencePos.left - pos.left)
),
"height": Math.min(
node.clientHeight,
referencePos.top + referenceNode.clientHeight - pos.top,
node.clientHeight - (referencePos.top - pos.top)
)
}
}
Demo.
If a reference node is not given, the parent node is assumed: Demo.
Note that this doesn't take into account whether or not an element is viewable in the viewport, just visible (not hidden due to overflow). If you need both, you can combine functionality with this answer. It also has no check of visibility: hidden, so if you need that you need to check the style.visibility property of the node and all its ancestors.
I think keeping a sibling next to it, calculating its scrollTop and the overflow element scrollTop and then subtracting it from the siblings scroolTop might work
The code below computes the visible portion of an element. By visible portion I mean the part that is visible in the window, but I think you can easily alter it to base the computation on an arbitrary container element.
function computeVisibleHeight ($t) {
var top = $t.position().top;
var windowHeight = $(window).height();
var scrollTop = $(window).scrollTop();
var height = $t.height();
if (top < scrollTop && height - scrollTop >= windowHeight) {
// first case: the top and the bottom of the element is outside of the window
return windowHeight;
} else if (top < scrollTop) {
// second: the top is outside of the viewport but the bottom is visible
return height - (scrollTop - top);
} else if (top > scrollTop && top + height < windowHeight) {
// the whole element is visible
return height;
} else {
// the top is visible but the bottom is outside of the viewport
return windowHeight - (top - scrollTop);
}
}
The code is using jquery.
How do I determine the distance between the very top of a div to the top of the current screen? I just want the pixel distance to the top of the current screen, not the top of the document. I've tried a few things like .offset() and .offsetHeight, but I just can't wrap my brain around it. Thanks!
You can use .offset() to get the offset compared to the document element and then use the scrollTop property of the window element to find how far down the page the user has scrolled:
var scrollTop = $(window).scrollTop(),
elementOffset = $('#my-element').offset().top,
distance = (elementOffset - scrollTop);
The distance variable now holds the distance from the top of the #my-element element and the top-fold.
Here is a demo: http://jsfiddle.net/Rxs2m/
Note that negative values mean that the element is above the top-fold.
Vanilla:
window.addEventListener('scroll', function(ev) {
var someDiv = document.getElementById('someDiv');
var distanceToTop = someDiv.getBoundingClientRect().top;
console.log(distanceToTop);
});
Open your browser console and scroll your page to see the distance.
This can be achieved purely with JavaScript.
I see the answer I wanted to write has been answered by lynx in comments to the question.
But I'm going to write answer anyway because just like me, people sometimes forget to read the comments.
So, if you just want to get an element's distance (in Pixels) from the top of your screen window, here is what you need to do:
// Fetch the element
var el = document.getElementById("someElement");
use getBoundingClientRect()
// Use the 'top' property of 'getBoundingClientRect()' to get the distance from top
var distanceFromTop = el.getBoundingClientRect().top;
Thats it!
Hope this helps someone :)
I used this:
myElement = document.getElemenById("xyz");
Get_Offset_From_Start ( myElement ); // returns positions from website's start position
Get_Offset_From_CurrentView ( myElement ); // returns positions from current scrolled view's TOP and LEFT
code:
function Get_Offset_From_Start (object, offset) {
offset = offset || {x : 0, y : 0};
offset.x += object.offsetLeft; offset.y += object.offsetTop;
if(object.offsetParent) {
offset = Get_Offset_From_Start (object.offsetParent, offset);
}
return offset;
}
function Get_Offset_From_CurrentView (myElement) {
if (!myElement) return;
var offset = Get_Offset_From_Start (myElement);
var scrolled = GetScrolled (myElement.parentNode);
var posX = offset.x - scrolled.x; var posY = offset.y - scrolled.y;
return {lefttt: posX , toppp: posY };
}
//helper
function GetScrolled (object, scrolled) {
scrolled = scrolled || {x : 0, y : 0};
scrolled.x += object.scrollLeft; scrolled.y += object.scrollTop;
if (object.tagName.toLowerCase () != "html" && object.parentNode) { scrolled=GetScrolled (object.parentNode, scrolled); }
return scrolled;
}
/*
// live monitoring
window.addEventListener('scroll', function (evt) {
var Positionsss = Get_Offset_From_CurrentView(myElement);
console.log(Positionsss);
});
*/
I used this function to detect if the element is visible in view port
Code:
const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
$(window).scroll(function(){
var scrollTop = $(window).scrollTop(),
elementOffset = $('.for-scroll').offset().top,
distance = (elementOffset - scrollTop);
if(distance < vh){
console.log('in view');
}
else{
console.log('not in view');
}
});