AnimeJS animation takes config from initial click - javascript

I implemented a Staggered Grid in React using AnimeJS, with 2 variants, defined as
export const SimpleAnimationConfig: AnimeParams = {
backgroundColor: COLORS[Math.floor(Math.random() * COLORS.length)],
scale: [
{ value: 0.1, easing: "easeOutSine", duration: 500 },
{ value: 1, easing: "easeInOutQuad", duration: 1200 },
],
};
export const CoolerAnimationConfig: AnimeParams = {
scale: [
{ value: 0.1, easing: "easeOutSine", duration: 500 },
{ value: 1, easing: "easeInOutQuad", duration: 1200 },
],
};
(and some other properties defined in CSS)
and using them as
async function onClickTile(index: number) {
const animationConfig = getAnimationConfig(isCooler);
animation.current = anime({
targets: ".tile",
delay: anime.stagger(50, { grid: [columns, rows], from: index }),
...animationConfig,
});
}
where animation is
const animation = useRef<AnimeInstance>();
and getAnimationConfig is
export function getAnimationConfig(isCooler: boolean): AnimeParams {
if (isCooler) {
return CoolerAnimationConfig;
}
return SimpleAnimationConfig;
}
Problem
Let say I clicked on a tile with index 50, it will start a staggered animation from the div with index 50 , Every subsequent animation I trigger from any other div located at any other index will however start from 50.
I console logged index, it shows the right value ,
I console logged the whole object that I am passing inside anime , it shows the correct value for fromIndex in the scope of function delay.
I did resolve the issue with
function onClickTile(index: number) {
animation.current = anime({
targets: ".tile",
delay: anime.stagger(50, { grid: [columns, rows], from: index }),
scale: [
{ value: 0.1, easing: "easeOutSine", duration: 500 },
{ value: 1, easing: "easeInOutQuad", duration: 1200 },
],
...(!isCooler && {
backgroundColor: COLORS[Math.floor(Math.random() * COLORS.length)],
}),
});
}
but still curious what was happening with separate objects, since using separate constants and helpers seems a much cleaner way than this.
DEMO

Related

How to exit a method in Phaser3 only when the played timeline is finished?

I'm quite new in Phaser, but I've already done a bunch of ionic/angular app.
One of my object has a method that will be called by the main scene:
powerOff() {
let easing = 'Cubic'
let overallDuration = 500
let visiblePauseDuration = 100
let flashDuration = overallDuration - visiblePauseDuration / 2
this.scene.tweens.timeline({
tweens: [
{
targets: this,
duration: 0,
tint: 0xff0000,
ease: easing,
},
{
targets: this,
duration: flashDuration,
tint: 0xffffff,
ease: easing,
},
{
targets: this,
duration: visiblePauseDuration,
tint: 0xff0000,
ease: easing,
},
{
targets: this,
duration: flashDuration,
tint: 0xffffff,
ease: easing,
},
{
targets: this,
duration: visiblePauseDuration,
tint: 0xff0000,
ease: easing,
onComplete: () => {
this.scene.sound.play(MainScene.POWER_DOWN)
},
},
{
targets: this,
duration: flashDuration,
tint: 0xf54242,
ease: easing,
},
],
})
this.poweredUp = false
}
The thing is: I need to exit this method only when the timeline has completed.
Is there some await/async support? Or at least promises ?
The scene will call this method on a lot of different objects, and I need that they are not done in parallel but sequentially.
Thanks a lot!!!
var timeline = this.scene.tweens.timeline({
/*TWEENS*/
})
//Timeline complete event listener
timeline.addListener("complete", function(){
//Do something when tweens are complete
}, this);

How to fix this? GSAP animation for Page transition work perfectly only the first time

I`m using barba.js with Gsap.
The idea is to have a transition from the home page and the about page with a centered logo animation, very simple. I click on my button, the transition comes in, the logo scale from 0 to 1, and go down fading, great!
The first animation works as it should but when I clicked again the scale factor is now missing, unfortunately.
How can I fix this to make it work? have a look at my code pen project:
https://codepen.io/cat999/project/editor/AEeEdg
Here my JS
function delay(n) {
n = n || 2000;
return new Promise((done) => {
setTimeout(() => {
done();
}, n);
});
}
function pageTransition() {
var tl = gsap.timeline();
tl.to(".loading-screen", {
duration: 1,
width: "100%",
left: "0%",
ease: "Expo.easeInOut",
});
tl.to("#svg-1", {
duration: 1, opacity: 0, y: 30, stagger: 0.4, delay: 0.2,
});
tl.to(".loading-screen", {
duration: 1,
width: "100%",
left: "100%",
ease: "Expo.easeInOut",
delay: 0.3,
});
tl.set(".loading-screen", { left: "-100%", });
tl.set("#svg-1", { opacity: 1, y: 0 });
}
function contentAnimation() {
var tl = gsap.timeline();
tl.from(".animate-this", { duration: 1, y: 30, opacity: 0, stagger: 0.4, delay: 0.2 });
}
$(function () {
barba.init({
sync: true,
transitions: [
{
async leave(data) {
const done = this.async();
pageTransition();
await delay(2000);
done();
},
async enter(data) {
contentAnimation();
},
async once(data) {
contentAnimation();
},
},
],
});
});

How can I better manage using GSAP animations in Nuxt.js?

I am building a portfolio page using nuxt.js and Green Sock(GSAP) animation for on-load, menu, and page transitions. It is more difficult to accommodate GSAP than using CSS based transitions but I feel the results are worth it.
I am not using webpack and nuxt correctly to make everything more modular and concise. I need some help to better export variables and functions, use Vue.js reactive properties better, and take advantage of what's already available instead of working against it.
My default.vue file has a method that manages the menu:
showMenu() {
if (process.browser) {
var tl = new TimelineMax();
var slide = document.querySelector("#slide-menu");
var pl = document.querySelector("body");
var nl = document.querySelectorAll(".nav-link");
if (this.$store.state.menuIsActive === false) {
tl
.to(slide, 0.5, {
y: "100%",
ease: this.$store.state.animParams.ease
})
.staggerTo(
nl,
this.$store.state.animParams.dur3,
{
y: "-10px",
autoAlpha: 1,
ease: this.$store.state.animParams.ease
},
this.$store.state.animParams.dur2
);
} else if (this.$store.state.menuIsActive === true) {
console.log("true");
tl
.staggerTo(
nl,
this.$store.state.animParams.dur3,
{
y: "10px",
autoAlpha: 0,
ease: this.$store.state.animParams.ease
},
this.$store.state.animParams.dur2
)
.to(slide, 0.5, {
y: "-100%",
ease: this.$store.state.animParams.ease
});
}
this.$store.commit("toggleMenuState");
}
}
I have a menu.js middleware that closes the menu when open. I would prefer to use the same variable but redeclare it instead:
import TweenMax from 'gsap'
export default function ({ store }) {
if (store.state.menuIsActive === !false) {
if (process.browser) {
var tl = new TimelineMax()
var slide = document.querySelector('#slide-menu')
var nl = document.querySelectorAll('.nav-link')
if (store.state.menuIsActive === true) {
console.log('initmenu')
tl
.staggerTo(
nl,
store.state.animParams.dur3,
{ y: '10px', autoAlpha: 0, ease: store.state.animParams.ease },
store.state.animParams.dur2
)
.to(slide, 0.5, { y: '-100%', ease: store.state.animParams.ease })
store.commit('setMenuState', false)
}
}
}
}
I duplicated the page transition because I couldn't get it working correctly in my nuxt.config.js. I would like to keep all of my transitions there or in a separate plugins file maybe but am not sure the best way to do so.
From my root index.vue page file:
import TweenMax from "gsap";
export default {
transition: {
name: "page",
mode: "out-in",
css: false,
enter: function(el, done) {
console.log("animenter contact");
if (process.browser) {
var tl = new TimelineMax();
var tg = document.querySelectorAll(".el");
var st = document.querySelector(".overlay-grid img");
var box = document.querySelectorAll(".box");
tl.fromTo(st, 0.3, { x: -100 }, { x: 0, autoAlpha: 1 });
tl.staggerTo(tg, 0.3, { autoAlpha: 1 }, 0.1);
tl.staggerTo(box, 0.3, { autoAlpha: 1, onComplete: done }, 0.1);
}
},
leave: function(el, done) {
console.log("leaving contact...");
if (process.browser) {
var tl = new TimelineMax();
var tg = document.querySelectorAll(".el");
var st = document.querySelector(".overlay-grid img");
var pl = document.querySelector("body");
var box = document.querySelectorAll(".box");
tl.fromTo(st, 0.3, { x: 0 }, { x: -100, autoAlpha: 0 });
tl.staggerTo(tg, 0.3, { autoAlpha: 0 }, 0.1);
tl.staggerTo(box, 0.3, { autoAlpha: 0, onComplete: done }, 0.1);
}
}
}
And finally, in nuxt.config.js:
router: {
middleware: 'menu'
},
build: {
vendor: [
'gsap',
....
] /*
}
I also have some variables set in the store to manage state, and some transition durations so I don't have to edit them in as many places to see how something looks. It is becoming a lot of work to preview ideas or small changes and I wasn't able to find an in-depth article that tackles this problem.
Any help with tips and tricks for Nuxt, Vue, GSAP, Webpack, and Javascript in general would be greatly appreciated.

Loop Velocity.js sequence of custom effects

I am using the Velocity UI library for text animation. I have registered two effects (In & Out, thus it handles the display property), and they are running in a sequence. How can I loop the sequence? I tried to trigger it as an option at the last in the sequence, but it did not work (as the running of the sequence is not a function).
I went through the answers here on Stack Overflow and on Github, but I could not figure out an answer. Please give me a suggestion what would be a good way to put it on an infinite loop. Thank you!
$.Velocity.RegisterUI("mythingIn", {
calls: [
[{ color: "#fff", opacity: 1 }, 0.5],
[{ color: "#ffac00" }, 0.5]
]
});
$.Velocity.RegisterUI("mythingOut", {
calls: [
[{ opacity: 0 }]
]
});
var a1wordflow1 = [
{ e: $('.a1w-1-1'), p: ("mythingIn"), o: { stagger: 70, duration: Math.random()*6000+14000 } },
{ e: $('.a1w-1-1'), p: ("mythingOut"), o: { stagger: 70, duration: 800 } },
{ e: $('.a1w-1-2'), p: ("mythingIn"), o: { stagger: 70, duration: Math.random()*6000+14000 } },
{ e: $('.a1w-1-2'), p: ("mythingOut"), o: { stagger: 70, duration: 800 } },
];
$.Velocity.RunSequence(a1wordflow1);
All you need to do is to calculate the total time of your sequence in advance, then call your sequence inside a setInterval call.
$.Velocity.RegisterUI("mythingIn", {
// ...
});
$.Velocity.RegisterUI("mythingOut", {
// ...
});
const rand = Math.random()*6000+14000;
var a1wordflow1 = [
{ e: $('.a1w-1-1'), p: ("mythingIn"), o: { stagger: 70, duration: rand } } ,
{ e: $('.a1w-1-1'), p: ("mythingOut"), o: { stagger: 70, duration: 800 } },
{ e: $('.a1w-1-2'), p: ("mythingIn"), o: { stagger: 70, duration: rand } },
{ e: $('.a1w-1-2'), p: ("mythingOut"), o: { stagger: 70, duration: 800 } },
];
let totalTime = 2 * rand + 1600 + maybeSomeOtherTime;
const interval = setInterval(() => {
$.Velocity.RunSequence(a1wordflow1);
}, totalTime);
If you some time later decide to stop the loop, you need to add the following to your code to stop the loop :
clearInterval(interval);

jQuery Knob update value with animate

I'm trying to build clock using jQuery Knob.
My clock is working (http://jsfiddle.net/Misiu/9Whck/1/), but right now I'm trying to add some extras to it.
At beginning I want to have all knobs set to 0, then using animate I want to animate their value to current time and then start normal timer update.
My code looks like this (demo here: http://jsfiddle.net/Misiu/cvQED/81/):
$.when(
$('.h').animate({
value: h
}, {
duration: 1000,
easing: 'swing',
progress: function () {
$(this).val(Math.round(this.value)).trigger('change');
}
}),
$('.m').animate({
value: m
}, {
duration: 1000,
easing: 'swing',
progress: function () {
$(this).val(Math.round(this.value)).trigger('change');
}
}),
$('.s').animate({
value: s
}, {
duration: 1000,
easing: 'swing',
progress: function () {
$(this).val(Math.round(this.value)).trigger('change');
}
})).then(function () {
myDelay();
});
function myDelay() {
var d = new Date(),
s = d.getSeconds(),
m = d.getMinutes(),
h = d.getHours();
$('.h').val(h).trigger("change");
$('.m').val(m).trigger("change");
$('.s').val(s).trigger("change");
setTimeout(myDelay, 1000)
}
In when I must call animate for every knob separately, but I would like to use data-targetValue and to have only one animate inside when.
Can this be done?
if you want to use data-targetValue you need to change your js like this
$('.h').data('targetValue', h);//$('.h').attr('targetValue', h);
$('.m').data('targetValue', m);
$('.s').data('targetValue', s);
//...
$.when(
$('.knob').each(function(){//each .knob
$(this).animate({//animate to data targetValue
value: $(this).data('targetValue')
}, {
duration: 1000,
easing: 'swing',
progress: function () {
$(this).val(Math.round(this.value)).trigger('change')
}
});
})
).then(function () {
myDelay();
});
http://jsfiddle.net/cvQED/83/
or without .each
$.when(
$('.knob').animate({
value: 100
}, {
duration: 1000,
easing: 'swing',
progress: function () {
$(this).val(Math.round(this.value/100*$(this).data('targetValue'))).trigger('change')
}
})
).then(function () {
myDelay();
});
http://jsfiddle.net/cvQED/84/

Categories

Resources