Slide header up if you scroll down and vice versa - javascript

Update
I made a repo on GitHub:
https://github.com/yckart/Veil.js
Big thanks to Sargo Darya and Edward J Payton.
I've to create a header which slides up if you scroll down and vice versa. The problem is, that it jumps (if you are in the diff-range between 0-128).
I can not figure out where the problem sits. Any idea how to get this to work correctly?
Here's what I've done so far: http://jsfiddle.net/yckart/rKW3f/
// something simple to get the current scroll direction
// false === down | true === up
var scrollDir = (function (oldOffset, lastOffset, oldDir) {
return function (offset) {
var dir = offset < oldOffset;
if (dir !== oldDir) lastOffset = offset;
oldOffset = offset;
oldDir = dir;
return {dir: dir, last: lastOffset};
};
}());
var header = document.querySelector('header');
var height = header.clientHeight;
addEventListener('scroll', function () {
var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
var dir = scrollDir(scrollY);
var diff = dir.last-scrollY;
var max = Math.max(-height, Math.min(height, diff));
header.style.top = (dir.dir ? max-height : max) + 'px';
});
Another problem is, that if the scroll-direction was changed the first time, nothing happens. However, this could be fixed with an interval, or else.

I believe this is exactly what you want:
var header = $('header'),
headerHeight = header.height(),
treshold = 0,
lastScroll = 0;
$(document).on('scroll', function (evt) {
var newScroll = $(document).scrollTop(),
diff = newScroll-lastScroll;
// normalize treshold range
treshold = (treshold+diff>headerHeight) ? headerHeight : treshold+diff;
treshold = (treshold < 0) ? 0 : treshold;
header.css('top', (-treshold)+'px');
lastScroll = newScroll;
});
Demo on: http://jsfiddle.net/yDpeb/

Try this out:- http://jsfiddle.net/adiioo7/rKW3f/7/
JS:-
var scrollDir = (function (oldOffset, lastOffset, oldDir) {
return function (offset) {
var dir = offset < oldOffset;
if (dir !== oldDir) {
lastOffset = offset;
} else {
offset = offset - height;
}
oldOffset = offset;
oldDir = dir;
return {
dir: dir,
last: lastOffset
};
};
}());
var header = document.querySelector('header');
var height = header.clientHeight;
$(window).scroll(function () {
var scrollY = $(window).scrollTop();
var dir = scrollDir(scrollY);
var diff = dir.last - scrollY;
var max = Math.max(-height, Math.min(height, diff));
max = (dir.dir ? max - height : max);
max = scrollY<height?0:max;
$('header').data('size', 'small');
$('header').stop().animate({
top: max
}, 600);
});

Sargo Darya's answer above is exacty what i was looking for but I found a bug with Webkits inertia scrolling so I made a fix:
// Scrolling Header
var header = $('header'),
headerHeight = header.height(),
offset = 0,
lastPos = 0;
$(document).on('scroll', function(e) {
var newPos = $(document).scrollTop(),
pos = newPos-lastPos;
if (offset+pos>headerHeight) {
offset = headerHeight;
} else if (newPos < 0){ // webkit inertia scroll fix
offset = 0;
} else {
offset = offset+pos;
};
if (offset < 0) {
offset = 0;
} else {
offset = offset;
};
header.css('top', (-offset)+'px');
lastPos = newPos;
});
Adding one line fixed it. If - if scroll position is lower than 0, set header offset at 0.
Demo based on Sargo Darya's - http://jsfiddle.net/edwardomni/D58vx/4/

Related

horizontal timeline fixed distance and centered on mobile devices

I am trying to reach a horizontal timeline like this:
https://codepen.io/ritz078/pen/LGRWjE
My problem is, that I've got no real dates (DD/MM/YYYY) but only years like 1998-2002 or just 2009. So there is a problem, I am struggling to fix, which ends up like this:
So my aims are:
Set a fixed distance between elements
Make it work just with years
When on a device less than 768px wide ensure a single element is displayed and it appears in the center
This is my solution for 3., but the other things, I couldnt solute:
if ($(window).width() < 768 {
eventsMinDistance = $('.cd-horizontal-timeline .events-wrapper').width(/2;)
}
(timelines.length > 0) && initTimeline(timelines);
$(window).resize(function(){
if ($(window).width() < 768 {
eventsMinDistance = $('.cd-horizontal-timeline .events-wrapper').width(/2;)
} else{
eventsMinDistance = 155;
}
}
Do you guys know how do adjust it, as I am struggling since hours without any success. Thank you very much for your help!
the first part of your code works fine, but it was faulty on the syntax, I fixed it and use it and also add a couple of changes to acomplished the desired fixed width amount between each date.
Actually it was pretty easy, when you debug and you know exactly what the developer wants to do.
This is the code I wrote:
jQuery(document).ready(function($){
var timelines = $('.cd-horizontal-timeline'),
eventsRelativeDistance = false;
if ($(window).width() < 768) {
eventsMinDistance = Number($('.cd-horizontal-timeline .events-wrapper').width())/2;
}else{
var eventsMinDistance = 100;
}
(timelines.length > 0) && initTimeline(timelines);
$(window).resize( function(){
if ($(window).width() < 768) {
eventsMinDistance = Number($('.cd-horizontal-timeline .events-wrapper').width())/2;
} else{
eventsMinDistance = 100;
}
});
function initTimeline(timelines) {
timelines.each(function(){
var timeline = $(this),
timelineComponents = {};
//cache timeline components
timelineComponents['timelineWrapper'] = timeline.find('.events-wrapper');
timelineComponents['eventsWrapper'] = timelineComponents['timelineWrapper'].children('.events');
timelineComponents['fillingLine'] = timelineComponents['eventsWrapper'].children('.filling-line');
timelineComponents['timelineEvents'] = timelineComponents['eventsWrapper'].find('a');
timelineComponents['timelineDates'] = parseDate(timelineComponents['timelineEvents']);
timelineComponents['eventsMinLapse'] = minLapse(timelineComponents['timelineDates']);
timelineComponents['timelineNavigation'] = timeline.find('.cd-timeline-navigation');
timelineComponents['eventsContent'] = timeline.children('.events-content');
if(!eventsRelativeDistance){
// Set up space to store the distance in pixels.
timelineComponents['distanceInPx'] = [];
}
//assign a left postion to the single events along the timeline
setDatePosition(timelineComponents, eventsMinDistance, eventsRelativeDistance);
//assign a width to the timeline
var timelineTotWidth = setTimelineWidth(timelineComponents, eventsMinDistance, eventsRelativeDistance);
//the timeline has been initialize - show it
timeline.addClass('loaded');
//detect click on the next arrow
timelineComponents['timelineNavigation'].on('click', '.next', function(event){
event.preventDefault();
updateSlide(timelineComponents, timelineTotWidth, 'next');
});
//detect click on the prev arrow
timelineComponents['timelineNavigation'].on('click', '.prev', function(event){
event.preventDefault();
updateSlide(timelineComponents, timelineTotWidth, 'prev');
});
//detect click on the a single gallery - show new gallery content
timelineComponents['eventsWrapper'].on('click', 'a', function(event){
event.preventDefault();
timelineComponents['timelineEvents'].removeClass('selected');
$(this).addClass('selected');
updateOlderEvents($(this));
updateFilling($(this), timelineComponents['fillingLine'], timelineTotWidth);
updateVisibleContent($(this), timelineComponents['eventsContent']);
});
//on swipe, show next/prev gallery content
timelineComponents['eventsContent'].on('swipeleft', function(){
var mq = checkMQ();
( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'next');
});
timelineComponents['eventsContent'].on('swiperight', function(){
var mq = checkMQ();
( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'prev');
});
//keyboard navigation
$(document).keyup(function(event){
if(event.which=='37' && elementInViewport(timeline.get(0)) ) {
showNewContent(timelineComponents, timelineTotWidth, 'prev');
} else if( event.which=='39' && elementInViewport(timeline.get(0))) {
showNewContent(timelineComponents, timelineTotWidth, 'next');
}
});
});
}
function updateSlide(timelineComponents, timelineTotWidth, string) {
//retrieve translateX value of timelineComponents['eventsWrapper']
var translateValue = getTranslateValue(timelineComponents['eventsWrapper']),
wrapperWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', ''));
//translate the timeline to the left('next')/right('prev')
(string == 'next')
? translateTimeline(timelineComponents, translateValue - wrapperWidth + eventsMinDistance, wrapperWidth - timelineTotWidth)
: translateTimeline(timelineComponents, translateValue + wrapperWidth - eventsMinDistance);
}
function showNewContent(timelineComponents, timelineTotWidth, string) {
//go from one gallery to the next/previous one
var visibleContent = timelineComponents['eventsContent'].find('.selected'),
newContent = ( string == 'next' ) ? visibleContent.next() : visibleContent.prev();
if ( newContent.length > 0 ) { //if there's a next/prev gallery - show it
var selectedDate = timelineComponents['eventsWrapper'].find('.selected'),
newEvent = ( string == 'next' ) ? selectedDate.parent('li').next('li').children('a') : selectedDate.parent('li').prev('li').children('a');
updateFilling(newEvent, timelineComponents['fillingLine'], timelineTotWidth);
updateVisibleContent(newEvent, timelineComponents['eventsContent']);
newEvent.addClass('selected');
selectedDate.removeClass('selected');
updateOlderEvents(newEvent);
updateTimelinePosition(string, newEvent, timelineComponents);
}
}
function updateTimelinePosition(string, event, timelineComponents) {
//translate timeline to the left/right according to the position of the selected gallery
var eventStyle = window.getComputedStyle(event.get(0), null),
eventLeft = Number(eventStyle.getPropertyValue("left").replace('px', '')),
timelineWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', '')),
timelineTotWidth = Number(timelineComponents['eventsWrapper'].css('width').replace('px', ''));
var timelineTranslate = getTranslateValue(timelineComponents['eventsWrapper']);
if( (string == 'next' && eventLeft > timelineWidth - timelineTranslate) || (string == 'prev' && eventLeft < - timelineTranslate) ) {
translateTimeline(timelineComponents, - eventLeft + timelineWidth/2, timelineWidth - timelineTotWidth);
}
}
function translateTimeline(timelineComponents, value, totWidth) {
var eventsWrapper = timelineComponents['eventsWrapper'].get(0);
value = (value > 0) ? 0 : value; //only negative translate value
value = ( !(typeof totWidth === 'undefined') && value < totWidth ) ? totWidth : value; //do not translate more than timeline width
setTransformValue(eventsWrapper, 'translateX', value+'px');
//update navigation arrows visibility
(value == 0 ) ? timelineComponents['timelineNavigation'].find('.prev').addClass('inactive') : timelineComponents['timelineNavigation'].find('.prev').removeClass('inactive');
(value == totWidth ) ? timelineComponents['timelineNavigation'].find('.next').addClass('inactive') : timelineComponents['timelineNavigation'].find('.next').removeClass('inactive');
}
function updateFilling(selectedEvent, filling, totWidth) {
//change .filling-line length according to the selected gallery
var eventStyle = window.getComputedStyle(selectedEvent.get(0), null),
eventLeft = eventStyle.getPropertyValue("left"),
eventWidth = eventStyle.getPropertyValue("width");
eventLeft = Number(eventLeft.replace('px', '')) + Number(eventWidth.replace('px', ''))/2;
var scaleValue = eventLeft/totWidth;
setTransformValue(filling.get(0), 'scaleX', scaleValue);
}
function setDatePosition(timelineComponents, min, relativeDistance) {
var distance,
distanceNorm = 0,
distancesInPx =[];
for (i = 0; i < timelineComponents['timelineDates'].length; i++) {
if (relativeDistance){
distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]);
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
}else{
distance = 5;
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2 + distanceNorm;
// Save am array of sizes to track the distance in pixels from the left.
timelineComponents['distanceInPx'].push(distanceNorm*min);
}
timelineComponents['timelineEvents'].eq(i).css('left', distanceNorm*min+'px');
}
}
function setTimelineWidth(timelineComponents, width, relativeDistance) {
var timeSpan = 0, timeSpanNorm, totalWidth;
if(relativeDistance){
// If relative Time Distance daydiff caclulates the first date and the last one.
timeSpan = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][timelineComponents['timelineDates'].length-1]);
timeSpanNorm = timeSpan/timelineComponents['eventsMinLapse'];
timeSpanNorm = Math.round(timeSpanNorm) + 4;
totalWidth = timeSpanNorm*width;
}else{
// However if no relative Distance we obtain the amount of distance in pixels from the last position of the array which is the farthest element on the array.
totalWidth = timelineComponents['distanceInPx'][timelineComponents['distanceInPx'].length-1];
}
timelineComponents['eventsWrapper'].css('width', totalWidth+'px');
updateFilling(timelineComponents['eventsWrapper'].find('a.selected'), timelineComponents['fillingLine'], totalWidth);
updateTimelinePosition('next', timelineComponents['eventsWrapper'].find('a.selected'), timelineComponents);
return totalWidth;
}
function updateVisibleContent(event, eventsContent) {
var eventDate = event.data('date'),
visibleContent = eventsContent.find('.selected'),
selectedContent = eventsContent.find('[data-date="'+ eventDate +'"]'),
selectedContentHeight = selectedContent.height();
if (selectedContent.index() > visibleContent.index()) {
var classEnetering = 'selected enter-right',
classLeaving = 'leave-left';
} else {
var classEnetering = 'selected enter-left',
classLeaving = 'leave-right';
}
selectedContent.attr('class', classEnetering);
visibleContent.attr('class', classLeaving).one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function(){
visibleContent.removeClass('leave-right leave-left');
selectedContent.removeClass('enter-left enter-right');
});
eventsContent.css('height', selectedContentHeight+'px');
}
function updateOlderEvents(event) {
event.parent('li').prevAll('li').children('a').addClass('older-gallery').end().end().nextAll('li').children('a').removeClass('older-gallery');
}
function getTranslateValue(timeline) {
var timelineStyle = window.getComputedStyle(timeline.get(0), null),
timelineTranslate = timelineStyle.getPropertyValue("-webkit-transform") ||
timelineStyle.getPropertyValue("-moz-transform") ||
timelineStyle.getPropertyValue("-ms-transform") ||
timelineStyle.getPropertyValue("-o-transform") ||
timelineStyle.getPropertyValue("transform");
if( timelineTranslate.indexOf('(') >=0 ) {
var timelineTranslate = timelineTranslate.split('(')[1];
timelineTranslate = timelineTranslate.split(')')[0];
timelineTranslate = timelineTranslate.split(',');
var translateValue = timelineTranslate[4];
} else {
var translateValue = 0;
}
return Number(translateValue);
}
function setTransformValue(element, property, value) {
element.style["-webkit-transform"] = property+"("+value+")";
element.style["-moz-transform"] = property+"("+value+")";
element.style["-ms-transform"] = property+"("+value+")";
element.style["-o-transform"] = property+"("+value+")";
element.style["transform"] = property+"("+value+")";
}
//based on http://stackoverflow.com/questions/542938/how-do-i-get-the-number-of-days-between-two-dates-in-javascript
function parseDate(events) {
var dateArrays = [];
events.each(function(){
var singleDate = $(this),
dateComp = singleDate.data('date').split('T');
if( dateComp.length > 1 ) { //both DD/MM/YEAR and time are provided
var dayComp = dateComp[0].split('/'),
timeComp = dateComp[1].split(':');
} else if( dateComp[0].indexOf(':') >=0 ) { //only time is provide
var dayComp = ["2000", "0", "0"],
timeComp = dateComp[0].split(':');
} else { //only DD/MM/YEAR
var dayComp = dateComp[0].split('/'),
timeComp = ["0", "0"];
}
var newDate = new Date(dayComp[2], dayComp[1]-1, dayComp[0], timeComp[0], timeComp[1]);
dateArrays.push(newDate);
});
return dateArrays;
}
function daydiff(first, second) {
return Math.round((second-first));
}
function minLapse(dates) {
//determine the minimum distance among events
var dateDistances = [];
for (i = 1; i < dates.length; i++) {
var distance = daydiff(dates[i-1], dates[i]);
dateDistances.push(distance);
}
return Math.min.apply(null, dateDistances);
}
/*
How to tell if a DOM element is visible in the current viewport?
http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
*/
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
function checkMQ() {
//check if mobile or desktop device
return window.getComputedStyle(document.querySelector('.cd-horizontal-timeline'), '::before').getPropertyValue('content').replace(/'/g, "").replace(/"/g, "");
}
});
Did you ever get this to work?? Have come across the same problem. If i change the default distance from 60 to 1 the gap between is not enough and the whole timeline breaks. The calculations for the distance as described in the article is as follows
First of all, in the main.js file, we set a minimum distance between two consecutive dates, using the eventsMinDistance variable; in our case, we set eventsMinDistance = 60 (so the minimum distance will be 60px). Then we evaluate all the differences between a date and the following one; to do that we use the data-date attribute added to each date. The minimum difference is then used as a reference to evaluate the distances between two consecutive dates.
For example, let's suppose the minimum found difference is 5 days; that means that the distance, along the timeline, between two dates separated by a lapse of 5days will be 60px, while the one between two events separated by a lapse of 10 days will be 120px.
source:: www.codyhouse.org
From what i read the min distance is here:~
var timelines = $('.cd-horizontal-timeline'),
eventsMinDistance = 60;
(timelines.length > 0) && initTimeline(timelines);
This creates a variable called timelines and sets it to the class .cd-hor... and sets the min distance to 60px. changing this to 1 breaks the application as the distance between the times are too small.
function setDatePosition(timelineComponents, min) {
for (i = 0; i < timelineComponents['timelineDates'].length; i++) {
var distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]),
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
timelineComponents['timelineEvents'].eq(i).css('left', distanceNorm*min+'px');
}
}
I might be wrong but here is the section calculating the distance and the last distanceNorm*min+'px'. min i believe is 60 and distance norm is the calculation of the 5 days etc. if you remove distance norm the app breaks so you cant just add min+'px' this is because you remove the original distance.
All distances are calculated from the first timeline. Thats why the app breaks. Need to find the code that tells which to calc from which is the
var distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]),
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
this sets distance as the first element of the index and then for each timelineDates within the loop [i].
I've been at it for days but have come to the conclusion the tutorial is good as is but it is not a library and should be used as reference to write your own from scratch which is what i am now doing.
If you did ever manage it though please update as so far i managed to manipulate the dates to get equal spacing but if you insert too many it breaks which is no good hence the rewrite!

javascript, offsetTop, offsetBottom

I have a paragraph tag in my html id is move, I am trying to move the p tag to slowing fall down while on page load. but my code is not working.......
var speed = 12;
var direction = 1;
var getParagraph = document.getElementById("move");
getParagraph.onmouseover = moving;
function moving() {
var bo = getParagraph.offsetHeight;
var boTop = getParagraph.offsetTop;
var boBottom = boTop + bo;
// When right side of the box goes too far - change direction:
if (boBottom > document.body.offsetHeight) {
direction = -1;
}
// When left side of the box goes too far - change direction:
if (boTop < 0) {
direction = 1;
}
// Recalculate position:
getParagraph.style.Top = (boTop + speed * direction)
}
This is your code with minor changes, and it "works":
JS:
var speed = 12;
var direction = 1;
var getParagraph = document.getElementById("move");
document.getElementById("move").addEventListener("mouseover", moving);
//getParagraph.onmouseover = moving;
function moving() {
console.log("Moving??");
var bo = document.getElementById("move").offsetHeight;
var boTop = document.getElementById("move").offsetTop;
var boBottom = boTop + bo;
// When right side of the box goes too far - change direction:
if (boBottom > document.body.offsetHeight) {
direction = -1;
}
// When left side of the box goes too far - change direction:
if (boTop < 0) {
direction = 1;
}
// Recalculate position:
document.getElementById("move").style.marginTop = (boTop + speed * direction) + "px";
speed++;
}
CSS:
#move {
display : block ;
position : absolute ;
}
Hope it helps.

Calculating & setting scroll speed of object in viewport

I have image I am scrolling within a div.
It make sure the image is visible I am using
var isVisible = (
threshold.top >= -39 &&
threshold.bottom <= (window.innerHeight || document.documentElement.clientHeight)
);
What I am trying to do now is make sure that once the element is visible it is able to completely finish scrolling before going out of the view port.
I am thinking I can do this by effecting the speed value based on the the distance of the element from the top on the window. But I am having a very hard time doing this.
I am using .getBoundingClientRect() to get the distance the element is from the top of the viewport:
var threshold = document.getElementById('page-feature').getBoundingClientRect();
var thresholdY = threshold.top;
Below is my code so far:
function scrollImageInViewport() {
var threshold = document.getElementById('page-feature').getBoundingClientRect();
var thresholdY = threshold.top;
var isVisible = (
threshold.top >= -39 &&
threshold.bottom <= (window.innerHeight || document.documentElement.clientHeight)
);
if (isVisible && window.innerWidth > 550) {
scrollDir(thresholdY);
}
}
function scrollUp(thresholdY) {
if (thresholdCounter < maxScrollNegative) {
return;
} else {
pageScroll.setAttribute('style', '-webkit-transform:translate3d(0,' + (--thresholdCounter *speed) + 'px,0); -ms-transform:translate3d(0,' + (--thresholdCounter *speed) + 'px,0); transform:translate3d(0,' + (--thresholdCounter *speed) + 'px,0);');
}
};
function scrollDown(thresholdY) {
if (thresholdCounter > maxScrollPositive) {
return;
} else {
pageScroll.setAttribute('style', '-webkit-transform:translate3d(0,' + (++thresholdCounter *speed) + 'px,0); -ms-transform:translate3d(0,' + (++thresholdCounter *speed) + 'px,0); transform:translate3d(0,' + (++thresholdCounter *speed) + 'px,0);');
}
};
function scrollToTop(){
initScroll();
pageScroll.setAttribute('style', 'transform:translate3d(0,0,0);');
thresholdCounter = 0;
};
function scrollDir(thresholdY) {
var scroll = window.scrollY;
if(scroll > position) {
distanceFromTop(thresholdY);
scrollUp(thresholdY);
} else if (scroll < position ){
scrollDown(thresholdY);
}
position = scroll;
};
function distanceFromTop(thresholdY) {
if (thresholdY > 0) {
`enter code here`//set speed as distance from top /px of not shown content
speed = (scrollImageHeight - scrollVisibleHeight) / thresholdY;
}
};
function initScroll(){
position = window.scrollY;
pageScroll = document.getElementById('page-scroll');
scrollImageHeight = pageScroll.offsetHeight; //total height of scroll image
pagePanel = document.getElementById("pagePanel");
pageStyle = window.getComputedStyle(pagePanel,"");
size = pageStyle.getPropertyValue("height");
scrollVisibleHeight = parseInt(size, 10);//visible height of scroll image
scrollImageEnd = scrollImageHeight - scrollVisibleHeight;
maxScrollNegative = -scrollImageEnd / speed;
}
var speed;
var thresholdCounter = 0;
var maxScrollPositive = 0;
var position,
pageScroll,
scrollImageHeight,
pagePanel,
pageStyle,
size,
scrollVisibleHeight,
scrollImageEnd,
maxScrollNegative;
window.addEventListener('resize', scrollToTop);
document.addEventListener('scroll', scrollImageInViewport);
window.addEventListener('load', initScroll);
This is what I ended up with:
var featurePage = document.getElementById('page-feature')
var pageScroll = document.getElementById('page-scroll');
var startP, // where animation needs to begin
endP, // where animation needs to end
diff; // visible element size
function getElementOffset(){ //init
var de = document.documentElement;
var box = featurePage.getBoundingClientRect();
var top = box.top + window.pageYOffset - de.clientTop;
var bottom = box.bottom + window.pageYOffset - de.clientTop;
var winHight = window.innerHeight;
diff = bottom - top;
var elPadding = (winHight - diff);
startP = top - elPadding;
endP = bottom - elPadding;
scrollImage()
}
function scrollImage(){
var scrollImageHeight = pageScroll.offsetHeight;
var scrollPos = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
var s1 = scrollPos - startP;
var realPos = -s1/diff;
var lengthLeft = scrollImageHeight - (diff)
if ( realPos < 0.09 && realPos > -1){
pageScroll.setAttribute('style', '-webkit-transform:translate3d(0,' + (realPos * lengthLeft) + 'px,0); -ms-transform:translate3d(0,' + (realPos *lengthLeft) + 'px,0); transform:translate3d(0,' + (realPos *lengthLeft) + 'px,0);');
}
}
window.addEventListener('resize', getElementOffset);
document.addEventListener('scroll', getElementOffset);

Event on margin change

I have an element with animated top margin. I need to detect if it isn't too close from the border, and if it is, scroll parent div to lower position, to prevent animated element from hiding. Here is an example:
http://jsfiddle.net/zYYBR/5/
This green box shouldn't be below the red line after clicking the "down" button.
Do you mean this?
var new_margin;
var step = 75;
var limit = $("#max")[0].offsetTop;
$('#down').click(function() {
var goStep = step;
var elHeight = $("#animated")[0].offsetTop + $("#animated")[0].offsetHeight;
if((elHeight + step) > limit)
{
goStep = limit - elHeight;
}
new_margin = goStep + parseInt($('#animated').css('margin-top'));
$("#animated").animate({marginTop: new_margin}, 1000);
});
http://jsfiddle.net/zYYBR/8/
EDIT: Or maybe something like that (of course you can improve the calculation, because currently it's very buggy with scroll):
var new_margin;
var step = 75;
$('#down').click(function () {
scroll(1000);
});
var scrollTimer = null;
$("#container").bind("scroll", function () {
clearTimeout(scrollTimer);
scrollTimer = setTimeout(function () { scroll(1); }, 10);
});
function scroll(speed) {
var scrollStep, animationStep = step;
var currentBoxBottom = $("#animated")[0].offsetTop + $("#animated")[0].offsetHeight;
var nextCurrentBoxBottom = currentBoxBottom + step;
var limit = $("#max")[0].offsetTop + $("#container")[0].scrollTop;
if (nextCurrentBoxBottom > limit) {
if (limit >= $("#container")[0].scrollTop) {
scrollStep = $("#container")[0].scrollTop + nextCurrentBoxBottom - limit;
}
else {
scrollStep = $("#container")[0].scrollTop - nextCurrentBoxBottom - limit;
animationStep = nextCurrentBoxBottom - limit;
}
$("#container")[0].scrollTop = scrollStep;
}
new_margin = animationStep + parseInt($('#animated').css('margin-top'));
$("#animated").animate({ marginTop: new_margin }, speed);
}
http://jsfiddle.net/zYYBR/13/
Do you mean something like this?
I have the same visual result as Alex Dn did, but I added a little extra direction to what I think you're talking about. If it's what you're looking for I'll make updates:
var new_margin;
var step = 75;
var limit = $("#max")[0].offsetTop;
$('#down2').click(function() {
var anim = $("#animated");
var hrOff = $("#max").offset();
var thOff = anim.offset();
new_margin = Math.min(hrOff.top - thOff.top - anim.height(), 75);
console.log(new_margin, hrOff.top, thOff.top);
var st = 0;
if (new_margin < 75) {
st = 75 - new_margin;
//have container scroll by this much?
}
anim.animate({
marginTop: "+=" + new_margin
}, 1000);
});​
​
http://jsfiddle.net/zYYBR/10/

How to add scroll background effect to multiple elements with different settings?

In this demo http://www.htmldrive.net/items/demo/527/Animated-background-image-with-jQuery
This code is for one background only. I want to add multiple background with different direction and speed.
var scrollSpeed = 70;
var step = 1;
var current = 0;
var imageWidth = 2247;
var headerWidth = 800;
var restartPosition = -(imageWidth - headerWidth);
function scrollBg(){
current -= step;
if (current == restartPosition){
current = 0;
}
$('#header').css("background-position",current+"px 0");
}
var init = setInterval("scrollBg()", scrollSpeed);
Currently it has settings for
$('#header').css("background-position",current+"px 0");
In a website I want to use this effect on #footer or #content background also. but with different speed and direction.
And is there any better and more optimized jquery method to achieve same effect?
And can we get same effect using CSS 3, without javascript?
Just saw the OP's answer, but decided to post anyway:
I've created a jQuery plugin to do this:
(function($) {
$.fn.scrollingBackground = function(options) {
// settings and defaults.
var settings = options || {};
var speed = settings.speed || 1;
var step = settings.step || 1;
var direction = settings.direction || 'rtl';
var animStep;
// build up a string to pass to animate:
if (direction === 'rtl') {
animStep = "-=" + step + "px";
}
else if (direction === 'ltr') {
animStep = '+=' + step + "px";
}
var element = this;
// perform the animation forever:
var animate = function() {
element.animate({
backgroundPosition: animStep + " 0px"
}, speed, animate);
};
animate();
};
})(jQuery);
Usage:
$("#header").scrollingBackground({
speed: 50,
step: 50,
direction: 'ltr'
});
This is pretty basic, and assumes that you're background-repeat is 'repeat-x' on the element you call it on. This way, there's no need to reset the background position every so often.
Working example: http://jsfiddle.net/andrewwhitaker/xmtpr/
I could work out the following solution. Am not sure if it is efficient. Will wait for anyone to comment or provide a better option.
Till then...:
var scrollSpeed = 70;
var step = 1;
var current = 0;
var images =
[
{
imageWidth:2247,
imagePath:"images/image1"
},
{
imageWidth:1200,
imagePath:"images/image2"
}
]
var headerWidth = 800;
var imageRotateCount = 0;
var imagesLength = images.length;
$('#header').css("background-image", images[0].imagePath);
function scrollBg(){
var curIndex = imageRotateCount%imagesLength;
var curImage = images[curIndex];
current -= step;
var restartPosition = -(curImage.imageWidth - headerWidth);
if (current == restartPosition){
current = 0;
imageRotateCount++;
curIndex = imageRotateCount%imagesLength;
curImage = images[curIndex];
$('#header').css("background-image", curImage.imagePath);
}
$('#header').css("background-position",current+"px 0");
}
var init = setInterval("scrollBg()", scrollSpeed);

Categories

Resources