I have a chart made using d3.js:
Code for chart
I have put this chart within a website.
website
Problem is that in the above website, when you scroll through the page to the "teamchart" section, I don't see the effect of the chart. When you refresh the page, you can see the chart role the effect.
I want the chart to role and show the effect, when I reach that section of the page or when I use the nav bar, click "teamchart" and reach that section.
I used the below JavaScript code, but it's repeating it continuously:
$(document).scroll(function() {
//Basically your position in the page
var x = $(this).scrollTop();
//How far down (in pixels) you want the user to be when the effect to starts, eg. 500
var y = 500;
if (x > y) {
//Put your effect functions in here.
}
});
Fiddle related to the website:
My code related to website (experiment here)
As i understand, your problem is the part where the animation keeps playing.
this is because every time you scroll the page, to a value greater then 500, you actually repeating your code.
Easy solution: place a flag to signal 'alreadyAnimated'
var g_pieChartAnimated=false;
$(document).scroll(function() {
//Basically your position in the page
var x = $(this).scrollTop();
//How far down (in pixels) you want the user to be when the effect to starts, eg. 500
var y = 500;
if (!g_pieChartAnimated && (x > y)) {
g_pieChartAnimated = true;
//Put your effect functions in here.
}
});
Second solution (bit faster):
is to detach the event handler once it did what you want.
function onScroll_AnimateChart() {
//Basically your position in the page
var x = $(this).scrollTop();
//How far down (in pixels) you want the user to be when the effect to starts, eg. 500
var y = 500;
if (!g_pieChartAnimated && (x > y)) {
$(document).off('scroll', onScroll_AnimateChart); // remove myself from the event handlers, so it won't be called again.
//Put your effect functions in here.
}
}
$(document).on('scroll', onScroll_AnimateChart);
Edit
I missed where you said the animation was repeating - #Tomer W solution is correct.
Similar to what #Tomer W posted, but run the chart function (or the chart the whatever function triggers the animation) in your scroll handler:
var chartInit = false;
var handler = function() {
var y = 500;
var x = $(this).scrollTop();
if (x > y && !charInit) {
charInit = true;
someD3ChartStuff();
}
};
$(document).scroll(handler);
I have the 2 following solutions for your issue, hope it helps!
1 - Pure css + jQuery solution
$(window).on('scroll' , function(){
scroll_pos = $(window).scrollTop() + $(window).height();
element_pos = $(".chart-wrapper").offset().top + $(".chart-wrapper").height() ;
if (scroll_pos > element_pos) {
$(".chart-wrapper").addClass('animation');
};
})
and after that manipulate your animation in the class animation
2- Wow.JS Library
1- Download the script here
2- Download the animate.css here
3- Use this snippet as example and understand how it works
<script src="http://mynameismatthieu.com/WOW/dist/wow.min.js"></script>
<link rel="stylesheet" href="css/animate.css">
<script>
new WOW().init();
</script>
<div class="wow bounceInLeft animated">
<h2>animated heading</h2>
</div>
Obs.: There's a bunch of animations that you can use with this library + animate.css just use any of the classes below and put the class wow also
Here's the list
bounce
flash
pulse
rubberBand
shake
headShake
swing
tada
wobble
jello
bounceIn
bounceInDown
bounceInLeft
bounceInRight
bounceInUp
bounceOut
bounceOutDown
bounceOutLeft
bounceOutRight
bounceOutUp
fadeIn
fadeInDown
fadeInDownBig
fadeInLeft
fadeInLeftBig
fadeInRight
fadeInRightBig
fadeInUp
fadeInUpBig
fadeOut
fadeOutDown
fadeOutDownBig
fadeOutLeft
fadeOutLeftBig
fadeOutRight
fadeOutRightBig
fadeOutUp
fadeOutUpBig
flipInX
flipInY
flipOutX
flipOutY
lightSpeedIn
lightSpeedOut
rotateIn
rotateInDownLeft
rotateInDownRight
rotateInUpLeft
rotateInUpRight
rotateOut
rotateOutDownLeft
rotateOutDownRight
rotateOutUpLeft
rotateOutUpRight
hinge
rollIn
rollOut
zoomIn
zoomInDown
zoomInLeft
zoomInRight
zoomInUp
zoomOut
zoomOutDown
zoomOutLeft
zoomOutRight
zoomOutUp
slideInDown
slideInLeft
slideInRight
slideInUp
slideOutDown
slideOutLeft
slideOutRight
slideOutUp
Related
I'm trying to make a certain image move from top of the document to it's bottom depending on the scroll percentage, for example, when you load the site, the image will be on top of the page and as the user scrolls down it'll go down little by little depending on the overall document percentage, until at 100% it's at the bottom.
I've went through lots of similar solutions on stackoverflow and other sites, but only two seemed close to being what I need.
The first works but only on one resolution which is manually adjusted in the code:
var imgscroll = document.getElementById('myimg');
window.addEventListener('scroll', function() {
var scrollposition = window.scrollY;
imgscroll.style.top = scrollposition * 0.1323 + 'vh';
}
The second is from a stackoverflow answer - located here and copied below - I think the percentage part is what I need, but couldn't make it work (the image stopped moving):
var container = document.getElementById('container');
var windowHeight = window.innerHeight;
var windowWidth = window.innerWidth;
var scrollArea = 1000 - windowHeight;
var square1 = document.getElementsByClassName('square')[0];
var square2 = document.getElementsByClassName('square')[1];
// update position of square 1 and square 2 when scroll event fires.
window.addEventListener('scroll', function() {
var scrollTop = window.pageYOffset || window.scrollTop;
var scrollPercent = scrollTop/scrollArea || 0;
square1.style.left = scrollPercent*window.innerWidth + 'px';
square2.style.left = 800 - scrollPercent*window.innerWidth*0.6 + 'px';
});
I'd appreciate any help or tips on how to reach the answer.
Personally I find the approach where you control the position of the image by using animation-play-state: paused and assigning a CSS variable to the animation-delay one of the neatest bit of scripts I ever saw on the web. Here's the pen by Chris Coyier it's based on. And a quote from his website that describes the mechanism:
A positive animation delay is where the animation waits a certain amount of time to begin. A negative animation delay starts the animation immediately, as if that amount of time has already gone by. In other words, start the animation at a state further into the animation cycle.
When the window has loaded, we first calculate the available space below the image and the amount of page overflow. The first CSS variable --maximum defines the end point of the animation. This is recalculated when the user resizes the screen. Then when scrolling, the ratio of progress is set through another CSS variable --epoch that controls the timing of the keyframe animation.
let aim = document.getElementById('image'), room, overflow;
window.addEventListener('load', setEdge);
window.addEventListener('resize', setEdge);
window.addEventListener('scroll', function() {
let ratio = (this.pageYOffset || this.scrollY)/overflow;
aim.style.setProperty('--epoch', ratio);
});
function setEdge() {
room = window.innerHeight;
overflow = document.body.scrollHeight-room;
aim.style.setProperty('--maximum', room-aim.height + 'px');
}
body {
margin: 0;
height: 700vh;
}
#image {
position: fixed;
animation-duration: 1s;
animation-timing-function: linear;
animation-play-state: paused;
animation-iteration-count: 1;
animation-fill-mode: both;
animation-name: move;
animation-delay: calc(var(--epoch) * -1s);
}
#-webkit-keyframes move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(var(--maximum));
}
}
#keyframes move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(var(--maximum));
}
}
<img id="image" src="https://via.placeholder.com/140x100" alt="">
For those that want to play around with it: https://jsfiddle.net/z2r40y8c/
I have a div:
<div class="coverImage" style="background-image:url('3.2.5\\assets\\img\\backgroundCanvas1.jpg');"></div>
and an attached jQuery script to rotate its background every 20 seconds
var coverChange =
{
init: function()
{
var itemInterval = 20000;
var numberOfItems = 4;
var currentItem = 1;
$('.coverImage').attr("style", "background-image:url('3.2.5/assets/img/backgroundCanvas"+currentItem+".jpg'");
//loop through the items
var infiniteLoop = setInterval(function(){
$('.coverImage').attr("style", "background-image:url()");
if(currentItem == numberOfItems -1){
currentItem = 1;
}else{
currentItem++;
}
$('.coverImage').attr("style", "background-image:url('3.2.5/assets/img/backgroundCanvas"+currentItem+".jpg'");
}, itemInterval);
}
};
coverChange.init();
When the image changes it happens to white out the bottom half until I scroll slightly. My main ask is help with a fadeIn of the new image. (everything else is secondary)
I have experimented using the jQuery fadeIn property but cannot get it to work in a seamless aesthetically pleasing way.
I am not looking for code elegance only function, as you can tell :-)
P.S Loading the image initially via CSS did not work.
You should be able to add a simple CSS transition to your coverImage element.
.coverImage {
transition: background 1s;
}
I've created a working example at https://jsfiddle.net/mark_c/pa44n42k/1/
For a fade in out effect, you should simply fade out the div before this step:
$('.coverImage').attr("style", "background-image:url()");
and fade it in after this step:
$('.coverImage').attr("style", "background-image:url('3.2.5/assets/img/backgroundCanvas"+currentItem+".jpg'");
For fade in out you can use simple jquery as I suppose you already have but not the right way, so good luck.
This will give you a nice fade in/out effect. :)
I have a fixed .widget element that remains visible at all times. Currently however, it scrolls over the footer area. My goal is to stop the widget before it hits the footer.
CSS
.widget {
position:fixed;
height:450px;
width:300px;
}
footer {
height:450px;
width:100%;
}
My route I'm taking is currently:
jQuery
var $bodyheight = $('body').height();
var $footerheight = $('footer').height();
var $widgetheight = $('.game_widget').height();
var $pageheight = $bodyheight - $footerheight - $widgetheight;
$(window).on('scroll', function() {
console.log($(this).scrollTop())
});
My next step would be to loop through to see if scrollTop > $pageheight then update some CSS.
Is this the best way of going about this? Is there a cleaner/simpler way to achieve the same result?
I have managed to solve this quite simply. Inside the scroll function I set 2 variables, one for the position of the fixed element, the other for the position of the footer. These return the exact value from how far the top of the element is from the top of the page. For the fixed element I need to know the distance to the bottom of this element so I also include the height.
var $fixedpos = $(".game_widget").offset().top + $('.game_widget').height();
var $footerpos = $("footer").offset().top - 25; // 25 accounts for margin
Using a simple if/else the CSS is updated to display none/initial depending on whether $fixedpos > $footerpos (i.e. the fixed element is overlapping the footer).
if ($fixedpos > $footerpos) {
$('.game_widget').css('display','none');
} else {
$('.game_widget').css('display','initial');
}
This works, however there is a 'flicking' effect as the fixed element overlaps the footer. This is due to the function executing extremely rapidly. The solution to the flicker is to use this simple 'throttling' plugin that adds a short delay (of your choice) between each execution of a function - http://benalman.com/projects/jquery-throttle-debounce-plugin/
You then just need to bind the on scroll function to the throttle:
function scrolling() {
console.log($(".game_widget").offset().top + $('.game_widget').height());
console.log($("footer").offset().top - 25);
var $fixedpos = $(".game_widget").offset().top + $('.game_widget').height();
var $footerpos = $("footer").offset().top - 25;
if ($fixedpos > $footerpos) {
$('.game_widget').css('display', 'none');
} else {
$('.game_widget').css('display', 'initial');
}
};
$(window).on('scroll', $.throttle(250, scrolling)); // 250ms between executing the function
});
This 250ms delay stops the function from executing so rapidly that the flickering effect occurs.
Hope this helps others trying to solve this problem.
I'm currently working on an iPad JS/HTML app, using native scrolling to view a large bar chart svg.
I'm looking to have the labeling along the x and y axes persist along the top and left of the graph. Basically, the graph should slide around freely underneath the labels, which themselves will only move in the appropriate direction (eg, the x axis header will shift its labels over as you scroll left, and the y axes labelings for vertical scrolling)
I currently have some css to do this, but the native scrolling moves a lot faster than my javascript to sync the panels up. There's sort of this elastic interplay as one element is dragged faster than the other. It all plops into the correct place once the scroll animation stops, but the interaction looks pretty janky when scrolling is going on.
Is there a better way to tackle this problem? Are their other events I could tap into? Is there a way to force multiple scrollable divs to react to the same scroll event without manual js position calculations? Or is the lag unavoidable due to native scrolling being offloaded to the gpu?
/* CSS */
.fixedaxis {
position:absolute;
top: 0px;
left: 0px;
background: blue;
}
#chartheader {
z-index:5;
}
#sidebar {
z-index:6;
}
.scroll {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
/* relevant html */
<div id="content" style="position: relative;">
<div id="chartheader" class="fixedaxis"></div>
<div id="sidebar" class="fixedaxis"></div>
<div class="scroll">
<section id="barchart">
</section>
</div>
</div>
/*javascript */
var scroller = $('.scroll');
var tableHeader = $('#chartheader');
var sidebar = $('#sidebar');
scroller.on('scroll', function() {
console.log("scrolling: " + this.scrollLeft);
tableHeader.css('left', (-1 * this.scrollLeft) + 'px');
sidebar.css('top', (-1 * this.scrollTop) + 'px');
});
So it turns out, you can't. At least, not at this point in time.
According to the Apple Developer docs
https://developer.apple.com/library/ios/#documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html
You receive events for scroll when the user's finger is on the screen, and one final scroll event once momentum stops. If the content is gliding around between those two periods, you receive no events.
What we ended up doing is making the sidebar content semi-transparent on the second scroll event, and then making it opaque again after a timeout, with an allowance for repositioning if a single "momentum-end" scroll event fired again.
Something along the lines of:
var lastTimeout;
var numScrolls = 1;
var startTop = 0;
function(event) {
var elem = event.target;
startTop = startTop || elem.scrollTop;
if (lastTimeout) {
clearTimeout(lastTimeout);
} else if (numScrolls == -1) {
/* I've omitted some short circuit logic for other scrolling cases
* but that's why we're going off of -1 here
*/
// stray scroll from native scroll end
$labels[0].scrollTop = elem.scrollTop;
$labels.css('opacity', '1');
startTop = null;
}
// wait for two consecutive scrolls
if (numScrolls > 0) {
$labels.css('opacity', '0.3');
}
++numScrolls;
lastTimeout = setTimeout(function() {
console.log(elem.scrollTop);
$labels[0].scrollTop = elem.scrollTop;
$labels.css('opacity', '1');
lastTimeout = null;
numScrolls = -1;
startTop = null;
}, 1000);
};
I'm curious how I can create a DIV (or anything really) that I can fade (or change opacity of) when a user scrolls down the page. This DIV would sit at the top of the page, but only be clearly visible when at the very top of the page.
Additionally, it would be ideal if I I could have this element fade back in onmouseover, regardless of the current scrolled position on the page.
jQuery would allow for a succinct solution, whilst hiding most browser discrepancies. Here's a quick mock-up to get you started:
<script type="text/javascript">
//when the DOM has loaded
$(document).ready(function() {
//attach some code to the scroll event of the window object
//or whatever element(s) see http://docs.jquery.com/Selectors
$(window).scroll(function () {
var height = $('body').height();
var scrollTop = $('body').scrollTop();
var opacity = 1;
// do some math here, by placing some condition or formula
if(scrollTop > 400) {
opacity = 0.5;
}
//set the opacity of div id="someDivId"
$('#someDivId').css('opacity', opacity);
});
});
</script>
See also:
jQuery
Selectors
CSS
Events/Scroll
CSS/ScrollTop
CSS/ScrollLeft
I thought I would give it a go using the actual value of scrollTop to dictate the opacity level, thus getting a smooth fade. I also added the hover state for the second part. Thanks to David for refining the maths for me.
//reduce the opacity of the banner if the page is scrolled.
$(window).scroll(function () {
var height = $("body").height();
var scrollTop = $("body").scrollTop();
var opacity = 1;
if(scrollTop < 41)
{opacity = 1-Math.floor(scrollTop)/100;}
else
{opacity = 0.6;}
$("#header").css("opacity", opacity);
$("#header").hover(function(){
$(this).css("opacity", 1);
},function(){
$(this).css("opacity", 0.6);
});
});
Use scroll event, and analyse value of document.documentElement.scrollTop to set appropriated opacity.
http://www.quirksmode.org/dom/events/scroll.html