Skip to content

Commit 8af89f2

Browse files
committed
feat: Add onConfettiComplete param
With stories.
1 parent a8bd0c2 commit 8af89f2

File tree

7 files changed

+58
-23
lines changed

7 files changed

+58
-23
lines changed

.storybook/addons.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import '@storybook/addon-knobs/register'
22
import '@storybook/addon-storysource/register'
3+
import '@storybook/addon-actions/register'

.storybook/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { addParameters, configure } from '@storybook/react'
22
import { create } from '@storybook/theming'
33
addParameters({
44
options: {
5+
sortStoriesByKind: true,
56
theme: create({
67
base: 'light',
78
brandTitle: 'React Confetti',

README.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,23 @@ export default () => {
4343

4444
## Props
4545

46-
| Property | Type | Default | Description |
47-
| ---------------- | --------------------- | --- | --- |
48-
| `width` | `Number` | `window.innerWidth \|\| 300` | Width of the `<canvas>` element. |
49-
| `height` | `Number` | `window.innerHeight \|\| 200` | Height of the `<canvas>` element. |
50-
| `numberOfPieces` | `Number` | 200 | Number of confetti pieces at one time. |
51-
| `confettiSource` | `{ x: Number, y: Number, w: Number, h: Number }` | `{x: 0, y: 0, w: canvas.width, h:0}` | Rectangle where the confetti should spawn. Default is across the top. |
52-
| `friction` | `Number` | 0.99 | |
53-
| `wind` | `Number` | 0 | |
54-
| `gravity` | `Number` | 0.1 | |
55-
| `colors` | `String[]` | `['#f44336'`</br>`'#e91e63'`</br>`'#9c27b0'`</br>`'#673ab7'`</br>`'#3f51b5'`</br>`'#2196f3'`</br>`'#03a9f4'`</br>`'#00bcd4'`</br>`'#009688'`</br>`'#4CAF50'`</br>`'#8BC34A'`</br>`'#CDDC39'`</br>`'#FFEB3B'`</br>`'#FFC107'`</br>`'#FF9800'`</br>`'#FF5722'`</br>`'#795548']`</br> | All available Colors for the confetti pieces. |
56-
| `opacity` | `Number` | 1.0 | |
57-
| `recycle` | `Bool` | true | Keep spawning confetti after `numberOfPieces` pieces have been shown. |
58-
| `run` | `Bool` | true | Run the animation loop |
59-
| `tweenDuration` | `Number` | 5000 | How fast the confetti is added |
60-
| `tweenFunction` | `(currentTime: number, currentValue: number, targetValue: number, duration: number, s?: number) => number` | easeInOutQuad | See [tween-functions](https://github.com/chenglou/tween-functions) |
61-
| `drawShape` | `(context: CanvasRenderingContext2D) => void` | `undefined` | See below
46+
| Property | Type | Default | Description |
47+
| ---------------- | --------------------- | --- | --- |
48+
| `width` | `Number` | `window.innerWidth \|\| 300` | Width of the `<canvas>` element. |
49+
| `height` | `Number` | `window.innerHeight \|\| 200` | Height of the `<canvas>` element. |
50+
| `numberOfPieces` | `Number` | 200 | Number of confetti pieces at one time. |
51+
| `confettiSource` | `{ x: Number, y: Number, w: Number, h: Number }` | `{x: 0, y: 0, w: canvas.width, h:0}` | Rectangle where the confetti should spawn. Default is across the top. |
52+
| `friction` | `Number` | 0.99 | |
53+
| `wind` | `Number` | 0 | |
54+
| `gravity` | `Number` | 0.1 | |
55+
| `colors` | `String[]` | `['#f44336'`</br>`'#e91e63'`</br>`'#9c27b0'`</br>`'#673ab7'`</br>`'#3f51b5'`</br>`'#2196f3'`</br>`'#03a9f4'`</br>`'#00bcd4'`</br>`'#009688'`</br>`'#4CAF50'`</br>`'#8BC34A'`</br>`'#CDDC39'`</br>`'#FFEB3B'`</br>`'#FFC107'`</br>`'#FF9800'`</br>`'#FF5722'`</br>`'#795548']`</br> | All available Colors for the confetti pieces. |
56+
| `opacity` | `Number` | 1.0 | |
57+
| `recycle` | `Bool` | true | Keep spawning confetti after `numberOfPieces` pieces have been shown. |
58+
| `run` | `Bool` | true | Run the animation loop |
59+
| `tweenDuration` | `Number` | 5000 | How fast the confetti is added |
60+
| `tweenFunction` | `(currentTime: number, currentValue: number, targetValue: number, duration: number, s?: number) => number` | easeInOutQuad | See [tween-functions](https://github.com/chenglou/tween-functions) |
61+
| `drawShape` | `(context: CanvasRenderingContext2D) => void` | `undefined` | See below |
62+
| `onConfettiComplete` | `(confetti: Confetti) => void` | `undefined` | Called when all confetti has fallen off-canvas. |
6263

6364

6465

src/Confetti.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ export interface IConfettiOptions {
8181
* Function to draw your own confetti shapes.
8282
*/
8383
drawShape?: (context: CanvasRenderingContext2D) => void
84+
/**
85+
* Function called when all confetti has fallen off-canvas.
86+
*/
87+
onConfettiComplete?: (confettiInstance?: Confetti) => void
8488
}
8589

8690
export const confettiDefaults: Pick<IConfettiOptions, Exclude<keyof IConfettiOptions, 'confettiSource'>> = {
@@ -128,9 +132,13 @@ export class Confetti {
128132
}
129133
set options(opts: Partial<IConfettiOptions>) {
130134
const lastRunState = this._options && this._options.run
135+
const lastRecycleState = this._options && this._options.recycle
131136
this.setOptionsWithDefaults(opts)
132137
if(this.generator) {
133138
Object.assign(this.generator, this.options.confettiSource)
139+
if(typeof opts.recycle === 'boolean' && opts.recycle && lastRecycleState === false) {
140+
this.generator.lastNumberOfPieces = this.generator.particles.length
141+
}
134142
}
135143
if(typeof opts.run === 'boolean' && opts.run && lastRunState === false) {
136144
this.update()
@@ -154,6 +162,7 @@ export class Confetti {
154162
const {
155163
options: {
156164
run,
165+
onConfettiComplete,
157166
},
158167
canvas,
159168
context,
@@ -165,10 +174,21 @@ export class Confetti {
165174
if(this.generator.animate()) {
166175
this.rafId = requestAnimationFrame(this.update)
167176
} else {
177+
if(onConfettiComplete && typeof onConfettiComplete === 'function' && this.generator.particlesGenerated > 0) {
178+
onConfettiComplete.call(this, this)
179+
}
168180
this._options.run = false
169181
}
170182
}
171183

184+
reset = () => {
185+
if(this.generator && this.generator.particlesGenerated > 0) {
186+
this.generator.particlesGenerated = 0
187+
this.generator.particles = []
188+
this.generator.lastNumberOfPieces = 0
189+
}
190+
}
191+
172192
stop = () => {
173193
this.options = { run: false }
174194
if(this.rafId) {

src/ReactConfetti.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class ReactConfetti extends Component<Props> {
5656
function extractCanvasProps(props: Partial<IConfettiOptions> | any): [Partial<IConfettiOptions>, Partial<CanvasHTMLAttributes<HTMLCanvasElement>>] {
5757
const confettiOptions: Partial<IConfettiOptions> = {}
5858
const rest: any = {}
59-
const confettiOptionKeys = [...Object.keys(confettiDefaults), 'confettiSource', 'drawShape']
59+
const confettiOptionKeys = [...Object.keys(confettiDefaults), 'confettiSource', 'drawShape', 'onConfettiComplete']
6060
for(const prop in props) {
6161
const val = props[prop as string]
6262
if(confettiOptionKeys.includes(prop)) {

stories/index.story.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import SizedConfetti from './SizedConfetti'
44
import { withKnobs, boolean, number } from '@storybook/addon-knobs'
55
import { storiesOf } from '@storybook/react'
66
import { withInfo } from '@storybook/addon-info'
7+
import { action } from '@storybook/addon-actions'
78

89
import ReactConfetti from '../src/ReactConfetti'
910

@@ -54,6 +55,7 @@ storiesOf('Props|Demos', module)
5455
max: 100,
5556
step: 1,
5657
}) / 100}
58+
onConfettiComplete={action('Confetti Complete')}
5759
/>
5860
))
5961
.add('Custom Source', () => (

0 commit comments

Comments
 (0)