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);
Related
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
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I have some code written in phaser.js and I need to optimize it, i.e. break it down into functions and remove unnecessary animation calls (the code is completely working, but it just needs to be optimized). I'm just new to js and this library :(
I tried it myself, but then the code stops working for me :(
class Example extends Phaser.Scene {
constructor() {
super();
}
preload() {
this.load.spritesheet("start", "img/bri_big_anim_start.png", {
frameWidth: 392,
frameHeight: 370,
});
this.load.spritesheet("middle", "img/bri_big_anim_middle.png", {
frameWidth: 450,
frameHeight: 430,
});
this.load.spritesheet("finish", "img/bri_big_anim_finish.png", {
frameWidth: 326,
frameHeight: 335,
});
}
create() {
const startAnimation = this.anims.create({
key: "walkStart",
frames: this.anims.generateFrameNumbers("start", { start: 0, end: 4 }),
frameRate: 4,
});
let middleAnimation = this.anims.create({
key: "walkMiddle",
frames: this.anims.generateFrameNumbers("middle", { start: 0, end: 4 }),
frameRate: 4,
});
const finishAnimation = this.anims.create({
key: "walkFinish",
frames: this.anims.generateFrameNumbers("finish", { start: 0, end: 4 }),
frameRate: 4,
});
const spriteStart = this.add.sprite(400, 350, "start").setScale(0.4);
spriteStart.play({ key: "walkStart", repeat: 1 });
this.tweens.add({
targets: spriteStart,
y: 360,
scaleX: 0.9,
scaleY: 0.9,
duration: 2000,
});
spriteStart.on(
"animationcomplete",
function () {
spriteStart.destroy();
let spriteMiddle = this.add.sprite(400, 350, "middle").setScale(0.8);
spriteMiddle.play({ key: "walkMiddle", repeat: 3 });
this.tweens.add({
targets: spriteMiddle,
});
spriteMiddle.on(
"animationcomplete",
function () {
spriteMiddle.destroy();
const spriteFinish = this.add
.sprite(400, 350, "finish")
.setScale(0.8);
spriteFinish.play({ key: "walkFinish", repeat: 1 });
this.tweens.add({
targets: spriteFinish,
y: 100,
x: 300,
scale: 0.1,
duration: 2000,
});
spriteFinish.on(
"animationcomplete",
function () {
spriteFinish.destroy();
let middleAnimation = this.anims.create({
frames: this.anims.generateFrameNumbers("middle", {
start: 0,
end: 1,
}),
frameRate: 1,
});
spriteMiddle = this.add
.sprite(300, 100, "middle")
.setScale(0.1);
spriteMiddle.play({ key: "walkMiddle", repeat: 0 });
this.tweens.add({
targets: spriteMiddle,
});
spriteMiddle.stop();
},
this,
);
},
this,
);
},
this,
);
}
}
const config = {
type: Phaser.AUTO,
parent: "phaser-example",
width: 800,
height: 600,
pixelArt: true,
scene: [Example],
};
const game = new Phaser.Game(config);
Everything I could do
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
preload ()
{
this.load.spritesheet('start', 'img/bri_big_anim_start.png', { frameWidth: 392, frameHeight: 370 });
this.load.spritesheet('middle', 'img/bri_big_anim_middle.png', { frameWidth: 450, frameHeight: 430 });
this.load.spritesheet('finish', 'img/bri_big_anim_finish.png', { frameWidth: 326, frameHeight: 335 });
}
create ()
{
const startAnimation = this.anims.create({
key: 'walkStart',
frames: this.anims.generateFrameNumbers('start', {start: 0, end: 4}),
frameRate: 4,
});
let middleAnimation = this.anims.create({
key: 'walkMiddle',
frames: this.anims.generateFrameNumbers('middle', {start: 0, end: 4}),
frameRate: 4,
});
const finishAnimation = this.anims.create({
key: 'walkFinish',
frames: this.anims.generateFrameNumbers('finish', {start: 0, end: 4}),
frameRate: 4,
});
const addSprite = (nameSpritePlay, keyPlay, repeatPlay) => {
nameSpritePlay.play({ key: keyPlay, repeat: repeatPlay });
}
const spriteStart = this.add.sprite(400, 350, 'start').setScale(0.4);
// spriteStart.play({ key: 'walkStart', repeat: 1 });
addSprite(spriteStart, 'walkStart', 1);
this.tweens.add({
targets: spriteStart,
y: 360,
scaleX: 0.9,
scaleY: 0.9,
duration: 2000,
});
spriteStart.on('animationcomplete', function () {
spriteStart.destroy();
let spriteMiddle = this.add.sprite(400, 350, 'middle').setScale(0.8);
// spriteMiddle.play({ key: 'walkMiddle', repeat: 3 });
addSprite(spriteMiddle, 'walkMiddle', 3);
this.tweens.add({
targets: spriteMiddle,
});
spriteMiddle.on('animationcomplete', function () {
spriteMiddle.destroy();
const spriteFinish = this.add.sprite(400, 350, 'finish').setScale(0.8);
// spriteFinish.play({ key: 'walkFinish', repeat: 1 });
addSprite(spriteFinish, 'walkFinish', 1);
this.tweens.add({
targets: spriteFinish,
y: 100,
x: 300,
scale: 0.1,
duration: 2000,
});
spriteFinish.on('animationcomplete', function () {
spriteFinish.destroy();
spriteMiddle = this.add.sprite(300, 100, 'middle').setScale(0.1);
// spriteMiddle.play({ key: 'walkMiddle', repeat: 0 });
addSprite(spriteMiddle, 'walkMiddle', 0);
spriteMiddle.stop();
}, this);
}, this);
}, this);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
pixelArt: true,
scene: [ Example ]
};
const game = new Phaser.Game(config);
Optimizie Code can take long, but I would say you could look into the example below, how to chain animations, this would minimize your code, with builtin phaser functionality:
https://phaser.io/examples/v3/view/animation/chained-animation#
the main idea is the playAfterRepeat function
sprite.playAfterRepeat(...);
Here a link to the documentation of this feature.
I personally would load animations from an atlas/json file as seen in this example: https://phaser.io/examples/v3/view/animation/from-animation-json
this keeps the code clean streamlined, and animations can be changed/managed with greater ease.
Or maybe create a helper function like this (but this is just my preference):
generateFrames(key, name){
let animation = this.anims.create({
key: key,
frames: this.anims.generateFrameNumbers(name, { start: 0, end: 4 }),
frameRate: 4,
});
return animation;
}
...
const startAnimation = generateFrames('walkStart', 'start');
const middleAnimation = generateFrames('walkMiddle', 'middle');
const finishAnimation = generateFrames('walkFinish', 'finish');
Currently been using react-spring to do our animations in our app; unfortunately, animation is not something I excel in and the design our designer gave us for our new logo is leaving me stumped on implementation. It is pretty easy with plain old JS but implementing it in react-spring has proved a challenge that I can not get past.
The end goal for the animation is to look like this:
https://codepen.io/darylginn/pen/GRqZxBZ
Currently, I am up to this stage:
import React from "react";
import { useTrail, animated } from "react-spring";
const Loader: React.FC = () => {
// Animations
const paths = [
{
id: 1,
color: "#466FB5",
d: "M90.6672 33H16L53.3336 96.4409L90.6672 33Z",
},
{
id: 2,
color: "#0093D3",
d: "M53.3347 96.4443H128.002L90.6683 33.0034L53.3347 96.4443Z",
},
{
id: 3,
color: "#53BFA2",
d: "M128.001 96.3701H53.3336L90.6672 159.811L128.001 96.3701Z",
},
{
id: 4,
color: "#93C83F",
d: "M90.6675 159.892H165.335L128.001 96.4417L90.6675 159.892Z",
},
{
id: 5,
color: "#58B647",
d: "M165.334 159.892H90.6664L128 223.333L165.334 159.892Z",
},
{
id: 6,
color: "#F2E90B",
d: "M202.667 96.4436H128L165.334 159.894L202.667 96.4436Z",
},
{
id: 7,
color: "#FBB12C",
d: "M128.001 96.4443H202.668L165.335 33.0034L128.001 96.4443Z",
},
{
id: 8,
color: "#FF5E8D",
d: "M240 33H165.333L202.666 96.4409L240 33Z",
},
];
const trail = useTrail(paths.length, {
from: {
scale: 1,
},
to: async (next: any) => {
while (1) {
await next({ scale: 1.5 });
await next({ scale: 1 });
}
},
});
return (
<div style={{ width: "200px", height: "200px" }}>
<svg
width="72"
height="72"
viewBox="0 0 256 256"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{ overflow: "visible" }}>
{trail.map(({ scale }, index) => {
const path = paths[index];
return (
<animated.path
key={path.id}
fill={path.color}
d={path.d}
style={{
transformOrigin: "center",
transform: scale.interpolate((s: any) => `scale(${s})`),
}}
/>
);
})}
</svg>
</div>
);
};
The main issue I am at now is the scale of each triangle in the SVG needs to happen one after another, but nothing I do with the useTrail make this happen.
I did try adding a delay like this to the useTrail
delay: (key: any) => key * 200
But the delay doesn't even seem to make a difference. If someone could help make sure each triangle finish it sequences before the next one starts that would be great.
Bonus if you can also help me add the colour change as seen in the original design (see link).
I have tried posting in the react-spring community but got no replies
I would change the useTrail to one useSpring for all the triangles. If you change the x value from 0 to 8, then you can use interpolate and a range for each triangle to change. For example for the second triangle you can use range:[0,1,1.5,2,8],output:[1,1,1.5,1,1]. It means that when x is between 1 and 2 it will change the scale from 1 to 1.5 to 1 and all other places it will remain 1.
const props = useSpring({
from: {
x: 0
},
config: {
duration: 4000
},
to: async (next: any) => {
while (1) {
await next({ x: 8 });
await next({ reset: true });
}
}
});
I also added the color interpolation.
{paths.map((path, index) => {
const colors = [];
for (let i = 0; i < 8; i++) {
colors.push(paths[(i + index) % 8].color);
}
return (
<animated.path
key={path.id}
fill={path.color}
d={path.d}
style={{
transformOrigin: "center",
transform: props.x
.interpolate({
range: [0, index, index + 0.5, index + 1, 8],
output: [1, 1, 1.5, 1, 1]
})
.interpolate((x) => `scale(${x})`),
fill: props.x.interpolate({
range: [0, 1, 2, 3, 4, 5, 6, 7, 8],
output: colors
})
}}
/>
);
})}
I have an example. There is some glitch with the center triangle. But I think you get the idea.
Example: https://codesandbox.io/s/animate-triangles-sequentially-with-interpolating-and-range-oer84
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();
},
},
],
});
});
I am using jquery to refresh my JustGage gauges. I get my data back from the controller and everything works just fine until eventually the pc runs out of memory and it freezes. I have 9 gauges and 2 pie charts that need refreshing. The setInterval call is the problem, as it fires every second instead of waiting 120000 ms. Am I doing something wrong with setInterval?
<script>
window.onload = function () {
var g9 = new JustGage({
id: "gage9",
value: '#ViewBag.TotalNeuro',
min: 0,
max: 150,
counter: true,
label: "Total Neuro",
labelMinFontSize: 11,
formatNumber: true,
customSectors: {
//percents: true,
ranges: [
{ lo: 0, hi: 33, color: '#f0f016' }, // lo and hi values are in %
{ lo: 34, hi: 67, color: '#f59a1b' },
{ lo: 68, hi: 100, color: '#e0121c' }
]
},
levelColorsGradient: false,
gaugeWidthScale: 0.9,
startAnimationTime: 2700,
startAnimationType: "bounce",
});
setInterval(function () {
var TotalNeuroUrl = '#Url.Action("TotalNeuro")';
$.getJSON(TotalNeuroUrl, {}, function (dataNeuro) {
g9.refresh(dataNeuro);
}, 120000);
});
};
It seems that you use setInterval incorrectly, refer to https://www.w3schools.com/jsref/met_win_setinterval.asp
Try to modify it to:
setInterval(function () {
var TotalNeuroUrl = '#Url.Action("TotalNeuro")';
$.getJSON(
TotalNeuroUrl,
{},
function (dataNeuro) {
g9.refresh(dataNeuro);
}
);
},120000);