├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── pulse-gif.gif
└── pulse.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Chad Sahlhoff
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Native Pulse Animation
2 |
3 | 
4 |
5 | ## Installation
6 |
7 | ```
8 | npm install react-native-pulse --save
9 | ```
10 |
11 | ## Usage
12 |
13 | ```js
14 | const Pulse = require('react-native-pulse').default;
15 |
16 | class helloWorld extends Component {
17 | render() {
18 | return (
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | ```
27 |
28 | ## Props
29 |
30 | Component accepts several self-descriptive properties:
31 |
32 |
33 | - **`color`** _(String)_ - Backgroundcolor for pulse. React-native colors supported. Default color is blue.
34 | - **`diameter`** _(Number)_ - This is the maximum diameter that a pulse will be. Defaults to 400.
35 | - **`duration`** _(Number)_ - Duration in milliseconds this is the delay new pulses will be created. Defaults to 1000.
36 | - **`image`** _(Object)_ - Image for center pulse thumbnail.
37 | - **`initialDiameter`** _(Number)_ - The diameter new pulses will start with. Defaults to 0.
38 | - **`numPulses`** _(Number)_ - This is the number of pulses that will be rendered. Defaults to 3.
39 | - **`pulseStyle`** _(Object)_ - Style properties for pulses (borderColor eg.)
40 | - **`speed`** _(Number)_ - Speed in milliseconds pulse will redraw. Defaults to 10.
41 | - **`style`** _(Object)_ - Style properties for pulse container (positioning eg.)
42 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-pulse",
3 | "version": "1.0.7",
4 | "description": "React Native Pulse Animation",
5 | "main": "pulse.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/sahlhoff/react-native-pulse.git"
12 | },
13 | "keywords": [
14 | "react",
15 | "react-component",
16 | "ios",
17 | "react-native",
18 | "animation",
19 | "ui",
20 | "pulse"
21 | ],
22 | "author": "Chad Sahlhoff",
23 | "license": "ISC",
24 | "bugs": {
25 | "url": "https://github.com/sahlhoff/react-native-pulse/issues"
26 | },
27 | "homepage": "https://github.com/sahlhoff/react-native-pulse#readme"
28 | }
29 |
--------------------------------------------------------------------------------
/pulse-gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sahlhoff/react-native-pulse/3446363ff20eb2df727bc93fe1b5348effe413e7/pulse-gif.gif
--------------------------------------------------------------------------------
/pulse.js:
--------------------------------------------------------------------------------
1 | import React, {
2 | Component
3 | } from 'react';
4 | import PropTypes from 'prop-types';
5 | import {
6 | View,
7 | Text,
8 | Image,
9 | StyleSheet,
10 | } from 'react-native';
11 |
12 | const styles = StyleSheet.create({
13 | container: {
14 | position: 'absolute',
15 | left: 0,
16 | right: 0,
17 | alignItems: 'center'
18 | },
19 | pulse: {
20 | position: 'absolute',
21 | flex: 1
22 | }
23 | });
24 |
25 | export default class Pulse extends Component {
26 | static propTypes = {
27 | color: PropTypes.string,
28 | diameter: PropTypes.number,
29 | duration: PropTypes.number,
30 | image: PropTypes.object,
31 | initialDiameter: PropTypes.number,
32 | numPulses: PropTypes.number,
33 | pulseStyle: PropTypes.object,
34 | speed: PropTypes.number,
35 | style: PropTypes.object
36 | };
37 |
38 | static defaultProps = {
39 | color: 'blue',
40 | diameter: 400,
41 | duration: 1000,
42 | image: null,
43 | initialDiameter: 0,
44 | numPulses: 3,
45 | pulseStyle: {},
46 | speed: 10,
47 | style: {
48 | top: 0,
49 | bottom: 0,
50 | flexDirection: 'row',
51 | justifyContent: 'center',
52 | alignItems: 'center'
53 | }
54 | }
55 |
56 | constructor(props){
57 | super(props);
58 |
59 | this.state = {
60 | color: this.props.color,
61 | duration: this.props.duration,
62 | image: this.props.image,
63 | maxDiameter: this.props.diameter,
64 | numPulses: this.props.numPulses,
65 | pulses: [],
66 | pulseStyle: this.props.pulseStyle,
67 | speed: this.props.speed,
68 | started: false,
69 | style: this.props.style
70 | };
71 | }
72 |
73 | mounted = true;
74 |
75 | componentDidMount(){
76 | const {numPulses, duration, speed} = this.state;
77 |
78 | this.setState({started: true});
79 |
80 | let a = 0;
81 | while(a < numPulses){
82 | this.createPulseTimer = setTimeout(()=>{
83 | this.createPulse(a);
84 | }, a * duration);
85 |
86 | a++;
87 | }
88 |
89 | this.timer = setInterval(() => {
90 | this.updatePulse();
91 | }, speed);
92 | }
93 |
94 | componentWillUnmount(){
95 | this.mounted = false;
96 | clearTimeout(this.createPulseTimer);
97 | clearInterval(this.timer);
98 | }
99 |
100 | createPulse = (pKey) => {
101 | if (this.mounted) {
102 | let pulses = this.state.pulses;
103 |
104 | let pulse = {
105 | pulseKey: pulses.length + 1,
106 | diameter: this.props.initialDiameter,
107 | opacity: .5,
108 | centerOffset: ( this.state.maxDiameter - this.props.initialDiameter ) / 2
109 | };
110 |
111 | pulses.push(pulse);
112 |
113 | this.setState({pulses});
114 | }
115 | }
116 |
117 | updatePulse = () => {
118 | if (this.mounted) {
119 | const pulses = this.state.pulses.map((p, i) => {
120 | let maxDiameter = this.state.maxDiameter;
121 | let newDiameter = (p.diameter > maxDiameter ? 0 : p.diameter + 2);
122 | let centerOffset = ( maxDiameter - newDiameter ) / 2;
123 | let opacity = Math.abs( ( newDiameter / this.state.maxDiameter ) - 1 );
124 |
125 | let pulse = {
126 | pulseKey: i + 1,
127 | diameter: newDiameter,
128 | opacity: (opacity > .5 ? .5 : opacity),
129 | centerOffset: centerOffset
130 | };
131 |
132 | return pulse;
133 |
134 | });
135 |
136 | this.setState({pulses});
137 | }
138 | }
139 |
140 | render(){
141 | const {color, image, maxDiameter, pulses, pulseStyle, started, style} = this.state;
142 | const containerStyle = [styles.container, style];
143 | const pulseWrapperStyle = {width: maxDiameter, height: maxDiameter};
144 |
145 | return (
146 |
147 | {started &&
148 |
149 | {pulses.map((pulse) =>
150 |
166 | )}
167 | {image &&
168 |
172 | }
173 |
174 | }
175 |
176 | )
177 | }
178 | }
179 |
--------------------------------------------------------------------------------