jQuery .scrollTop() not scrolling to li elements as expected - javascript

I essentially have an unordered list of list items in a div that doesn't scroll to the next element properly. I'm just trying to have a button to scroll up and down the list.
While the code does scroll, it doesn't match up with the li elements. After every click, it scrolls up a little bit, then down on the next click. I've tried walking the DOM and verifying the element it is scrolling to is an li element, but didn't see the issue.
I have the following jsfiddle:
http://jsfiddle.net/YD9s5/9/
The elements are:
A scrolling div with an id of photos-div
An unordered list with an id of photos-li (whoops, leaving it for now)
List items with incrementing ids of photo-li-X where X is a number
The code being used to scroll the div is:
$('#photos-div').scrollTop($('#photo-li-' + i).offset().top);
The i variable is being incremented, as you can see.

The problem is that .offset() gets the position of an element relative to the entire document, and that position is constantly moving up. So once you've scrolled to item 1, it returns the .offset().top that item 1 currently has in the document, which is now where item 0 used to be.
Add console.log( $('#photo-li-0').offset() ); to the top of your scrollToElement() function and you'll see what I mean. Notice that the top offset keeps decreasing, quickly moving into the negative numbers as it moves off the top of the document.
The fix is to take the difference between the offset of $('#photo-li-'+i) and $('#photo-li-0') (or the container $('#photos-li') itself) and scroll to that instead:
var newpos = $('#photo-li-' + i).offset().top - $('#photo-li-0').offset().top;
$('#photos-div').scrollTop(newpos);
http://jsfiddle.net/mblase75/x4hQP/ (incorporates other improvements)

It appears that .offset() only measures from the top of the document. You are interested in how far the element is from the top of #photos-div. Here's a working version where I track the position in the div manually. Notice in the console that when I log the value of .offset() it's relative to the document rather than the scrolling div.
Seems that there should be a way to do this without carrying the position of that div in state. Working on it...
Here's my more programatic solution.

Related

Move divs with mouseclick between div container

I would like to drag and drop divs within a container-div. Only up and down the list, using the mouse. How can I create this?
Searching the internet and stackoverflow didn't give me a good answer, since I would like to have it in vanilla Javascript and everything is nowadays in jQuery. :S
This is wat I have:
<div class="chapcontainer" data-chaporder="1000">
<div class="chapter">Big fire</div>
<div class="subchapter" data-chapid="1">Forest burning</div>
<div class="subchapter" data-chapid="2">Balu hoses</div>
<div class="subchapter" data-chapid="3">Forest animals die</div>
<div class="subchapter" data-chapid="4">Lovely fire</div>
</div>
</div>
The chapter-div is the container. Within this div I want to be able to move the subchapter-div with a click of the mousebutton up and down the list of subchapter-divs.
For example I move the subchapter-div with data-chapid 4 to the top, then it should be moved to the top and the data-chapid changed to 1. Is something like this possible in vanilla javascript?
I've read about AppendChild, but I don't know how I can trigger this with the mouse.
You could do it with jQuery:
$(".subchapter[data-chapid='1']").on("click", function() {
$(this).css('margin-left', '20px') // add margin/padding/etc here
})
Fiddle
Doing drag and drop yourself is complicated, but here are some of the basic steps. One advantage of rolling your own is you can do more advanced things than your standard jquery ui drag and drop can, like smooth scrolling the container, auto-opening nested tree items if the user hovers over them, or doing animations while moving items.
Steps:
Listen for mousedown events on your items in your container. When the user presses down on an item, store the mouse's offset relative to the top of container (this includes the scroll of the container). Also store the mouse's offset relative to the item being dragged.
Clone the element that's being dragged and absolute position it under the mouse, using the relative offset you stored in step 1.
Make the original element invisible.
Listen for mousemove events on your container. Reposition the dragged item appropriately.
As the mouse moves, you'll need to update the mouse's new offset from the top (including scroll) and figure out which item you're over. You can do this by getting the height of each item in your list. So if your mouse is 710 pixels from the top, and each item is 100 pixels high, you're over index 8. You can use this info to change the style of the item you're over to show that it's a drop target. One thing to watch out for is if you do any styling changes that change the heights of items, you'll need to recalculate your heights.
On mouseup, you already know which item you're over, so now you need to update your data array to move the dragged item, probably using array.splice. Delete the absolutely positioned dragged element, and rerender your list to reflect your changes. I'm assuming you're using some sort of templating library to render your stuff, or at least a render function that clears what's there and replaces it with the current state.

Parallax effect on an elements position only when in view

Similar to this unresolved question (jQuery - parallax - update background position correctly)
I am animating the transform property of an element on page scroll to achieve a parallax-like effect. I want this element to only begin animating up when it is in view. The problem now is that if the element appears further down the page, it has already moved up a lot and loses the effect.
Here is my code currently
function parallax() {
var scrolled = $(window).scrollTop();
$('[data-scroll]').css('transform', 'translateY('+-(scrolled*0.02)+'px)');
}
$(window).scroll(function(e){
parallax();
});
In answer to your question how to separate "parallax'ed" divs, so they shift their position independently from each other upon scrolling, one should rely on their unique coordinates - each one has it's own $(elem).offset().top - a general vertical offset from the top of the page (it's stays the same all the time unless you meddle with the TOP property manually).
so all calculation could be based against this property.
$('.parallax').each(function(){
if ($(this).is_on_screen()) {
var firstTop = $(this).offset().top;
var winScrollTop = $(window).scrollTop();
var shiftDistance = (firstTop - winScrollTop)*0.02;
$(this).css("transform":"translateY("+shiftDistance+"px)");
}
});
plus you check if the element is in the viewport. Thus, you assure it moves the same delta distance in its own time no matter where it's on the page - further down or up.
Another thing is that how to put "borders" of visibility of the element on the screen. If you are moving an element when it's in viewport, i would suggest making a wrapping div within which the movement occurs (like a bg moving within a div wrapper).
<div class="parallax-section slide1">
<span class="moving-block"></span>
</div>
div has a bigger height and we check when this div is on the screen, not the moving element.
demo
Also other modifications can be applied if one needs different speed, offset for each element. I found this plugin a good beginner stuff to learn parallax.
P.S. btw, all initial properties should be cached in variables instead of retrieving them each time in a callback, like firstTop for instance

Inside of a scrolling div, offset and position do not properly give dimensions in term of the top of the doc

I have a scrolling div, which has enough controls to scroll. Which all flow in a block display. when scrolling down, when i was to take a snapshot of all the elements, i was wanting to get the list of all the positions and print them out. The issue at hand is that when scrolling, things that are out of view (towards the top) have a neg. position.
I was looking at offset and Position, but they both arent giving me the numbers i was wanting.
How would i get the X:Y positions of all the children, from the top of the div? IE: [0,0], [0,20], [0,40] etc etc.
Is there another variable i am not making use of? some sort of scrollY or something which should be appended to adjust everything?
Edit: When dealing with scrollable divs, making use of: $.scrollTop gives the offset, which would need to be applied to all the children. when getting the position of all the items
If I'm understanding the question correctly, it sounds like you want scrollTop, i.e.
document.getElementById('div1').scrollTop;
...which you can get and set. If I've misudnderstood, perhaps you could create a jsfiddle?

Jquery Scrolling Element to Position of Newly Appended Element (Calculating relative offset to parent)

I've created a horizontal list of elements. The list has a fixed width and scrolls on overflow. When a button is clicked a new element is added to this list and I'm trying to scroll the ul element to this newly created li element.
Here's the JQuery I'm using:
var ul = $('ul')
$('button').click(function() {
var li = $('<li></li>');
ul.append(li);
ul.stop().animate({
scrollLeft: li.offset().left
}, 2000);
});
Oddly if you start tracing the variables li.offset().left stays pretty much the same value for the first few elements and the scrolling works fine until li.offset().left becomes less than ul.scrollLeft() max value.
You can see this here: http://jsfiddle.net/ePrwZ/16/
It appears what is going on is that li.offset().left is tracking the position relative to the document when I need it relative to the parent ul element. But I can't just minus the parent offest due to the overflow. Any idea on how to calculate this?
Note: I would like to scroll to the specific element not just to the end of the ul.
change to:
ul.stop().animate({
scrollLeft: li.position().left + ul.scrollLeft()
}, 2000);
You are looking for position() method, which returns relative position, instead of offset, which returns absolute (more proper - relative to the document) position, and add current scroll state (which affects the position reading)

Get item below another item in JavaScript

If you have a document full of absolute positioned items and you set a document click handler (document.onclick = handler). Is it possible to get all objects that share the mouse position? i.e. two div boxes overlapped, not only the top one
Use the following algorithm:
find out the x and y coordinates of mouse.
Use document.elementFromPoint, add returned element to array.
Hide that element using display:none
Go to 2 until returned element is document.body
Display all hidden elements.

Categories

Resources