How to deal with css animations on tab change - javascript

I'm developing a little roulette game like: https://csgofast.com/
My question is, the roulette animation used with transform & transition, works pretty well when I'm in the actual tab.
The problem is, when i move to another tab or miniminize, before the roullete starts, until i dont get back to the tab, it dosnt start scrolling / moving.
Is like the roullete animation is waiting until i get to the tab again, to start moving.
let intervalJackpot = setInterval(() => {
if (something == true) {
$("#slider").css('transform', 'translate3d(-7850px, 0px, 0px)');
$("#slider").css('transition', '15000ms cubic-bezier(0.32, 0.64, 0.45, 1)');
}
}, 500);
The code is in a setInterval, and that's the problem as i know.
The DB.roulleteSpin is just a simple code that comes from the Database.
How I could approach this situation? I will like to know the roulette starts moving and ends in the right place, no matters if I'm in the tab or not.
How i could approach this situation? Can someone show me an example? Thanks a lot.

Related

Web audio api: smooth transitions between audio fades in/out

I have a 3d space with different zones, each zone has its own sounds. My goal is to have smooth audio transitions when the user moves from one zone to another, basically doing cross-fades between the audio tracks.
Also I would like to handle gracefully the case when the user changes its mind and abruptly goes back to the zone just left, this means cancel the new audio transitions and revert back to the previous state gradually.
To do this I am using web audio api, in particular linearRampToValueAtTime and cancelScheduledValues to define the fades in/out functions:
const fadeIn = (sound, time = 4, gain = 1.0) => {
sound.gainNode.gain.cancelScheduledValues(sound.context.currentTime)
!sound.isPlaying && sound.play()
sound.gainNode.gain.linearRampToValueAtTime(gain, sound.context.currentTime + time)
}
const fadeOut = (sound, time = 4, gain = 0.0) => {
sound.gainNode.gain.cancelScheduledValues(sound.context.currentTime)
sound.gainNode.gain.linearRampToValueAtTime(gain, sound.context.currentTime + time)
}
I am testing this on just one sound, pressing key "I" triggers fadeIn and key "O" triggers fadeOut:
document.addEventListener("keyup", e => {
switch (e.keyCode) {
// I key
case 73:
fadeIn(mySound)
break
// O key
case 79:
fadeOut(mySound)
break
})
I got inconsistent results. Sometimes the audio fades correctly, other times it starts abruptly in the fadeIn or cut in the fadeOut. It seems like calling cancelScheduledValues when a transition has not been completed results in an erratic behaviour. I would like this to work smoothly even when triggering a fadeOut when a fadeIn has not completed yet and viceversa. I have also tried to defer a bit the linearRamps with setTimeout, something like
setTimeout(() => sound.gainNode.gain.linearRampToValueAtTime(gain, sound.context.currentTime + time), 0.1)
but got equally wrong results.
Am I using the api incorrectly? Any suggestion?
I think what's happening here is that, say, you're fading in and you haven't finished the ramp yet. Then you want a fade out, and cancel the events, including the unfinished fade-in ramp. Then that fade-in ramp is gone, and the timeline value reverts back to the value of the previous event.
So, as HankMoody suggests, use cancelAndHoldAtTime which is meant to handle this problem. But, AFAIK, only Chrome has this.
To be portable, I think what you want to do is compute where the ramp is at the time you want to cancel. Let's say the value is v. Then do
setValueAtTime(v, context.currentTime);
cancelScheduledValues(context.currentTime + eps);
where eps is some small value around 1/context.sampleRate or more.

JavaScript scroll based animation is choppy on mobile

I have 2 divs (left and right) and i want to scroll the left based on the right.
https://jsfiddle.net/3jdsazhg/2/
This works fine on desktop, but when i change to mobile, it's not smooth anymore...
This can be noticed very easily, by changing
_left.style.top = _content.scrollTop - (_content.scrollTop * ratioLeftRight) + 'px';
to
_left.style.top = _content.scrollTop + 'px';
Where it should act as a fixed positioned div
I would like to know the exact reason why this isn't smooth... I know that it's not the animation. Simple animation on the div is smooth, the issue comes up when it's based on scroll.
How can i make this animation smooth?
It's probably choppy because it's being fired ALOT when being scrolled, in fact i'm pretty sure IOS mobile pauses the javascript execution whilst the user is scrolling.
Instead I'd suggest using an interval, you could tweak the time between each interval to what feels good for your use-case.
Although it may seem intensive that it's firing this logic every X millisecond when using the scroll event you could be firing the event off hundreds of times per second, which is going to be far more intensive and noticeable to a user using a device with limit processing power.
(function () {
var interval = null,
//Currently set at 0.4 seconds, play with the code
//and change this value to see what works best for
//this use-case
time_between_interval = 400;
setInterval(scrollLogic, time_between_interval);
function scrollLogic () {
//The function body of what you're assigning
//to the scroll event.
}
//I have omitted clearing the interval but you would want to do that, perhaps on page change, or something.
//clearInterval(interval);
})();
I finally managed to think out a solution.
From my point of view, i'm guessing the mobile view fires the scroll event less often and because we are scrolling the wrapper, we first scroll the whole page and then scroll back with js the left part and because it's different from the desktop version, this issue becomes visible...
The solution was to change the left side to fixed position, and substract from the top instead of adding to it.
_left.style.top = -(_content.scrollTop * ratioLeftRight) + 'px';

Animating SVG elements with GSAP

I am tasked with creating an interactive SVG infographic with few slides for a browser game, it has 5 steps total. When you click prev / next buttons or a specific step, the whole svg should animate itself to the correct step.
In terms of code, this is what I have:
function Slide() {
// Cache all top-level svg elements for later use
this.el = $('svg#betfair-slider');
this.hands = this.el.find('#hands_8_');
this.cardsDesk = this.el.find('g#center-cards');
this.textContainer = $('.step-text');
// Use a shared timeline across all slides, so there are no overlapping tweens
this.tween = new TimelineLite();
}
function Slide2 () {
// Inherit from the main slide
Slide.call(this);
// each slide has its own supporting explanatory text
this.html = [
'<h3>Preflop</h3>',
'<p>Amet sit lorem ipsum dolar</p>'
].join('');
// the main openslide method
this.openSlide = function() {
// find the cards that need to be animated for this specific slide
var cards = this.hands.find('.card');
// fade out each card
this.tween.staggerTo(cards, 0.2, { opacity: 0 }, 0.2);
// Render supporting text
this.textContainer.html(this.html);
};
}
Here are the cards I am trying to get:
I am able to fetch them using the this.hands.find('.card'); jquery method (I can see them in the console), but I just can't animate them. I have tried animating different attributes (opacity, x, y, left, etc), but nothing happens - nothing moves on the screen.
I am able to do this.hands.find('.card').hide() and change the css using jQuery, but why TimelineLite doesn't work here? I also tried this approach:
var cards = this.hands.find('.card');
for (var i = cards.length - 1; i >= 0; i -= 1) {
var card = cards[i];
this.tween.to(card, 0.2, { opacity: 0 });
}
But still no success... The interesting thing is that when I attach an onComplete callback on the tweens, THEY ARE fired, but absolutely nothing moves on the screen. You can check out everything here.
Thanks for the help in advance, any suggestions are more then welcome.
I think you might be misunderstanding how timelines work (or perhaps I'm misunderstanding your intent). Like all tweens, timelines start playing immediately by default. So if you're using one timeline and shoving all your tweens in there based on user interaction (meaning time elapses between when you create it and when you populate it...and populate it more...), its playhead will already have advanced. I bet that's causing your tweens to jump to their end state almost immediately. That's not a bug - it's how things are supposed to work, although there's some logic in GSAP to adjust behavior in certain circumstances to make it more intuitive.
I see several options:
Just use TweenMax instead of a TimelineLite. Like TweenMax.staggerTo(...) and TweenMax.to(...).
Or just create a TimelineLite for each user interaction (instead of one for ALL of your tweens globally). That way you'll populate it right away and it'll play as you expected.
You could use one global timeline if you really want to, but you might just need to manage its playhead if you're going to be inserting tweens on each user interaction rather than all at once.
If you're still having trouble, don't hesitate to post in the GSAP-dedicated forums at http://greensock.com/forums/ and it's be super helpful if you included a codepen or jsfiddle reduced test case so that we can tinker and very quickly see what's going on and how the changes affect the result.
Happy tweening!

Slide Element Off Screen -- Wait --- Slide Back in place

I want to slide an image (of a boomerang) off screen and then 5 seconds later slide it back into place. I want the image to right next to some text to begin with and end.
Ideally I'd like the animation to be smooth. I can find many examples doing things like this, but none that seem to do this very simple thing. Any pointers in the right direction would be greatly appreciated.
$(document).ready(function()
{
var my_div = $("#target");
var div_top = my_div.offset().top;
$(document).scroll(function()
{
if (div_top <= $(document).scrollTop()+($(window).height() /2))
{
// EVENT TO SEND IMAGE OFF SCREEN TO THE RIGHT
// EVENT TO WAIT 5 SECONDS
// EVENT TO SEND THE IMAGE BACK
}
});
});
<div id="target;">
<p style="font-size:32px; display: inline;">TEXT</p>
<img id="foo" style="height:35px;" src="https://upload.wikimedia.org/wikipedia/commons/4/46/Ic_account_box_48px.svgg">
You've tagged the question with javascript and provide code that's an incomplete javascript solution, but you also mention you want it to be smooth.
Perhaps declaring a CSS animation using transforms would be better?
Check out https://daneden.github.io/animate.css/ for some examples of what a CSS animation can do. And they can be quite complex, as you can define as many steps as needed.
Now if in some of your animation steps you need to perform calculations, you're stuck with JS, but you can still use a library that uses CSS transitions under the hood get get a smooth frame-rate.
I've used move.js for such a task in the past, and worked pretty well.
https://visionmedia.github.io/move.js/

Control sprite animation speed

How can I control the animation speed of a sprite using create JS?
When you press right and left, the sprite will run through the frames... I'd like to leave the fps at 60, but alter how fast the frames are looped through without altering the main game FPS rate.
See a demo here. Press right and left arrow to see.
I thought changing the bmp animation frequency property would do the trick...
bmpAnimation.frequency = 2;
But it did not work...
Or should I be using the jQuery animation?
Also, I noticed that each time I hit a random key, the animation plays 1 frame then goes back to first frame. Why is that?
Thanks!
1) The frequency is a property of the spriteSheet-animation, not the bitmapAnimation itself.
So you would have to set the freuqency in the SpriteSheetData itself(http://www.createjs.com/Docs/EaselJS/classes/SpriteSheet.html) or if you want to set it during runtime you could use:
bmpAnimation.spriteSheet.getAnimation("walk_right").frequency = 2;
Please also note that the frequency will be deprecated in the next version of EaselJS in favor of speed (bit this is in the NEXT version, so just something for you to keep in mind)
2) You are currently calling the gotoAndPlay() every frame (if walking), that means that every frame your animation will be set to the first frame of that animation, you could easily avoid this by using something like:
if ( dir == "right" and bmpAnimation.currentAnimation != "walk_right" ) {
bmpAnimation.gotoAndPlay("walk_right");
}
But a better way would be to only call that method ONCE when you start walking and then again when you stop walking.

Categories