diff --git a/README.md b/README.md index 64111b0..7dbe99b 100644 --- a/README.md +++ b/README.md @@ -94,24 +94,26 @@ useReward params: Confetti config object: -| name | type | description | default | -|-----------------|--------|--------------------------------------------------------|---------------------------| -| lifetime | number | time of life | 200 | -| angle | number | initial direction of particles in degrees | 90 | -| decay | number | how much the velocity decreases with each frame | 0.94 | -| spread | number | spread of particles in degrees | 45 | -| startVelocity | number | initial velocity of particles | 35 | -| elementCount | number | particles quantity | 50 | -| elementSize | number | particle size in px | 8 | -| zIndex | number | z-index of particles | 0 | -| position | string | one of CSSProperties['position'] - e.g. "absolute" | "fixed" | -| colors | string[]| An array of colors used when generating confetti |['#A45BF1', '#25C6F6', '#72F753', '#F76C88', '#F5F770']| -| onAnimationComplete | () => void | A function that runs when animation completes | undefined | +| name | type | description | default | +|---------------------|--------|----------------------------------------------------|---------------------------------------------------------| +| fps | number | frames per second | 60 | +| lifetime | number | time of life | 200 | +| angle | number | initial direction of particles in degrees | 90 | +| decay | number | how much the velocity decreases with each frame | 0.94 | +| spread | number | spread of particles in degrees | 45 | +| startVelocity | number | initial velocity of particles | 35 | +| elementCount | number | particles quantity | 50 | +| elementSize | number | particle size in px | 8 | +| zIndex | number | z-index of particles | 0 | +| position | string | one of CSSProperties['position'] - e.g. "absolute" | "fixed" | +| colors | string[]| An array of colors used when generating confetti | ['#A45BF1', '#25C6F6', '#72F753', '#F76C88', '#F5F770'] | +| onAnimationComplete | () => void | A function that runs when animation completes | undefined | Balloons config object: | name | type | description | default | |-----------------|--------|--------------------------------------------------------|---------------------------| +| fps | number | frames per second | 60 | | lifetime | number | time of life | 600 | | angle | number | initial direction of balloons in degrees | 90 | | decay | number | how much the velocity decreases with each frame | 0.999 | @@ -128,6 +130,7 @@ Emoji config object: | name | type | description | default | |-----------------|--------|--------------------------------------------------------|---------------------------| +| fps | number | frames per second | 60 | | lifetime | number | time of life | 200 | | angle | number | initial direction of emoji in degrees | 90 | | decay | number | how much the velocity decreases with each frame | 0.94 | @@ -138,5 +141,5 @@ Emoji config object: | elementSize | number | emoji size in px | 25 | | zIndex | number | z-index of emoji | 0 | | position | string | one of CSSProperties['position'] - e.g. "absolute" | "fixed" | -| emoji | string[]| An array of emoji to shoot |['🤓', '😊', '🥳'] | +| emoji | string[]| An array of emoji to shoot |['🤓', '😊', '🥳'] | | onAnimationComplete | () => void | A function that runs when animation completes | undefined | diff --git a/package.json b/package.json index 72fab3c..114326e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-rewards", - "version": "2.0.5", + "version": "2.1.0", "description": "This package lets you easily add micro-interactions to your app and reward users with the rain of confetti, emoji or balloons.", "author": "thedevelobear", "license": "MIT", diff --git a/src/components/Balloons/Balloons.ts b/src/components/Balloons/Balloons.ts index 214b1af..aa18e8a 100644 --- a/src/components/Balloons/Balloons.ts +++ b/src/components/Balloons/Balloons.ts @@ -94,6 +94,7 @@ export const balloons = ( zIndex = 0, position = 'fixed', colors = defaultColors, + fps = 60, onAnimationComplete, } = options; const spanElements = createElements( @@ -116,5 +117,5 @@ export const balloons = ( internalAnimatingCallback(); }; - animate({ root, particles, decay, lifetime, updateParticle, onFinish }); + animate({ root, particles, decay, lifetime, fps, updateParticle, onFinish }); }; diff --git a/src/components/Balloons/Balloons.types.ts b/src/components/Balloons/Balloons.types.ts index 24ab230..290f709 100644 --- a/src/components/Balloons/Balloons.types.ts +++ b/src/components/Balloons/Balloons.types.ts @@ -10,4 +10,5 @@ export type BalloonsConfig = { position?: string; colors?: string[]; onAnimationComplete?: () => void; + fps?: number; }; diff --git a/src/components/Confetti/Confetti.ts b/src/components/Confetti/Confetti.ts index 7bd8583..8a1ab27 100644 --- a/src/components/Confetti/Confetti.ts +++ b/src/components/Confetti/Confetti.ts @@ -86,6 +86,7 @@ export const confetti = ( startVelocity = 35, zIndex = 0, position = 'fixed', + fps = 60, onAnimationComplete, } = options; const spanElements = createElements( @@ -113,6 +114,7 @@ export const confetti = ( particles, decay, lifetime, + fps, updateParticle, onFinish, }); diff --git a/src/components/Confetti/Confetti.types.ts b/src/components/Confetti/Confetti.types.ts index 71f0bf6..01854d2 100644 --- a/src/components/Confetti/Confetti.types.ts +++ b/src/components/Confetti/Confetti.types.ts @@ -10,4 +10,5 @@ export type ConfettiConfig = { position?: string; colors?: string[]; onAnimationComplete?: () => void; + fps?: number; }; diff --git a/src/components/Emoji/Emoji.ts b/src/components/Emoji/Emoji.ts index 6d69569..c312033 100644 --- a/src/components/Emoji/Emoji.ts +++ b/src/components/Emoji/Emoji.ts @@ -54,12 +54,10 @@ const updateParticle = ( ? `rotate3d(0, 0, 1, ${differentiator % 2 ? tiltAngle : -1 * tiltAngle}rad)` : ''; - const transformStyles = [translateStyle, rotateStyle] + particle.element.style.transform = [translateStyle, rotateStyle] .filter(Boolean) .join(' '); - particle.element.style.transform = transformStyles; - if (progress > 0.5) { particle.element.style.opacity = `${2 - 2 * progress}`; } @@ -83,6 +81,7 @@ export const emoji = ( zIndex = 0, position = 'fixed', rotate = true, + fps = 60, onAnimationComplete, } = options; const spanElements = createElements( @@ -111,6 +110,7 @@ export const emoji = ( decay, rotate, lifetime, + fps, updateParticle, onFinish, }); diff --git a/src/components/Emoji/Emoji.types.ts b/src/components/Emoji/Emoji.types.ts index c615e66..304c03b 100644 --- a/src/components/Emoji/Emoji.types.ts +++ b/src/components/Emoji/Emoji.types.ts @@ -11,4 +11,5 @@ export type EmojiConfig = { emoji?: string[]; rotate?: boolean; onAnimationComplete?: () => void; + fps?: number; }; diff --git a/src/functions/helpers.ts b/src/functions/helpers.ts index 5fa70a0..8b3888d 100644 --- a/src/functions/helpers.ts +++ b/src/functions/helpers.ts @@ -6,28 +6,41 @@ export const animate: AnimateFunction = ({ decay, rotate, lifetime, + fps, updateParticle, onFinish, }) => { const totalTicks = lifetime; let tick = 0; + let lastTime = 0; + const interval = 1000 / fps; - const update = () => { - particles.forEach((particle) => - updateParticle(particle, tick / totalTicks, decay, rotate) - ); + const update = (timestamp: number) => { + if (!lastTime) lastTime = timestamp; + + const elapsed = timestamp - lastTime; + + if (elapsed >= interval) { + lastTime = timestamp - (elapsed % interval); - tick += 1; - if (tick < totalTicks) { - window.requestAnimationFrame(update); - } else { - particles.forEach((particle) => { - if (particle.element.parentNode === root) { - return root.removeChild(particle.element); - } - }); - onFinish(); + particles.forEach((particle) => + updateParticle(particle, tick / totalTicks, decay, rotate) + ); + + tick += 1; + + if (tick >= totalTicks) { + particles.forEach((particle) => { + if (particle.element.parentNode === root) { + root.removeChild(particle.element); + } + }); + onFinish(); + return; + } } + + window.requestAnimationFrame(update); }; window.requestAnimationFrame(update); diff --git a/src/functions/helpers.types.ts b/src/functions/helpers.types.ts index cf7bbee..26fb0f4 100644 --- a/src/functions/helpers.types.ts +++ b/src/functions/helpers.types.ts @@ -6,6 +6,7 @@ export type AnimateFunctionArgs = { decay: number; rotate?: boolean; lifetime: number; + fps: number; updateParticle: ( particle: Particle, progress: number,