I have the following structure of my page:
<div id="skrollr-body">
<div class="sections-container" id="sections-portrait">
<div class="section" id="section_1">
Section 1
<div class="baloon"
data-anchor-target="#section_1 .baloon"
data-center-top="bottom: -20%"
data-top="bottom: 50%"
></div>
</div>
<div class="section" id="section_2">
Section 2
</div>
<div class="section" id="section_3">
Section 3
</div>
<div class="section" id="section_4">
Section 4
</div>
</div>
<div class="sections-container" id="sections-landscape"></div>
Notice the div with class baloon. I want it to go from bottom to top (which it currently does), and after a while go a little bit down. Is it possible to do it with Skrollr.js and if it is - how?
Here's Demo CodePen DEMO
Well i haven't use Skrollr.js plugin but tried without it jQuery and Css
As Section is Shown after few second Baloon is moved from bottom to top and middle
Debounce on scroll and webtransitionend src
Function from David Walsh:
transitionEnd Callback
Debounce on wheel
debounce = function(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
// Function from David Walsh: http://davidwalsh.name/css-animation-callback
function whichTransitionEvent() {
var t,
el = document.createElement("fakeelement");
var transitions = {
"transition": "transitionend",
"OTransition": "oTransitionEnd",
"MozTransition": "transitionend",
"WebkitTransition": "webkitTransitionEnd"
}
for (t in transitions) {
if (el.style[t] !== undefined) {
return transitions[t];
}
}
}
var transitionEvent = whichTransitionEvent();
var winH = $(window).height();
$(document).ready(function() {
$('.section').height(winH);
var updateLay = debounce(function(e) {
callback(e);
}, 500);
$(window).on('wheel DOMMouseScroll', function(e) {
updateLay(e);
});
obj.textTransiton();
animLoop();
})
var globalSetting = {
y: 0,
delta: 0,
maxScroll: 0,
moved: false
}
function callback(event) {
var delta = Math.sign(event.originalEvent.wheelDelta) || -Math.sign(event.originalEvent.detail);
globalSetting.y += delta * winH;
globalSetting.delta = delta;
obj.move(obj.textTransiton);
}
function checkScrollExtents() {
if (globalSetting.y > 0) {
globalSetting.y = 0;
} else if (Math.abs(globalSetting.y) > globalSetting.maxScroll) {
globalSetting.y = -globalSetting.maxScroll;
}
}
function animLoop() {
globalSetting.maxScroll = obj.selector.height() - obj.selector.find('.section:last').height();
checkScrollExtents();
obj.scrolls();
window.requestAnimationFrame(animLoop);
}
var obj = {
'selector': $('#skrollr-body'),
'current': $('.current'),
scrolls: function() {
obj.vertical();
},
vertical: function() {
obj.selector.css('transform', 'translateY(' + globalSetting.y + 'px)');
},
textTransiton: function() {
var baloon = obj.current.find('.baloon');
baloon.css('transform', 'translateY(-' + winH + 'px)');
baloon.one(transitionEvent, function(event) {
baloon.css('transform', 'translateY(-' + (winH / 2) + 'px)');
});
},
move: function(callback) {
if (globalSetting.delta > 0) {
obj.Prev(callback);
} else {
obj.Next(callback);
}
},
Prev: function(c) {
if (obj.current.prev().length) {
var currt = obj.current.prev();
obj.updateCurrentModule(currt);
setTimeout(function() {
c();
}, 1000);
}
},
Next: function(c) {
if (obj.current.next().length) {
var currt = obj.current.next();
obj.updateCurrentModule(currt);
setTimeout(function() {
c();
}, 1000);
}
},
updateCurrentModule: function(currt) {
obj.current.removeClass('current');
obj.current.find('.baloon').css({
"-webkit-transform": "translateY(0px)"
});
currt.addClass('current');
obj.current = currt;
},
};
html,
body {
margin: 0;
overflow: hidden;
}
div {
transition: all 600ms ease-in !important;
}
.section {
position: relative;
color: white;
background-size: contain;
min-height: 100%;
white-space: nowrap;
position: relative;
min-width: 100%;
}
.baloon {
font-size: 10em;
color: #020000;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
bottom: 0px;
position: absolute;
margin: 0;
transition: all 1000ms cubic-bezier(0.32, 0.51, 0.78, 0.34) !important;
border: 1px solid;
background-color: white;
mix-blend-mode: exclusion;
width: 100%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="skrollr-body">
<div class="sections-container" id="sections-portrait">
<div class="section current" id="section_1" style="background-image: url(http://img13.deviantart.net/83ee/i/2014/145/5/e/naruto_negative_space_poster_by_jde_studios-d7jrnhc.jpg);">
<div class="baloon">
Naruto
</div>
</div>
<div class="section" id="section_2" style="background-image: url(http://www.jeffreydavidson.com.au/images/blogs/naruto-negative-space-posters/sasuke-negative-space.jpg);">
<div class="baloon">
Sasuke
</div>
</div>
<div class="section" id="section_3" style="background-image: url(https://s-media-cache-ak0.pinimg.com/736x/2f/2f/ef/2f2fefdccc4688ab3d640b65cca02d47.jpg);">
<div class="baloon">
Kakashi
</div>
</div>
<div class="section" id="section_4" style="background-image: url(http://www.jeffreydavidson.com.au/images/blogs/naruto-negative-space-posters/sakura-negative-space.jpg);">
<div class="baloon">
Sakura
</div>
</div>
</div>
<div class="sections-container" id="sections-landscape"></div>
</div>
Related
I'm trying to delay a function by using setInterval however it seems to be affecting a typewriting effect I have added to my text. The first <h1> works fine ie the typewriting effect starts from the first character of the sentence whereas the typewriting effect for the next <h2> starts from the 4th word and ignores the previous 3 words - I do believe this has to do with the milliseconds I have set on my setInterval.
var h1MessageArray = ["West Sussex Web Design"];
var h2MessageArray = ["Your down-to-earth website designer."];
var speed = 100;
var textPosition = 0;
typewriter1 = () => {
document.querySelector("#h1Message").innerHTML = h1MessageArray[0].substring(0,
textPosition) + '<span>\u25AE</span>';
if (textPosition++ != h1MessageArray[0].length) {
setTimeout("typewriter1()", speed);
}
}
window.addEventListener('load', typewriter1);
typewriter2 = () => {
document.querySelector("#h2Message").innerHTML = h2MessageArray[0].substring(0,
textPosition) + '<span>\u25AE</span>';
if (textPosition++ != h2MessageArray[0].length) {
setTimeout("typewriter2()", speed);
}
}
window.setInterval(typewriter2, 4000);
#typewriter {
width: fit-content;
margin: auto;
}
span {
animation: blinker 1s linear infinite;
}
#keyframes blinker {
50% {
opacity: 0;
}
}
#media(max-width:480px) {
#typewriter h2 {
font-size: 1rem;
}
}
<div class="container-fluid mt-5">
<div class="row">
<div class="col-12 text-center" id="typewriter">
<h1 id="h1Message"></h1>
<h2 id="h2Message"></h2>
</div>
</div>
</div>
What am I missing?
The problem is you are reusing textPosition in both functions. So the second function starts at the end of the position of the first function.
A simple solution is two different variables.
var h1MessageArray = ["West Sussex Web Design"];
var h2MessageArray = ["Your down-to-earth website designer."];
var speed = 100;
var textPosition1 = 0;
var textPosition2 = 0;
typewriter1 = () => {
document.querySelector("#h1Message").innerHTML = h1MessageArray[0].substring(0,
textPosition1) + '<span>\u25AE</span>';
if (textPosition1++ != h1MessageArray[0].length) {
setTimeout("typewriter1()", speed);
}
}
window.addEventListener('load', typewriter1);
typewriter2 = () => {
document.querySelector("#h2Message").innerHTML = h2MessageArray[0].substring(0,
textPosition2) + '<span>\u25AE</span>';
if (textPosition2++ != h2MessageArray[0].length) {
setTimeout("typewriter2()", speed);
}
}
window.setInterval(typewriter2, 4000);
#typewriter {
width: fit-content;
margin: auto;
}
span {
animation: blinker 1s linear infinite;
}
#keyframes blinker {
50% {
opacity: 0;
}
}
#media(max-width:480px) {
#typewriter h2 {
font-size: 1rem;
}
}
<div class="container-fluid mt-5">
<div class="row">
<div class="col-12 text-center" id="typewriter">
<h1 id="h1Message"></h1>
<h2 id="h2Message"></h2>
</div>
</div>
</div>
I have two or in future may be more divs with background images in css. I would like to fade them in and out in a loop.
I am trying to do something like this but it doesn`t work.
$(window).load(function(){
var divs = $('.fade');
function fade() {
var current = $('.current');
var currentIndex = divs.index(current),
nextIndex = currentIndex + 1;
if (nextIndex >= divs.length) {
nextIndex = 0;
}
var next = divs.eq(nextIndex);
next.stop().fadeIn(2000, function() {
$(this).addClass('current');
});
current.stop().fadeOut(2000, function() {
$(this).removeClass('current');
setTimeout(fade, 2500);
});
}
fade();
#one {
background-image: url("Test_bg.jpg");
margin-top: -150px;
min-height: 100%;
background-attachment: fixed;
}
#two {
background-image: url("Test_bg1.jpg");
margin-top: -150px;
min-height: 100%;
display: block;
background-attachment: fixed;
}
<div id="one" class="fade current">
</div>
<div id="two" class="fade">
</div>
You are mising }) at the end with causes syntax error
$(window).load(function(){
var divs = $('.fade');
function fade() {
var current = $('.current');
var currentIndex = divs.index(current),
nextIndex = currentIndex + 1;
if (nextIndex >= divs.length) {
nextIndex = 0;
}
var next = divs.eq(nextIndex);
next.stop().fadeIn(2000, function() {
$(this).addClass('current');
});
current.stop().fadeOut(2000, function() {
$(this).removeClass('current');
setTimeout(fade, 2500);
});
}
fade();
})
#one {
color: red
}
#two {
color: blue
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="one" class="fade current">a
</div>
<div id="two" class="fade">b
</div>
Find below image reference:
What I want exactly is when only one section (section4) comes in window view around 40% - 80%. On scroll stop the section4 should auto scroll to fit on window.
Here, The basic fiddle without any script.
body,
html {
height: 100%;
margin: 0;
}
.sections {
height: 100%;
background: #000;
opacity: 0.7;
}
#section2 {
background: #ccc;
}
#section3 {
background: #9c0;
}
#section4 {
background: #999;
}
#section4 {
background: #ddd;
}
<div class="sections" id="section1"></div>
<div class="sections" id="section2"></div>
<div class="sections" id="section3"></div>
<div class="sections" id="section4"></div>
<div class="sections" id="section5"></div>
I have tried jquery visible plugin but it didn't help. So I have put commented one.
/*
var ww = $(window).width();
$(window).scroll(function(){
if ($('#section3').visible(true)) {
$('body, html').animate({scrollTop: $('#section4').offset().top});
}else if($('#section5').visible(true)) {
$('body, html').animate({scrollTop: $('#section4').offset().top});
}
});
*/
Use script to compare the scrollTop of the screen with the offset().top and the height of the section.
Note that ratio determines how much the element is seen on the screen (greater that 0.6 is used to determine if more than 60% of the section is visible on screen).
See demo below with comments inline:
/*debouce (courtesy:underscore.js)*/
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
// scroll listener
$(window).scroll(debounce(function() {
var $window = $(window);
// change this to '.sections' if you want the effect for all sections
$('#section4').each(function() {
var top_of_element = $(this).offset().top;
var bottom_of_element = $(this).offset().top + $(this).outerHeight();
var bottom_of_screen = $window.scrollTop() + $window.height();
var top_of_screen = $window.scrollTop();
var height_of_element = $(this).outerHeight();
// if element below top of screen
if (top_of_element > top_of_screen && bottom_of_screen < bottom_of_element) {
var ratio = (bottom_of_screen - top_of_element) / height_of_element;
if (ratio > 0.6) {
// animate by scrolling up
$('body, html').animate({
scrollTop: $(this).offset().top
});
}
}
// if element above top of screen
else if (bottom_of_element > top_of_screen && bottom_of_screen > bottom_of_element) {
var ratio = (bottom_of_element - top_of_screen) / height_of_element;
if (ratio > 0.6) {
// animate by scrolling down
$('body, html').animate({
scrollTop: $(this).offset().top
});
}
}
});
}, 250));
body,
html {
height: 100%;
margin: 0;
}
.sections {
height: 100%;
background: #000;
opacity: 0.7;
}
#section2 {
background: #ccc;
}
#section3 {
background: #9c0;
}
#section4 {
background: #999;
}
#section4 {
background: #ddd;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="sections" id="section1"></div>
<div class="sections" id="section2"></div>
<div class="sections" id="section3"></div>
<div class="sections" id="section4"></div>
<div class="sections" id="section5"></div>
Basically I have a structure like this, my goal is to animate 4 divs so that when you click on one the other slide out and when you click on the container they return to their initial positions.
var TL = new TimelineMax;
$('.quater').on('click', function () {
$faders = $('.container').find('.quater').not(this),
$faders.each(function () {
TL.to($(this), 1, {autoAlpha:0, x:50}, 0);
});
});
$('.container').on('click', function () {
TL.reverse();
TL.clear();
});
The problem is that if I omit the "TL.clear();" it will work just for the first ".quater" div clicked, if i put in the "TL.clear();" the animation will not reverse anymore.
jsFiddle.
Snippet:
var container = document.querySelector('.container');
var items = document.querySelectorAll('.item');
var duration = 0.6;
var ease = Expo.easeOut;
var numItems = items.length;
var i;
container.addEventListener('click', onContainerClicked, false);
for (i = 0; i < numItems; i += 1) {
(function(index){
items[index].timeline = new TimelineMax({ paused: true });
items[index].timeline.fromTo(items[index], duration, { y: 0, autoAlpha: 0.4 }, { y: -104, autoAlpha: 1, ease: ease });
items[index].addEventListener('click', onItemClicked, false);
}(i));
}
function onContainerClicked() { reverseAll(); }
function onItemClicked(e) {
reverseAll();
e.target.timeline.play();
}
function reverseAll() {
for (i = 0; i < numItems; i += 1) { items[i].timeline.reverse(); }
}
html, body {
margin: 0;
padding: 0;
}
.container {
background: #444;
width: 512px;
height: 104px;
}
.item {
float: left;
margin: 2px 0 0 2px;
width: 100px;
height: 100px;
}
.item:nth-child(odd) { background: #0cc; }
.item:nth-child(even) { background: #cc0; }
<script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.17.0/TweenMax.min.js"></script>
<div class="container"></div>
<div class="item"> </div>
<div class="item"> </div>
<div class="item"> </div>
<div class="item"> </div>
<div class="item"> </div>
I am trying to create a music player/centre online.
I have a player that plays the music and displays the current track:
As you can see from th title of the song it is too long for the div. What i would like to do is scroll the text and reset it an rescroll etc.
I have attempted this with the below code:
html:
<div id="top-bar">
<div id="player-container">
<div id="player">
<div id="level1">
<div class="current-track"><h1><span id="title">Party All Night (Sleep All Day) -</span> Sean Kingston</h1></div>
<div class="add-to-playlist"></div>
<div class="share"></div>
</div>
<div class="clearfix"></div>
<div id="level2">
<div class="current-time">0:00</div>
<div class="progress"><span id="slider"></span></div>
<div class="total-time">3:43</div>
</div>
</div>
</div>
</div>
Jquery:
$(function() {
var scroll_text;
$('div.current-track').hover(
function() {
var $elmt = $(this);
scroll_text = setInterval(function() {
scrollText($elmt);
}, 5);
}, function() {
clearInterval(scroll_text);
$(this).find('div.current-track h1').css({
left: 0
});
});
var scrollText = function($elmt) {
var left = $elmt.find('div.current-track h1').position().left - 1;
left = -left > $elmt.find('div.current-track h1').width() ? $elmt.find('div.current-track').width() : left;
$elmt.find('div.current-track h1').css({
left: left
});
};
});
Any pointer would be appriciated
Here is a jsfiddle for you guys: JSfiddle
UPDATE
Could anybody tell me:
How to make this happen automatically? Done
How to slow the scrolling? Done
Here is the updated jsfiddle for you guys: JSfiddle
I think you are misunderstanding how jquery .find() works:
$elmt.find('div.current-track h1')
should be:
$elmt.find('h1')
http://jsfiddle.net/Dn6jx/5/
edit: updated fiddle for comments
http://jsfiddle.net/Dn6jx/15/
Added check to see if text is long enough to require scrolling, removed the clear interval, and wrapped in plugin.
JSFiddle update
$.fn.scrolltxt = function() {
var options = $.extend({
speed : 28
}, arguments[0] || {});
return this.each(function() {
var el = $(this);
if( el.find('span').width() > el.parent().width() ) {
var scroll_text = setInterval(function() {
scrollText();
}, options.speed);
};
var scrollText = function() {
var width = el.width(),
left = el.position().left - 1;
left = -left > width ? width : left;
el.css({left: left});
};
}); };
$('.current-track h1').scrolltxt();
A better way to animate the text (when the text is fully read => re-animate) :
JSFiddle update
$.fn.scrolltxt = function() {
var options = $.extend({
speed : 28
}, arguments[0] || {});
return this.each(function() {
var el = $(this);
if( el.find('span').width() > el.parent().width() ) {
var scroll_text = setInterval(function() {
scrollText();
}, options.speed);
};
var scrollText = function() {
var width = el.find('span').width(),
left = el.position().left - 1;
left = -left > width ? el.width() : left;
el.css({left: left});
};
});
};
$(function() {
$('.current-track h1').scrolltxt();
});
I improved the answer of Holiday Mat a bit.
If you want to replace the text with other text dynamically (which is not too long), the scrolling will still keeps place. You have to reset the interval somehow.
Another problem you might run into is, too many intervals are set and the text scrolls faster and faster.
Here a snippet which shows how I handled this. (I used h5 instead of h1, which you probably use somewhere else.) :
$.fn.scrolltxt = function() {
var options = $.extend({
speed: 28
}, arguments[0] || {});
return this.each(function() {
var $h5 = $(this);
var containerWidth = $h5.parent().width();
var textWidth = $h5.find('span').width();
var refreshIntervalId;
if (textWidth > containerWidth) {
refreshIntervalId = setInterval(function() {
scrollText();
}, options.speed);
$h5.data('refreshIntervalId', refreshIntervalId);
} else {
refreshIntervalId = $h5.data('refreshIntervalId');
if (refreshIntervalId != undefined) {
window.clearInterval(refreshIntervalId);
$h5.removeData('refreshIntervalId');
}
}
var scrollText = function() {
var textWidth = $h5.find('span').width();
var left = $h5.position().left - 1;
left = -left > textWidth ? $h5.width() : left;
$h5.css({
left: left
});
};
});
};
$('h5.scroll').scrolltxt();
#player {
width: 500px;
background: #000;
border: 1px solid #1f1f1f;
border-radius: 10px;
margin: 10px;
padding: 10px 20px;
}
.current-track {
height: 100%;
background: #333;
color: #FFF;
margin-right: 5px;
width: 100%;
font-size: 150%;
border-radius: 5px;
line-height: 30px;
overflow: hidden;
position: relative;
}
.current-track h5 {
position: relative;
white-space: nowrap;
line-height: 1.5em;
font-size: 1.5em;
}
* {
margin: 0;
padding: 0;
}
body {
font-family: Arial, Helvetica, sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="player">
<div id="level1">
<div class="current-track">
<h5 class="scroll"><span><strong>KAFKA (The artist formerly known as Prince)</strong></span></h5>
</div>
<br /><br /><br />
<div class="current-track">
<h5 class="scroll"><span>The Most Beautiful Girl In The World (original 1995 version)</span></h5>
</div>
</div>
</div>
Or see the CodePen: https://codepen.io/r-w-c/pen/dyKoKQX