windows.scrollBy adding a fixed scrolling value to top - javascript

I have this function I'm using it in my AngularJS directive. This function scrolls to the top of the page, but this is not what I am aiming to do: I want to make it scroll up just 400px or 30%.
function scrollToTop() {
var scrollDuration = 500;
var scrollStep = -window.scrollY / (scrollDuration / 15);
console.log(scrollStep);
var scrollInterval = setInterval(function () {
if (window.scrollY != 0) {
window.scrollBy(0, scrollStep);
} else {
clearInterval(scrollInterval);
}
}, 15);
}
I tried changing the scrollStep variable to be 300 or any other number but I can't understand it actually.

The total distanceToScroll is either an arbitrary number of pixels (i.e 400) or the whole window-scroll distance if it is less than 400. For that you can use Math.min. scrollStep is calculated dependently from distanceToScroll. You need to keep a count of "how much I've scrolled so far" in the setInterval, lets call it distanceScrolled. Keep scrolling until you have covered the distanceToScroll.
function scrollToTop() {
var scrollDuration = 500;
var stepDuration = 15;
var distanceToScroll = Math.min(400, window.scrollY);
var scrollStep = distanceToScroll / (scrollDuration / stepDuration);
console.log(scrollStep);
var distanceScrolled = 0;
var scrollInterval = setInterval(function () {
if (distanceScrolled < distanceToScroll) {
window.scrollBy(0, -1 * scrollStep);
distanceScrolled += scrollStep
} else {
clearInterval(scrollInterval);
}
}, stepDuration);
}
document.getElementById('btn').addEventListener('click', scrollToTop);
#very-high {
height: 3000px;
}
#btn {
position: fixed;
right: 10px;
top: 10px;
}
<div id="very-high"></div>
<button id="btn">Scroll</button>

Related

Javascript Track page scroll depth on webpage load after 25%, 50%, 75% and 100% only if a user waits for 2seconds

To fire a console.log if a user scrolls on a webpage 25% and waits for 2 seconds or more. Similarly fire 50% scroll after a user scrolls a webpage 50% and waits for 2 seconds and similarly for 75% and 100%.
For example a user scrolls directly to 50% and waits there for 2 seconds then fire only 50% and not 25%. And also when the user scrolls to 100% quickly without 2 secs halt and then goes back to top do not fire any console.log as user has'nt waited for 2 secs. Pls help in adding this 2 seconds halt and then firing the console.log,
I did this using Javascript it is working but now how to add 2 seconds ?
var maxScrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
var percentageObj = {};
var percentagesArr = [25,50,75,100];
window.addEventListener("scroll", function (event) {
var scrollVal = this.scrollY;
for(var i =0; i<percentagesArr.length;i++){
var currentPercentage = percentagesArr[i];
var scrollPercentage = parseInt((maxScrollHeight/100) * currentPercentage);
if(scrollVal >= scrollPercentage && !window.percentageObj[scrollPercentage.toString()]){
console.log("scrolled past - " + currentPercentage.toString() + "%");
window.percentageObj[scrollPercentage.toString()] = true;
}
}
});
Use setTimeout to delay logging and clearTimeout whenever page percentage changes:
var maxScrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
var percentagesArr = [25,50,75,100];
const showed = {};
let timeout;
let previousPercentage;
window.addEventListener("scroll", function (event) {
var scrollVal = this.scrollY;
var scrollPercentage = Math.round(scrollVal / maxScrollHeight * 100);
let currentPercentage = 0;
let i = 0;
while(percentagesArr[i] <= scrollPercentage) {
currentPercentage = percentagesArr[i++];
}
if (previousPercentage !== currentPercentage) {
clearTimeout(timeout);
timeout = currentPercentage !== 0 && !showed[currentPercentage]
? setTimeout(() => {
console.log(currentPercentage);
showed[currentPercentage] = true;
}, 2000)
: null;
previousPercentage = currentPercentage;
}
});
window.addEventListener("resize", () => {
maxScrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
})
body {
height: 500vh;
position: relative;
margin: 0;
}
#container div {
height: 30px;
background-color: red;
position: absolute;
width: 100%;
font-family: sans-serif;
justify-content: center;
display: flex;
align-items: center;
}
#p25 {
top: calc(25% * 4/5);
}
#p50 {
top: calc(50% * 4/5);
}
#p75 {
top: calc(75% * 4/5);
}
<div id="container">
<div id="p25">25%</div>
<div id="p50">50%</div>
<div id="p75">75%</div>
</div>
var maxScrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
var percentageObj = {};
var percentagesArr = [25,50,75,100];
window.addEventListener("scroll", function (event) {
var scrollVal = this.scrollY;
for(var i =0; i<percentagesArr.length;i++){
var currentPercentage = percentagesArr[i];
var scrollPercentage = parseInt((maxScrollHeight/100) * currentPercentage);
let currentTop = window.scrollY;
if(scrollVal >= scrollPercentage && !window.percentageObj[scrollPercentage.toString()]){
setTimeout((currentTop)=>{
if(currentTop === window.scrollY){
console.log("scrolled past - " + currentPercentage.toString() + "%");
window.percentageObj[scrollPercentage.toString()] = true;
}
},2000)
}
}
});
try this.

Get elements coordinates

I need some help here.
First off, here is a small demo code from my game: https://jsfiddle.net/MiloSx7/a0dn9a4f/2/
Animation idea: Make the coin scale to 2x after it's collected, then slowly move it and gradually reduce scale to the exact spot where the image displaying the coin inventory stat is , invLocation is the ID of the element where the animation should end. It starts from the current coinId X and Y
Is it possible to somehow get the X and Y of the invLocation, so that I know where should I tell the animation to move?
You can do this with JQuery position() and offset() methods.
const spawnTime = 10000;
var coin = 0;
var intervalId = '';
var coinDiv = $('#coinDiv');
var coinImg = $('#coinImg');
var invDiv = $('#invDiv');
var invId = $('#inventoryId');
var invImg = $('#invLocation');
coinImg.on('click', collect);
intervalId = setInterval(setLocation, spawnTime);
function setLocation() {
var x = parseInt( Math.random()*(80-20+1) ) + 20;
var y = parseInt( Math.random()*(80-20+1) ) + 20;
coinImg.animate({
opacity: 1
}, 3000,
function() {
coinImg.css('top', x+'%');
coinImg.css('left', y+'%');
coinImg.css('display', 'initial');
setTimeout( () => coinImg.animate({ opacity: 0 }, 3000), 6000);
});
}
function collect() {
clearInterval(intervalId);
coinImg.stop();
coinImg.css('opacity', 1);
/* Increment coin counter */
coin++;
invId.text(coin);
/* In order to disable multiple clicks */
coinImg.css('pointer-events', 'none');
/* Double the size */
coinImg.css('width', '128px');
coinImg.css('height', '128px');
/* Animate and return to normal */
coinImg.animate({
width: '32px',
height: '32px',
left: invImg.offset().left + 'px',
top: invImg.offset().top + 'px'
}, 1500,
function() {
coinImg.css('pointer-events', 'auto');
coinImg.css('display', 'none');
coinImg.css('width', '64px');
coinImg.css('height', '64px');
intervalId = setInterval(setLocation, spawnTime);
}
);
}
Working example: https://jsfiddle.net/wz4q9w69/

Moving to sections of a website using jQuery `.scroll()`

I am trying to create a simple effect in jQuery that when the user scrolls down the page, a "pane" is automatically animated into view (so that the user doesn't have to scroll down all of the way themselves).
It's hard to explain, so here is the example: http://jsfiddle.net/naxb22q3/1/
As you can see, when you scroll down past the blue pane a few pixels, the green pane is shown. However, the code that I currently have makes it so that once that green pane is shown, you can no longer scroll up or down. You have to reload the page to get it to work again.
Ideally, the user could scroll up or down and the animations would work.
HTML:
<div class="pane bgBlue"></div>
<div class="pane bgGreen"></div>
<div class="pane bgRed"></div>
CSS:
.pane {
height: 1000px;
width: 100%;
}
.bgBlue {
background-color: blue;
}
.bgGreen {
background-color: green;
}
.bgRed {
background-color: red;
}
JavaScript:
/**
* Lock scroll position for each pane
* as the user scrolls down.
*/
$.fn.scrollView = function () {
return this.each(function () {
$('html, body').animate({
scrollTop: $(this).offset().top
}, 1250);
});
}
// Variables
var windowHeight = $(window).height();
var headerHeight = $('.siteHeader').outerHeight();
var paneHeight = windowHeight - (headerHeight / 2);
// `.scroll()` function
$(window).scroll(function () {
height = $(window).scrollTop();
if (height > 5) {
$('.pane.bgGreen').scrollView();
//$(this).off('scroll');
}
// After we scroll past the green pane,
// the red pane is shown (via the same animation)
if (height > (paneHeight * 2)) {
$('.pane.bgRed').scrollView();
}
});
Rough solution, but a start - http://jsfiddle.net/bkseqsu4/
Javascript:
// Variables
var windowHeight = $(window).height();
var headerHeight = $('.siteHeader').outerHeight();
var paneHeight = windowHeight - (headerHeight / 2);
var scrollLock = 0;
var paneIndex = 0;
var lastScroll = 0;
var panes = ['.pane.bgBlue', '.pane.bgGreen', '.pane.bgRed'];
/**
* Lock scroll position for each pane
* as the user scrolls down.
*/
$.fn.scrollView = function() {
this.each(function() {
$('html, body').animate({
scrollTop: $(this).offset().top
}, 1000, "swing", function() {
setTimeout(function() {
scrollLock = 0;
var currentPosition = $(this).scrollTop();
lastScroll = currentPosition;
}, 100);
});
});
}
// `.scroll()` function
$(window).scroll(function() {
if (scrollLock == 0) {
var currentPosition = $(this).scrollTop();
if (currentPosition > lastScroll) {
paneIndex = paneIndex + 1;
} else {
paneIndex = paneIndex - 1;
}
scrollLock = 1;
$(panes[paneIndex]).scrollView();
}
});

How to calculate anchor point, when changing transformX value on touchmove event?

I'm creating a slider that displays a panoramic image by moving it horizontally inside a container.
Features or Intention (it's under development):
By default the animation happens automatically, changing the transformX value, in each step;
the user's able to touch the element and drag it left or right;
when touchend event's triggered, the slider resumes the animation from the user's dragged x position;
The problem is that when a user touch the element and starts dragging, the input value on transformX makes the element jumpy, apparently because the anchor point is different every time the user touches the draggable element.
What I'd like to know is, how to calculate the anchor point or position, where the user is dragging from? Or what's the best practice to always calculate from the same point, to avoid having this jumps.
I've done quite a lot of research at the moment without success. You can find a live example in the following link (http://jsbin.com/quhabi/1/edit). Please turn on the touch emulator on your brower because at the moment I'm not yet supporting mouse dragging.
You can also have a look into the code below (depends on jQuery):
sass:
html {
width: 100%;
height: 100%;
body {
width: 100%;
height: 100%;
background-color: #999;
.panorama {
width: 80%;
height: 80%;
margin: 0 auto;
overflow: hidden;
img {
height: 100%;
position: relative;
transition: opacity 0.6s ease;
transform-origin:left top;
}
}
}
}
html:
<div class="panorama">
<img src="images/panorama.jpg" alt="">
</div>
Javascript:
/*globals $, window */
'use strict';
$('document').ready(function () {
var panorama = {
// properties
$panorama: $('.panorama'),
$moveElement: $('.panorama img'),
timestart: 0,
seconds: 12,
msTotal: 0,
direction: -1,
positionX: 0,
percentage: 0,
animationFrameID: false,
myRequestAnimationFrame: (function () {
return function (callback) {
return window.setTimeout(callback, 1000 / 60);
};
})(),
touchPlayTimeout: 3000,
moveTimeoutID: null,
rightBoundary: null,
// methods
step: function (timestart) {
var self = this,
timestamp,
positionX;
timestamp = Date.now();
self.progress = timestamp - timestart;
self.percentage = (self.progress * (100 / self.msTotal));
positionX = self.direction * self.percentage;
positionX = self.positionBounderies(positionX);
positionX += '%';
self.position(positionX);
if (self.progress < self.msTotal) {
timestamp += 10;
self.animationFrameID = self.myRequestAnimationFrame(function () {
self.step.call(self, timestart);
});
}
},
positionBounderies: function (positionX) {
// move the next line to init method, after image preload done!
this.rightBoundary = 100 - (100 * (this.$panorama.width() / this.$moveElement.width()));
positionX = positionX > 0 ? 0 : positionX;
positionX = (positionX < 0 && Math.abs(positionX) > this.rightBoundary) ? this.direction * this.rightBoundary : positionX;
return positionX;
},
progressByPercentage: function (percentage) {
return percentage * (this.msTotal / 100);
},
dragIt: function (touchX) {
var positionX,
percentage = (this.progress * (100 / this.msTotal));
positionX = this.direction * percentage;
positionX = positionX + (touchX / 100);
positionX = this.positionBounderies(positionX);
positionX += '%';
// update percentage
this.percentage = Math.abs(parseFloat(positionX));
this.position(positionX);
},
position: function (posX) {
this.$moveElement.css('transform', 'translateX(' + posX + ')');
},
init: function () {
var self = this;
// set initial values
this.msTotal = this.seconds * 1000;
// set listeners
this.$moveElement.on('touchstart mousedown', function (e) {
// on mousedown prevent browser default `img` drag
e.preventDefault();
clearTimeout(self.animationFrameID);
clearTimeout(self.moveTimeoutID);
});
this.$moveElement.on('touchend mouseup', function (e) {
// on mousedown prevent browser default `img` drag
e.preventDefault();
// calculate where to play from using current progress
var playFrom = null;
self.progress = self.progressByPercentage(self.percentage);
self.moveTimeoutID = setTimeout(function () {
clearTimeout(self.moveTimeoutID);
playFrom = Date.now();
playFrom = playFrom - self.progress;
self.step(playFrom);
}, self.touchPlayTimeout);
});
this.$moveElement.on('touchmove', function (e) {
console.log(e);
var touch = e.originalEvent.touches[0],
touchPosition = touch.pageX - self.$panorama.width();
self.dragIt(touchPosition);
});
this.step(Date.now());
}
};
panorama.init();
});
I found that my problem is related with how I'm calculating the drag distance. The code above clearly shows that I'm using solely the position of pageX to calculate the transformX, which is absolutely wrong. The correct way is to store the start point from where the drag is happening from and the current dragging x value should be used to calculate the distance.
For example,
this.$moveElement.on('touchstart mousedown', function (e) {
var touch = e.originalEvent.touches[0];
self.touchDistance.start = touch.pageX;
});
this.$moveElement.on('touchmove', function (e) {
var touch = e.originalEvent.touches[0],
distance = 0;
self.touchDistance.end = touch.pageX;
distance = self.touchDistance.end - self.touchDistance.start;
self.dragIt(distance);
});
With this, I've got a working solution, as we can see here http://jsbin.com/quhabi/2/edit
Thanks for looking, hope this is useful for someone else in the future!

javascript toggle animation issue

I am doing a small javascript animation. this is my code :
window.onload = function () {
var heading = document.getElementsByTagName('h1')[0];
heading.onclick = function () {
var divHeight = 250;
var speed = 10;
var myInterval = 0;
alert(divHeight);
slide();
function slide() {
if (divHeight == 250) {
myInterval = setInterval(slideUp, 30);
} else {
myInterval = setInterval(slideDwn, 30);
alert('i am called as slide down')
}
}
function slideUp() {
var anima = document.getElementById('anima');
if (divHeight <= 0) {
divHeight = 0;
anima.style.height = '0px';
clearInterval(myInterval);
} else {
divHeight -= speed;
if (divHeight < 0) divHeight = 0;
anima.style.height = divHeight + 'px';
}
}
function slideDwn() {
var anima = document.getElementById('anima');
if (divHeight >= 250) {
divHeight = 250;
clearInterval(myInterval);
} else {
divHeight += speed;
anima.style.height = divHeight + 'px';
}
}
}
}
i am using above code for simple animation. i need to get the result 250 on the first click, as well second click i has to get 0 value. but it showing the 250 with unchanged. but i am assigning the value to set '0', once the div height reached to '0'.
what is the issue with my code? any one help me?
Everytime you click on the div the divHeight variable is reset to 250, thus your code never calls slideDwn. Moving the divHeight declaration outside the event handler should do the trick.
Also, your div wont have the correct size when any of the 2 animations end. You're setting the divHeight variable to 250 or 0 correctly, but never actually setting anima.style.height after that.
I've rewritten your code into something simpler and lighter. The main difference here is that we're using a single slide() function here, and that the height of the div in question is stored in a variable beforehand to ensure that the element slides into the correct position.
Note that this is a very simplistic implementation and assumes that the div carries no padding. (The code uses ele.clientHeight and ele.style.height interchangeably, which admittedly, is a pretty bad choice, but is done here to keep the code simple)
var heading = document.getElementsByTagName('h1')[0],
anima = document.getElementById('anima'),
divHeight = anima.clientHeight,
speed = 10,
myInterval = 0,
animating = false;
function slide(speed, goal) {
if(Math.abs(anima.clientHeight - goal) <= speed){
anima.style.height = goal + 'px';
animating = false;
clearInterval(myInterval);
} else if(anima.clientHeight - goal > 0){
anima.style.height = (anima.clientHeight - speed) + 'px';
} else {
anima.style.height = (anima.clientHeight + speed) + 'px';
}
}
heading.onclick = function() {
if(!animating) {
animating = true;
var goal = (anima.clientHeight >= divHeight) ? 0 : divHeight;
myInterval = setInterval(slide, 13, speed, goal);
}
}
See http://www.jsfiddle.net/yijiang/dWJgG/2/ for a simple demo.
I've corrected your code a bit (See working demo)
window.onload = function () {
var heading = document.getElementsByTagName('h1')[0];
var anima = document.getElementById('anima');
var divHeight = 250;
heading.onclick = function () {
var speed = 10;
var myInterval = 0;
function slideUp() {
divHeight -= speed;
if (divHeight <= 0) {
divHeight = 0;
clearInterval(myInterval);
}
anima.style.height = divHeight + 'px';
}
function slideDwn() {
divHeight += speed;
if (divHeight >= 250) {
divHeight = 250;
clearInterval(myInterval);
}
anima.style.height = divHeight + 'px';
}
function slide() {
console.log(divHeight )
if (divHeight == 250) {
myInterval = setInterval(slideUp, 30);
} else {
myInterval = setInterval(slideDwn, 30);
}
}
slide();
}
}​

Categories