From 90aba4102b0923a9828f90df05896fb1c7159f1e Mon Sep 17 00:00:00 2001 From: Jack Thomson Date: Thu, 20 Jul 2017 10:11:19 +0100 Subject: [PATCH 1/2] Confetti falls within the container --- confetti.js | 198 ++++++++++++++++++++++++++---------------------- confettiView.js | 148 +++++++++++++++++++++--------------- 2 files changed, 193 insertions(+), 153 deletions(-) diff --git a/confetti.js b/confetti.js index f41d602..6ff225a 100644 --- a/confetti.js +++ b/confetti.js @@ -1,112 +1,126 @@ -import React, {Component} from 'react'; +import React, { Component } from "react"; import { - AppRegistry, - StyleSheet, - Text, - View, - Animated, - Dimensions -} from 'react-native'; - -let windowHeight = Dimensions.get('window').height; -let windowWidth = Dimensions.get('window').width; + AppRegistry, + StyleSheet, + Text, + View, + Animated, + Dimensions +} from "react-native"; class Confetti extends Component { - constructor(props) { - super(props); - this._yAnimation = new Animated.Value(0); - this.color = this.randomColor(this.props.colors); - this.left = this.randomValue(0, windowWidth); - } + constructor(props) { + super(props); + this._yAnimation = new Animated.Value(0); + this.color = this.randomColor(this.props.colors); + this.left = this.randomValue(0, this.props.containerWidth); + } - componentWillMount() { - let rotationOutput = this.randomValue(-220, 220) + 'deg'; - this._rotateAnimation = this._yAnimation.interpolate({ - inputRange: [0, windowHeight / 2, windowHeight], - outputRange: ['0deg', rotationOutput, rotationOutput] - }); + componentWillMount() { + let rotationOutput = this.randomValue(-220, 220) + "deg"; + this._rotateAnimation = this._yAnimation.interpolate({ + inputRange: [ + 0, + this.props.containerHeight / 2, + this.props.containerHeight + ], + outputRange: ["0deg", rotationOutput, rotationOutput] + }); - let xDistance = this.randomIntValue((windowWidth / 3 * -1), windowWidth / 3); - this._xAnimation = this._yAnimation.interpolate({ - inputRange: [0, windowHeight], - outputRange: [0, xDistance] - }); - } + let xDistance = this.randomIntValue( + this.props.containerWidth / 3 * -1, + this.props.containerWidth / 3 + ); + this._xAnimation = this._yAnimation.interpolate({ + inputRange: [0, this.props.containerHeight], + outputRange: [0, xDistance] + }); + } - componentDidMount() { - let {duration, index} = this.props; - Animated.timing(this._yAnimation, { - duration: duration, - toValue: windowHeight + 1.25, - useNativeDriver: true - }).start(this.props.onComplete); - } + componentDidMount() { + let { duration, index } = this.props; + Animated.timing(this._yAnimation, { + duration: duration, + toValue: this.props.containerHeight + 1.25, + useNativeDriver: true + }).start(this.props.onComplete); + } - getTransformStyle() { - return { - transform: [ - {translateY: this._yAnimation}, - {translateX: this._xAnimation}, - {rotate: this._rotateAnimation} - ] - } - } + getTransformStyle() { + return { + transform: [ + { translateY: this._yAnimation }, + { translateX: this._xAnimation }, + { rotate: this._rotateAnimation } + ] + }; + } - getConfettiStyle() { - let {index} = this.props; - let bigConfetti = { - height: 5.5, - width: 11, - borderBottomLeftRadius: 5, - borderBottomRightRadius: 5, - borderTopLeftRadius: 2.6, - borderTopRightRadius: 2.6 - }; - let smallConfetti = { - height: 4.5, - width: 8, - borderBottomLeftRadius: 2.5, - borderBottomRightRadius: 2.5, - borderTopLeftRadius: 1.3, - borderTopRightRadius: 1.3 - } - return index % 5 === 0 ? smallConfetti : bigConfetti; - } + getConfettiStyle() { + let { index } = this.props; + let bigConfetti = { + height: 5.5, + width: 11, + borderBottomLeftRadius: 5, + borderBottomRightRadius: 5, + borderTopLeftRadius: 2.6, + borderTopRightRadius: 2.6 + }; + let smallConfetti = { + height: 4.5, + width: 8, + borderBottomLeftRadius: 2.5, + borderBottomRightRadius: 2.5, + borderTopLeftRadius: 1.3, + borderTopRightRadius: 1.3 + }; + return index % 5 === 0 ? smallConfetti : bigConfetti; + } - randomValue(min, max) { - return Math.random() * (max - min) + min; - } + randomValue(min, max) { + return Math.random() * (max - min) + min; + } - randomIntValue(min, max) { - return Math.floor(Math.random() * (max - min) + min); - } + randomIntValue(min, max) { + return Math.floor(Math.random() * (max - min) + min); + } - randomColor(colors) { - return colors[this.randomIntValue(0,colors.length)]; - } + randomColor(colors) { + return colors[this.randomIntValue(0, colors.length)]; + } - render() { - let {left, ...otherProps} = this.props; - return - } + render() { + let { left, ...otherProps } = this.props; + return ( + + ); + } } Confetti.defaultProps = { - duration: 6000, - colors: [ - "rgb(242.2, 102, 68.8)", - "rgb(255, 198.9, 91.8)", - "rgb(122.4, 198.9, 163.2)", - "rgb(76.5, 193.8, 216.7)", - "rgb(147.9, 99.4, 140.2)" - ] -} + duration: 6000, + colors: [ + "rgb(242.2, 102, 68.8)", + "rgb(255, 198.9, 91.8)", + "rgb(122.4, 198.9, 163.2)", + "rgb(76.5, 193.8, 216.7)", + "rgb(147.9, 99.4, 140.2)" + ] +}; const styles = StyleSheet.create({ - confetti: { - position: 'absolute', - marginTop: 0 - } + confetti: { + position: "absolute", + marginTop: 0 + } }); export default Confetti; diff --git a/confettiView.js b/confettiView.js index a68d4c2..7156092 100644 --- a/confettiView.js +++ b/confettiView.js @@ -1,78 +1,104 @@ -import React, {Component} from 'react'; +import React, { Component } from "react"; import { - AppRegistry, - StyleSheet, - View, - Animated -} from 'react-native'; + AppRegistry, + StyleSheet, + View, + Animated, + Dimensions +} from "react-native"; import Confetti from "./confetti.js"; +let windowHeight = Dimensions.get("window").height; +let windowWidth = Dimensions.get("window").width; + class ConfettiView extends Component { - constructor(props) { - super(props); - this.state = {confettis: []}; - this.confettiIndex = 0; - this.shouldStop = false; - } + constructor(props) { + super(props); + this.state = { confettis: [], width: windowWidth, height: windowHeight }; + this.confettiIndex = 0; + this.shouldStop = false; + } + + startConfetti() { + let { confettis } = this.state; + let { confettiCount, timeout } = this.props; + this.shouldStop = false; + if (this.confettiIndex < confettiCount) { + setTimeout(() => { + if (this.shouldStop) { + return; + } else { + confettis.push({ key: this.confettiIndex }); + this.confettiIndex++; + this.setState({ confettis }); + this.startConfetti(); + } + }, timeout); + } + } - startConfetti() { - let {confettis} = this.state; - let {confettiCount, timeout} = this.props; - this.shouldStop = false; - if(this.confettiIndex < confettiCount) { - setTimeout(() => { - if (this.shouldStop) { - return; - } else { - confettis.push({key: this.confettiIndex}); - this.confettiIndex++; - this.setState({confettis}); - this.startConfetti(); - } - }, timeout); - } - } + removeConfetti(key) { + let { confettis } = this.state; + let { confettiCount } = this.props; + let index = confettis.findIndex(confetti => { + return confetti.key === key; + }); + confettis.splice(index, 1); + this.setState({ confettis }); + if (key === confettiCount - 1) { + this.confettiIndex = 0; + } + } - removeConfetti(key) { - let {confettis} = this.state; - let {confettiCount} = this.props; - let index = confettis.findIndex(confetti => {return confetti.key === key}); - confettis.splice(index, 1); - this.setState({confettis}); - if(key === confettiCount - 1) { - this.confettiIndex = 0; - } - } + onPositioned(event) { + let { x, y, width, height } = event.nativeEvent.layout; + this.setState({ width, height }); + } - stopConfetti () - { - this.shouldStop = true; - } + stopConfetti() { + this.shouldStop = true; + } - render() { - let {confettis} = this.state; - let {...otherProps} = this.props - return - {confettis.map(confetti => { - return - })} - - } + render() { + let { confettis } = this.state; + let { ...otherProps } = this.props; + return ( + this.onPositioned(event)} + > + {confettis.map(confetti => { + return ( + + ); + })} + + ); + } } ConfettiView.defaultProps = { - confettiCount: 100, - timeout: 30 -} + confettiCount: 100, + timeout: 30 +}; const styles = StyleSheet.create({ - container: { - position: 'absolute', - top: 0, - left: 0, - right: 0 - } + container: { + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0 + } }); export default ConfettiView; From 55dc2ad5acb40675d2d7400b5a3a1e54b32208d2 Mon Sep 17 00:00:00 2001 From: Jack Thomson Date: Thu, 20 Jul 2017 11:57:38 +0100 Subject: [PATCH 2/2] Fix on unmount --- confettiView.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/confettiView.js b/confettiView.js index 7156092..8159c24 100644 --- a/confettiView.js +++ b/confettiView.js @@ -18,6 +18,12 @@ class ConfettiView extends Component { this.state = { confettis: [], width: windowWidth, height: windowHeight }; this.confettiIndex = 0; this.shouldStop = false; + this.unmounted = false; + } + + componentWillUnmount() { + this.stopConfetti(); + this.unmounted = true; } startConfetti() { @@ -39,6 +45,7 @@ class ConfettiView extends Component { } removeConfetti(key) { + if (this.unmounted === true) return; let { confettis } = this.state; let { confettiCount } = this.props; let index = confettis.findIndex(confetti => {