I have this code:
function scroll() {
shouldScroll = chat.clientHeight === chat.scrollHeight;
if (!shouldScroll) {
scrollToBottom();
}
}
function scrollToBottom() {
chat.scrollTop = chat.scrollHeight;
}
scrollToBottom();
setInterval(scroll, 100);
In this code I have an automatically scroll but, When I want to see the whole conversation, he does not let me go up so I can read the conversations. It just keeps me down.
How can i fix this?
Thanks
Check if user has scrolled to another position using scrollTop or is near to the bottom by comparing to an offset:
var offset = 50; // if user is 50px far from bottom
var shouldScroll = false;
if (chat.scrollHeight - chat.scrollTop) < offset){
shouldScroll = true;
}
Related
I have written some javaScript so that my menu starts off as position: static but will become position: fixed and stay at the top of the screen whenever the user scrolls upwards but will disappear again whenever scrolling downwards. Because the menu has some content above it, once the user has scrolled to the very top, the menu becomes position: static again.
This code works ok but I am having a problem when adding debounce. I've read I need either throttling or debounce for performance. I have tried using both the Lodash _.debounce and _.throttle functions separately. I don't mind having some delay on the menu showing itself on scroll-up, but with a debounce the header has a delay when returning to position: static once the user has scrolled back to the top of the page. I have tried using the {'leading': true} option for the debounce and throttle function but it hasn't done much good.
If I set my wait/delay time too low, surely there is no point in even using debounce or throttle anymore? I do not want to sacrifice the performance of the site but have been asked to implement this effect.
var header = document.getElementById("fixed-header");
var offset = header.offsetTop;
var $header = $(header);
var headerHeight = parseInt($header.css("height"));
var total = headerHeight + offset;
var lastScrollTop = 0;
window.addEventListener("scroll", _.debounce(scrollHeader, 200, {
'leading': true
}));
function scrollHeader() {
var st = window.pageYOffset || document.documentElement.scrollTop;
if (st > lastScrollTop) {
// downscroll code
if (pageYOffset >= total) {
document.body.classList.add("fixed");
document.body.classList.add("is-hidden");
document.body.style.paddingTop = header.offsetHeight + "px";
header.style.transition = ".5s";
} else {
document.body.classList.remove("fixed");
document.body.classList.remove("is-hidden");
document.body.style.paddingTop = 0;
}
} else {
// upscroll code
if (pageYOffset >= offset) {
document.body.classList.add("fixed");
document.body.classList.remove("is-hidden");
document.body.style.paddingTop = header.offsetHeight + "px";
} else {
header.style.transition = "initial";
document.body.classList.remove("fixed");
document.body.style.paddingTop = 0;
}
}
lastScrollTop = st;
}
I have a function which basically runs when an arrow with the class 'downArrow' is click. The function will find the parent of that arrow then find the next sibling with a class of 'scrollPoint' and then scroll to that area. Everything I just described works fine for me the issue I am having is if the bottom of the document hits the bottom of my viewport before the top of the element I am scrolling to hits the top of the viewport it just glitches out and scrolls back to the very top of the document. So I think What I need to do is detect if this scenario is going to happen and then set a max scroll value so the scroll functions doesnt try to scroll passed the bottom of the document.
How would I detect if the bottom of the document will be visible on the viewport and prevent from scrolling that far?
I will provide my code below in hopes that it will help, if you have any questions or need more clarification of what I am asking for just let me know. Thanks
This is my component although for what i am asking only the scrollTo function is really relevant
exports.init = init;
function init (options){
var downArrows = document.querySelectorAll(options.selector);
downArrows.forEach(triggerScrollHandler);
}
function scrollTo(element, to, duration) {
if (duration < 0) return;
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
setTimeout(function() {
element.scrollTop = element.scrollTop + perTick;
if (element.scrollTop === to) return;
scrollTo(element, to, duration - 10);
}, 10);
}
function scrollHandler (e) {
e.preventDefault();
var el = this,
scrollPoint = findSibling(el),
offsetVal = scrollPoint.getBoundingClientRect(),
windowOffset = window.pageYOffset;
offsetVal = offsetVal.top + windowOffset - 1;
scrollTo(document.body, offsetVal, 600);
}
function findParent(el) {
while (el && el.parentNode) {
el = el.parentNode;
if (el.tagName) {
return el;
}
}
return null;
}
function findSibling (el) {
var parent = findParent(el),
siblings = document.querySelectorAll('.scrollPoint'),
scrollTo;
siblings.forEach(function (currentSib, i) {
if(scrollTo == 'found'){
scrollTo = currentSib;
}
if(currentSib == parent){
scrollTo = 'found'
}
});
return scrollTo;
}
function triggerScrollHandler (el) {
el.addEventListener('click', scrollHandler);
}
And this is where I call in my app.js
var scrollHandler = require('./components/scrollHandler.js');
(function(){
scrollHandler.init({
selector: '.downArrow'
});
}())
Put this in your scroll listener:
if (document.body.scrollHeight <= document.body.scrollTop + document.body.clientHeight ){
console.log('scrolled to bottom');
}
Simple, pure JS solution :)
I have an absolutely positioned div that uses the jQuery .animate function to move horizontally from the right to left of the screen.
My problem is that once the div reaches the far left side, it continues and eventually disappears from the screen. How do you make it so that once the div reaches the left side, it will reverse and start going to the right? (and then vice versa so that the right side won't continue going right, but goes left again once it reaches the end)
HTML:
<div class="container">
<div class="block"></div>
</div>
CSS:
.block {
float:right;
position:absolute;
right:100px;
width:100px;
height:100px;
background:red;
}
jQuery:
$('.block').click(function() {
$(this).animate(
{"right": "+=100px"},"slow");
});
Here is my JSFiddle: https://jsfiddle.net/ebkc9dzL/
Thank you I really appreciate the help!
may be you should try like this:
$('.block').click(function() {
var leftPosition = $(this).position();
if (leftPosition.left > 100) {
$(this).animate({"right": "+=100px"},"slow");
} else {
$(this).animate({"right": "-=100px"},"slow");
}
});
when the element is close to the border the if..else part of the code will reverse the direction.
Here is a fiddle, try to click on the red box to get an idea on how it works:
https://jsfiddle.net/dimitrioglo/ebkc9dzL/14/
Working fiddle: https://jsfiddle.net/ebkc9dzL/19/
You need to have a variable outside the click function that will tell you the direction of the animation, so that once inside the click function you can calculate the location of the animated object using getBoundingClientRect() (mdn reference).
Then, if object is moving left and its left distance is less than its own width, you need to move it only enough so that it comes to the edge. If it's AT the edge (left is zero), you need to change the direction.
If it's moving right and its right distance is less than its own width, you need to move it only enough (calculated by window.innerWidth - 100, since 100 is width of your object) so that it comes to the edge. If it's AT the right edge, you need to change direction.
Changing direction in object you pass to jQuery's animate function is a simple matter of adding or subtracting from its "right" attribute.
var direction = "+";
$('.block').click(function() {
var obj = {},
distance = 100,
rect = this.getBoundingClientRect();
if(direction=="+"){
if(rect.left>0 && rect.left < 100)
distance = rect.left;
else if(rect.left<=0)
direction = "-";
}
else {
if(rect.right >(window.innerWidth-100) && rect.right+1<window.innerWidth)
distance = (window.innerWidth-rect.right);
else if(rect.right+1 >=window.innerWidth){
direction = "+";
}
}
obj = {"right": direction+"="+distance.toString()+"px"}
$(this).animate(obj,"slow");
});
Here you go: jsFiddle.
The new javascript is as follows:
var goLeft = true;
$('.block').click(function() {
var animateDist = 100;
var distLeft = $(this).position().left;
var distRight = window.innerWidth - distLeft;
if (goLeft) {
if (distLeft < 100) {
animateDist = "+="+distLeft+"px";
$(this).animate(
{"right": animateDist},"slow"
);
goLeft = false;
} else {
$(this).animate(
{"right": "+=100px"},"slow"
);
}
} else {
if (distRight < 100) {
animateDist = "-="+distRight+"px";
$(this).animate(
{"right": animateDist},"slow"
);
goLeft = true;
} else {
$(this).animate(
{"right": "-=100px"},"slow"
);
}
}
});
This isn't perfect, you need to adjust your internal window width to match the parent container, but this is enough to get you in the right direction.
Good luck!
Try this code:
var sign = [ "+" , "-" ];
var signPosition = 0;
var maxOffset = $(".block").offset().left;
$('.block').click(function() {
if ($(this).offset().left < 100) {
signPosition = 1;
} else if ($(this).offset().left == maxOffset) {
signPosition = 0;
}
$(this).animate(
{"right": sign[signPosition] + "=100px"},"slow");
});
The variable sign is the array that contains the directions in which the element might move, the variable signPosition contains the position of the direction currently in use, the variable maxOffset contains the starting position.
Hope this will help you.
I am looking for a way to only scroll horizontal OR vertical inside a html table view while maintaining a header and row that is always visible. Preferably I would like something similar to this but in pure Javascript without ember or coffeescript. I prefer not to use the ember-table because the rest of my project is not based on ember and I am unfamiliar with it.
So I started out with something similar here. It has the benefit of having the header row and column but it scrolls in both the horizontal direction as well as the vertical direction. The difference between this example and the first one is that the addepar table only scrolls in one direction. Which is a more calm user experience.
I have been looking into possible ways to get to where I want. The first part seems to be to check in which direction the user is scrolling. Such a thing can be done with jQuery;
var previousScrollvertical = 0,
previousScrollHorizontal = 0;
$(window).scroll(function(){
var currentVerticalScroll = $(this).scrollTop(),
currentHorizontalScroll = $(this).scrollLeft();
if(currentVerticalScroll==previousScrollvertical) {
if (currentHorizontalScroll > previousScrollHorizontal){
console.log('Right');
} else {
console.log('left');
}
} else if(currentHorizontalScroll==previousScrollHorizontal) {
if (currentVerticalScroll > previousScrollvertical){
console.log('down');
} else {
console.log('up');
}
}
previousScrollHorizontal = currentHorizontalScroll;
previousScrollvertical =currentVerticalScroll;
});
This snippet of code works on any website that has jQuery loaded. You can try it out from the console.
But from here I seem to be stuck. Is it possible to block a scroll direction with jQuery? Is there an easier way to achieve this? Should I be considering a completely different route?
The short answer is to use jQuery's scrollTop or scrollLeft to set the scroll of the direction you want to block back to what it was before.
I've created a quick example that shows how one might do that in practice:
Live Demo
var $container = $('.table-container');
var $table = $container.find('table');
var previousScroll = [0, 0];
var correction = false;
// Adjust the threshold to a larger number if you'd like it
// to take longer to switch between horizontal and vertical
// scrolling
var threshold = 10;
var direction;
var directionTimeout;
$container.on('scroll', function (event) {
if (!correction) {
var element = event.currentTarget,
$element = $(event.currentTarget),
x = element.scrollLeft,
y = element.scrollTop;
var diff = [
Math.abs(x - previousScroll[0]),
Math.abs(y - previousScroll[1])
];
correction = true;
if (!direction) {
if (diff[0] > diff[1]) {
direction = 'horizontal';
} else if (diff[0] < diff[1]) {
direction = 'vertical';
} else {
direction = 'vertical';
}
}
if (direction === 'horizontal') {
$element.scrollTop(previousScroll[1]);
previousScroll = [x, previousScroll[1]];
} else {
$element.scrollLeft(previousScroll[0]);
previousScroll = [previousScroll[0], y];
}
clearTimeout(directionTimeout);
directionTimeout = setTimeout(function () {
direction = null;
}, threshold);
} else {
correction = false;
}
});
I have aa div that I want to slide in once the user scrolls down a specified amount. It initially works but after than the div keeps moving to the left a little on every scroll action instead of staying in place. Anyone has an idea why is this happening?
var opening = false;
var closing = false;
$(window).scroll(function(){
var windowHeight = $(window).height();
var windowScroll = $(window).scrollTop();
var position1 = $("#Support").offset().top;
if ( windowScroll > (position1 - (windowHeight/2)) )
{
if (!opening) {
opening = true;
closing = false;
$("#SupportImage1").stop().animate({
left: "1200px"
}, 1500, function(){
opening = false;
});
}
}
else
{
if (!closing) {
closing = true;
opening = false;
$("#SupportImage1").stop().animate({
left: "100%"
}, 1400, function() {
closing = false;
});
}
}
});
the scroll bar is most likely affecting your width calculations.
everytime you run that function against the scroll bar you are adding in the total screen width plus the offset by the scroll bar.