Using either pure Javascript or jQuery, how do I scroll the page so that the nth row in a table is centered on the page?
Some examples I've seen that have this sort of feature usually require that the element I scroll to uses an id as the selector, but since the table has a dynamic amount of rows and may be paged, I'd rather not go this route of having to give each <td> tag an id.
Is the easiest way to just calculate the position of the td relative to the top of the document and scroll the window using setInterval until the middle of the window is >= to the position of the nth <td> tag?
I suppose some pseudo-code of the way I imagine it working would be:
function scrollToNthTD(i) {
var position = CalculatePositionOfTR(i);
var timer = setTimeout(function () {
ScrollDownALittle();
if( CenterOfVerticalWindowPosition > position)
clearInterval(timer);
}, 100);
}
Latest update (no-jquery for for modern browsers)
var rows = document.querySelectorAll('#tableid tr');
// line is zero-based
// line is the row number that you want to see into view after scroll
rows[line].scrollIntoView({
behavior: 'smooth',
block: 'center'
});
Demo at http://jsfiddle.net/r753v2ky/
Since you can use jQuery here it is..
var w = $(window);
var row = $('#tableid').find('tr').eq( line );
if (row.length){
w.scrollTop( row.offset().top - (w.height()/2) );
}
Demo at http://jsfiddle.net/SZKJh/
If you want it to animate instead of just going there use
var w = $(window);
var row = $('#tableid').find('tr').eq( line );
if (row.length){
$('html,body').animate({scrollTop: row.offset().top - (w.height()/2)}, 1000 );
}
Demo at http://jsfiddle.net/SZKJh/1/
Don't use jQuery - it slows down sites!
var elem = document.getElementById("elem_id");
elem.scrollIntoView(true);
You can do something like this
function CalculatePositionOfTR(){
return $('tr:eq(' + i + ')').offset().top;
}
function ScrollDownALittle(position){
$('html, body').animate({
scrollTop: position
}, 2000);
}
function scrollToNthTD(i) {
var position = CalculatePositionOfTD(i);
var timer = setTimeout(function () {
ScrollDownALittle(position);
if( CenterOfVerticalWindowPosition > position)
clearInterval(timer);
}, 100);
}
Give this a shot:
/*pseudo-code*/
$("td.class").bind("click", function() {
var y = $(this).position().top,
h = $(window).height();
if(y > h/2) {
$("body").animate({
scrollTop: y - h/2
}, 2000);
};
});
aka-g-petrioli
I have corrected the followings from your answer.
$('#control button').click(function(){
var w = $(window);
var row = table.find('tr')
.removeClass('active')
.eq( +$('#line').val() )
.addClass('active');
if (row.length){
w.scrollTop( row.offset().top - row.offset().top/5);
}
});
This will help you to scroll accurate position.
Related
The below function mostly works - it moves the backgrounds as I need, however I would like the function to run on any element with a class of "animate", rather than having to call each element down the bottom. I tried $('.animate').load(function(){}; but it just wont work... Thanks
JAVASCRIPT
$(window).load(function(){
(function(){
$.fn.move = function(){
var $this = $(this);
var offset = $this.offset().top;
var start = 0;
var end = offset + $this.height();
var speed = $this.attr("speed");
return this.each(function(){
$(window).bind('scroll', function() {
var windowPos = $(window).scrollTop();
if((windowPos >= start) && (windowPos <= end)) {
var newCoord = windowPos * speed;
$this.css({'background-position': '0 '+ newCoord + 'px'});
};
});
});
};
})(jQuery);
$('.animate').move();
});
HTML
<div class="welcome_6"></div>
<div class="welcome_5"></div>
<div class="welcome_4"></div>
<div class="welcome_3"></div>
<div class="welcome_2 animate" speed="-1"></div>
<div class="welcome_1 animate" speed="0"></div>
EDIT:
When I scroll the page the elements move according to the scroll location. Each element moves at a different speed (set as html attribute). This code moves them all at the same speed.. I'm assuming the $('.animate') should be somewhere up the top replacing the $.fn.move but i cant figure it out..
Should be $('.animate') instead of $('animate') note the dot at the start of the query which says to the jQuery that you are looking for a class.
I think the issue is with the way you are using the immediately invoked function inside the load function and you are passing in jQuery at the bottom and not into the immediately invoke function. This will update the background position as long as you script tag is placed after the jquery script tag
Here is a link to js fiddle:
UPDATE: https://jsfiddle.net/kriscoulson/pnrx34wp/1/
I do not have your exact code for styling so I improvised but if you inspect the elements the background position is being updated;
AND UPDATE :
$.fn.move = function() {
var $this = $(this);
var offset = $this.offset().top;
var start = 0;
var end = offset + $this.height();
return this.each(function(index, element) {
var $element = $(element);
var speed = $element.attr("speed");
$(window).bind('scroll', function() {
var windowPos = $(window).scrollTop();
if ((windowPos >= start) && (windowPos <= end)) {
var newCoord = windowPos * speed;
$element.css({
'background-position': '0 ' + newCoord + 'px'
});
};
});
});
};
$(document).ready(function() {
$('.animate').move();
});
EDIT: Your 'this' binding was off and your speed was declared outside of the this.each
I've read a bunch of threads but still can't come away with a solution that doesn't use a snap scroll plugin (https://github.com/wtm/jquery.snapscroll).
I was trying to follow this
function scrollTo(a){
//Get current scroll position
var current = (document.all ? document.scrollTop : window.pageYOffset);
//Define variables for data collection
var target = undefined;
var targetpos = undefined;
var dif = 0;
//check each selected element to see witch is closest
$(a).each(function(){
//Save the position of the element to avoid repeated property lookup
var t = $(this).position().top;
//check if there is an element to check against
if (target != undefined){
//save the difference between the current element's position and the current scroll position to avoid repeated calculations
var tdif = Math.abs(current - t);
//check if its closer than the selected element
if(tdif < dif){
//set the current element to be selected
target = this;
targetpos = t;
dif = tdif;
}
} else {
//set the current element to be selected
target = this;
targetpos = t;
dif = Math.abs(current - t);
}
});
//check if an element has been selected
if (target != undefined){
//animate scroll to the elements position
$('html,body').animate({scrollTop: targetpos}, 2000);
}
}
I'm trying to get it to scroll into view
<div class="projectWrap">
Fiddle: http://jsfiddle.net/Dar_T/2h2wjp2L/1/
much like how this site http://www.takumitaniguchi.com/tokyoblue/ has it scroll for its containers.
First you have to find the offset() of the element. Then comparing it to the $(window.scrollTop()), then you can do whatever changes you want. Here's some of the codes:
var project1 = $(".projectWrap").offset();
if($(window).scrollTop() >= project1.top){ // compare window scrolltop to element offset()
$("#tlos1").css("color","blue"); // change navigation
$("#tlos2").css("color","black");
$("#tlos3").css("color","black");
}
Here's the DEMO
Try this out:
var topoffset = 30;
function goTo(tagId) {
var destination = $( '#'+tagId ).offset().top - topoffset;
$("html:not(:animated),body:not(:animated)").animate( { scrollTop: destination}, speed);
});
And create urls with hash like this:
Go to section1
I am creating a splitscrolling website and it's working great. But i have one problem, when the user stops scrolling it fires a function called alignWhenIdle and what this does is align the columns so they become "one".
Now that is working nicely but i can't seem to target a specific part of the column that aligns. let's say when the number 2 column aligns ( see image ) i want to be able to fire an animation. I tried using a callback but that fires a function every time the columns are aligned.
This is my JS:
(function ($) {
var top = 0;
var contentHeight, contents, totalHeight;
var locked = false;
var timeout;
var align = function () {
var pos = (top + $(window).scrollTop());
var snapUp = 0 - (pos % contentHeight) < (contentHeight / 2);
var multiplier = snapUp
? Math.ceil(pos / contentHeight)
: Math.floor(pos / contentHeight);
var newTop = contentHeight * multiplier;
$('html, body').animate({ scrollTop: newTop + totalHeight }, 200);
locked = false;
};
var reset = function () {
contentHeight = $('.right').height();
contents = $('.right > .content').length;
totalHeight = contentHeight * (contents - 1);
top = (0 - totalHeight);
};
var scrollRight = function () {
$('.right').css('top', (top + $(window).scrollTop()) + 'px');
};
var alignWhenIdle = function (delay) {
clearTimeout(timeout);
timeout = setTimeout(align, delay);
};
$(document).on('ready', function () {
reset();
scrollRight();
});
$(window).on('scroll', function () {
locked = true;
scrollRight();
});
$(window).on('mouseup', function (e) {
if (locked) {
align();
}
});
$(window).resize(function () {
locked = true;
reset();
scrollRight();
alignWhenIdle(300);
});
$(window).on('mousewheel', function (e) {
alignWhenIdle(300);
});
$(window).on("keyup", function (e) {
alignWhenIdle(300);
});
})(jQuery);
http://jsfiddle.net/ev3B8/
Any help is much appreciated,
Cheers
See http://jsfiddle.net/5T9Y8/
Scroll till the column 2 and see result...
In the method align I've added a callback:
$('html, body').animate({ scrollTop: newTop + totalHeight }, 200, function(){
$(".animate").animate({ marginLeft: "200px" },300);
});
Works well, did you need exactly that?
EDIT
You should just check for some condition.
E.g. based on this solution Check if element is visible after scrolling you can build this:
$('html, body').animate({ scrollTop: newTop + totalHeight }, 200, function(){
if (isScrolledIntoView(".animate")) $(".animate").animate({ marginLeft: "200px" },300);
});
See updated solution here http://jsfiddle.net/5T9Y8/1/
This is only one way, I'm really sure there is a way to do it even better. E.g. you can calculate the current elements which are shown and then just find the things only inside of them.
I tried using a callback but that fires a function every time the columns are aligned.
Use one method for functioning only once instead of on.
What is the equivalent of this:
$('html, body').animate({
scrollTop: 200
}, 400);
In MooTools or agnostic javascript?
Im going round in circles....
Cheers
This loop can animate the scrollTop property of the window in basic javascript:
window.onload = function() {
var offset = 0; //vertical offset
var interval = setInterval(function() {
window.scrollTo(0, offset);
offset += 4; // plus 4 pixels
if (offset >= 200) {
clearInterval(interval);
}
}, 8); // 200px/4px==50 cycles ; 400ms/50cycles == 8ms per cycle
};
fiddle
Because you asked for a version in mootools, it's just one line:
new Fx.Scroll(window).start(0, 200);
http://jsfiddle.net/ye3vX/
Note: It needs mootools more's Fx.Scroll.
How I can move DOM elements slowly?
This does not work
for ( var a = 0 ; a < 100 ; a++){
$('*').each(function(){
if ( ! /HTML/.test($(this).context.nodeName))
{
var top = parseInt($(this).css('top')) + 1;
$(this).css('top',top + "px");
}
});
}
Elements are positioned when the loop finish
How can I do this slowly?
Sorry for my English
Or in pure javascript, you should use a timer
var $elem = $(this), // jquery object
elem = $elem[0], // dom element
currentPos = $elem.offset().top, // current position
targetPos = currentPosition + 100, // target position
timer = setInterval (function () { // timer to move element slowly
currentPos++;
$elem.css('top',currentPosition + "px");
if (currentPos == targetPos)
clearInterval(timer);
}, 100);
try jquery's $.animate()
it requires you to set a target position to move to, rather than continuous movement
or using setInterval:
intervalInMilliseconds=17;//60 frames per second
var interval = setInterval(function()
{
for ( var a = 0 ; a < 100 ; a++){
$('*').each(function(){
if ( ! /HTML/.test($(this).context.nodeName))
{
var top = parseInt($(this).css('top')) + 1;
$(this).css('top',top + "px");
}
});
}
},intervalInMilliseconds);
stop when you're done by doing this:
clearInterval(interval)
If you are targetting new enough browser versions, you could use CSS animation instead.