Skip to content

Commit

Permalink
Merge pull request #19 from stevent-team/feat/spawn-opts
Browse files Browse the repository at this point in the history
More options for controlling confetti spawning
  • Loading branch information
giraugh authored Jan 1, 2023
2 parents a682155 + a2528dd commit d19e9a8
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/curvy-buckets-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@stevent-team/react-party": minor
---

Add more options for controlling the confetti spawn location and velocity
7 changes: 6 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ module.exports = {
'semi': [
'error',
'never'
]
],
'no-unused-vars': [1, {
'args': 'all',
'argsIgnorePattern': '^_',
'ignoreRestSiblings': true
}]
}
}
34 changes: 30 additions & 4 deletions lib/confetti.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,39 @@ export const createRandomParticle = (
options: ConfettiOptions
): Particle => {
const { left, top, width, height } = source.getBoundingClientRect()
const [cx, cy] = [left + width / 2, top + height / 2]
const [vxInitial, vyInitial] = options.initialVelocity
const [vxSpread, vySpread] = options.initialVelocitySpread
const [x, y] = [left + Math.random() * width, top + Math.random() * height]
const [cx, cy] = [left + width / 2, top + height / 2]

// Determine spawn location
let [x, y] = [0, 0]
if (options.spawnLocation === 'area') {
[x, y] = [left + Math.random() * width, top + Math.random() * height]
} else if (options.spawnLocation === 'edges') {
[x, y] = [left + Math.random() * width, top + Math.random() * height]
if (Math.random() < .5) {
x = x < cx ? left : left + width
} else {
y = y < cy ? top : top + height
}
} else if (options.spawnLocation === 'corners') {
[x, y] = [left + Math.random() * width, top + Math.random() * height]
x = x < cx ? left : left + width
y = y < cy ? top : top + height
}

// Find dir to center
const a = Math.atan2(y - cy, x - cx)
const vx = Math.cos(a) * Math.random() * vxSpread + vxInitial
const vy = Math.sin(a) * Math.random() * vySpread + vyInitial
const [dx, dy] = [Math.cos(a), Math.sin(a)]

// Apply spacing
x += dx * options.spawnGap
y += dy * options.spawnGap

// Determine initial movement
const vx = dx * Math.random() * vxSpread + vxInitial
const vy = dy * Math.random() * vySpread + vyInitial

return {
x, y,
vx, vy,
Expand Down
22 changes: 21 additions & 1 deletion lib/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DEFAULT_SHAPE_FUNCTIONS } from './util/drawing'

export type RangeArg = number | [number, number]
export type VectorArg = [number, number]
export type ConfettiSpawnLocation = 'area' | 'edges' | 'corners'

export interface CreateConfettiOptions {
/** The amount of particles that will be spawned. Overrides the count property in the options passed to `useConfetti`. */
Expand All @@ -15,6 +16,12 @@ export interface CreateConfettiOptions {

/** Pass in a ref to use as the source of the confetti. By default, `document.activeElement` will be used if this isn't set. */
sourceRef?: MutableRefObject<HTMLElement>

/** Where in the source element the confetti should be created. Defaults to `area`. */
spawnLocation: ConfettiSpawnLocation,

/** Spacing between the source element and the spawned confetti. Applied in direction away from the center of source element. */
spawnGap: number,
}

export interface ConfettiOptions {
Expand All @@ -35,7 +42,10 @@ export interface ConfettiOptions {
/** A vector representing the initial x and y velocity of each particle. */
initialVelocity: VectorArg,

/** A vector representing an x and y velocity spread that's applied to the initialVelocity values to randomise the spread of confetti. */
/** A vector representing x and y velocities. These are applied relative to the direction away from the center of the source element.
* @example e.g Use [1, 0] to only move horizontally away from the center of the source element
* @example e.g Use [0, -1] to move vertically towards the source element
*/
initialVelocitySpread: VectorArg,

/** Minimum and maximum values for the twirl of each particle between 0 and 1. Offsets the centerpoint of each particle. Set to a number to use the same value for every particle. */
Expand Down Expand Up @@ -66,6 +76,14 @@ export interface ConfettiOptions {
* @note Can be overriden when calling createConfetti */
duration: number,

/** Where in the source element the confetti should be created. Defaults to `area`.
* @note Can be overriden when calling createConfetti */
spawnLocation: ConfettiSpawnLocation,

/** Spacing between the source element and the spawned confetti. Applied in direction away from the center of source element.
* @note Can be overriden when calling createConfetti */
spawnGap: number,

/* Drawing */

/** An object of functions for each shape that is used to draw them. See README for more details. */
Expand Down Expand Up @@ -105,4 +123,6 @@ export const DEFAULT_CONFETTI_OPTIONS: ConfettiOptions = {
},
count: 75,
duration: 0,
spawnLocation: 'area',
spawnGap: 0,
}
12 changes: 10 additions & 2 deletions sample/Confetti.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const Confetti = () => {
const launch = useControls('Creation options', {
duration: { value: 0, min: 0, max: 5000 },
count: { value: 75, min: 1, max: 2000, step: 1 },
spawnLocation: { value: 'area', options: ['area', 'edges', 'corners'] },
spawnGap: { value: 0, min: -50, max: 50 },
})

const global = useControls('Environment options', {
Expand All @@ -40,7 +42,7 @@ const Confetti = () => {
rotationVelocityCoefficient: { value: .8, min: 0, max: 5 },
}, { collapsed: true })

const { 'Explore shape options': _btn, ...shapeWeights }= useControls('Shape weights', {
const { 'Explore shape options': _btn, ...shapeWeights } = useControls('Shape weights', {
'Explore shape options': button(() => window.open('/shapes')),
'moon': { value: 0, min: 0, max: 5, step: 1 },
'line': { value: 0, min: 0, max: 5, step: 1 },
Expand Down Expand Up @@ -80,9 +82,15 @@ const Confetti = () => {
}
})

const buttonStyle = ['edges', 'corners'].includes(launch.spawnLocation) ? {
opacity: .2,
width: '50%',
paddingBlock: '10em',
} : {}

return <>
<canvas {...canvasProps} />
<button onClick={() => createConfetti(launch)}>Party!</button>
<button onClick={() => createConfetti(launch)} style={buttonStyle}>Party!</button>
</>
}

Expand Down

0 comments on commit d19e9a8

Please sign in to comment.