├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── demo
├── android.png
└── ios.png
├── package.json
└── src
└── Pie.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | yarn.lock
3 | yarn-error.log
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | demo/
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Neo Nie
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-pie
2 |
3 | Pie chart for React Native, works on both **iOS** and **Android**
4 |
5 | ## Demo
6 |
7 | 
8 | 
9 |
10 | ## Install
11 |
12 | ```bash
13 | # NPM
14 | npm i --save react-native-pie
15 | OR
16 | # Yarn
17 | yarn add react-native-pie
18 | ```
19 |
20 | ## For react-native-pie >= 1.1.0 install peer dependency
21 | ```bash
22 | # NPM
23 | npm i --save @react-native-community/art
24 | OR
25 | # Yarn
26 | yarn add @react-native-community/art
27 | ```
28 |
29 | ## Migration from react-native-pie <= 0.6.2
30 |
31 | Please unlink react-native ART library
32 |
33 | ## Linking module
34 |
35 | ### Mostly automatic linking
36 |
37 | If `react-native` >= 0.60 && react-native-pie >= 1.1.0, the package will be linked automatically.
38 |
39 | ### Manual linking for react-native-pie <= 0.6.2
40 | Link the ART library to your ReactNative project ([how to link a library](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#content)). You'll find the React ART library in `node_modules/react-native/Libraries/ART/ART.xcodeproj`
41 |
42 |
43 | ### React Native Version Support
44 | > **If you are using < `.45`, please install `react-native-pie` `v0.1.0` instead**
45 | > `npm i --save react-native-pie@0.1.0`
46 |
47 | > **Please use >= `0.50.0-rc.0` otherwise there is a ring shape drawing issue with `react-native-pie`**
48 |
49 | ## Usage
50 |
51 | ```jsx
52 | import React from 'react'
53 | import {
54 | StyleSheet,
55 | View,
56 | Text,
57 | } from 'react-native'
58 | import Pie from 'react-native-pie'
59 |
60 | export default () => {
61 | return (
62 |
63 |
71 |
93 |
116 |
117 |
125 |
149 |
173 |
174 |
182 |
205 |
206 |
217 |
220 |
223 | 60%
224 |
225 |
226 |
227 |
228 |
229 | )
230 |
231 | }
232 |
233 | const styles = StyleSheet.create({
234 | container: { alignItems: 'center', justifyContent: 'center', height: 1050 },
235 | gauge: {
236 | position: 'absolute',
237 | width: 100,
238 | height: 160,
239 | alignItems: 'center',
240 | justifyContent: 'center',
241 | },
242 | gaugeText: {
243 | backgroundColor: 'transparent',
244 | color: '#000',
245 | fontSize: 24,
246 | },
247 | })
248 | ```
249 |
250 | ## Props
251 |
252 | * **sections** `{percentage, color}` of each section in the pie - array, **required**
253 | * **radius** `radius = size / 2` , - number, **required**
254 | * **innerRadius** defaults to `0` - number, **optional**
255 | * **backgroundColor** defaults to `#fff` - string, **optional**
256 | * **strokeCap** ( `round` , `butt` ) defaults to `butt` - string, **optional**
257 | * **PLEASE NOTE** If using `strokeCap={'round'}` it is highly recommended to use a higher `innerRadius` (around 60% of `radius` and higher) in addition to not having very small percentage sections. This will ensure proper display. We hope to address these issues in future PRs
258 | * **dividerSize** defaults to `0` - percentage size to divide the sections - number, **optional**
259 |
260 | ## License
261 |
262 | MIT
263 |
264 |
--------------------------------------------------------------------------------
/demo/android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nihgwu/react-native-pie/0687c2a8b49faca05bc0dbeadb55909d7b7af17f/demo/android.png
--------------------------------------------------------------------------------
/demo/ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nihgwu/react-native-pie/0687c2a8b49faca05bc0dbeadb55909d7b7af17f/demo/ios.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-pie",
3 | "version": "1.1.2",
4 | "description": "a pie chart for react native",
5 | "main": "src/Pie.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/nihgwu/react-native-pie.git"
12 | },
13 | "keywords": [
14 | "pie",
15 | "doughnut",
16 | "gauge",
17 | "chart",
18 | "react native"
19 | ],
20 | "author": "Neo (nihgwu@live.com)",
21 | "license": "MIT",
22 | "bugs": {
23 | "url": "https://github.com/nihgwu/react-native-pie/issues"
24 | },
25 | "homepage": "https://github.com/nihgwu/react-native-pie#readme",
26 | "peerDependencies": {
27 | "prop-types": "^15.6.0",
28 | "react": "*",
29 | "react-native": "*",
30 | "@react-native-community/art": "*"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Pie.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {Platform} from 'react-native';
4 | import {Surface, Shape, Path, Group} from '@react-native-community/art';
5 |
6 | function createPath(cx, cy, r, startAngle, arcAngle, isBezian, innerRadius) {
7 | const p = new Path();
8 | //starting point of our chart
9 | if (isBezian) {
10 | const roundnessOutside =
11 | 1 - (r - innerRadius) / innerRadius - arcAngle * 0.5;
12 | const roundnessInside =
13 | 1 + (r - innerRadius) / innerRadius + arcAngle * 0.5;
14 | const pullback = 0.1;
15 | const anchorForward = 0.2;
16 | //This is for the part that is the divider
17 | p.moveTo(
18 | cx + r * roundnessOutside * Math.cos(startAngle + pullback),
19 | cy + r * roundnessOutside * Math.sin(startAngle + pullback),
20 | );
21 | p.onBezierCurve(
22 | undefined,
23 | undefined,
24 | cx + r * roundnessOutside * Math.cos(startAngle + pullback),
25 | cy + r * roundnessOutside * Math.sin(startAngle + pullback),
26 | cx + r * Math.cos(startAngle + anchorForward),
27 | cy + r * Math.sin(startAngle + anchorForward),
28 | cx + r * roundnessInside * Math.cos(startAngle + pullback),
29 | cy + r * roundnessInside * Math.sin(startAngle + pullback),
30 | );
31 | } else {
32 | //This is for the main arc of the pie chart
33 | p.moveTo(cx + r * Math.cos(startAngle), cy + r * Math.sin(startAngle));
34 | p.onArc(
35 | undefined,
36 | undefined,
37 | undefined,
38 | undefined,
39 | cx,
40 | cy,
41 | r,
42 | r,
43 | startAngle,
44 | startAngle + arcAngle,
45 | );
46 | }
47 | return p;
48 | }
49 |
50 | const ArcShape = ({
51 | dimensions,
52 | color,
53 | strokeCap,
54 | startAngle,
55 | arcAngle,
56 | isBezian,
57 | }) => {
58 | const {radius, innerRadius, width, dividerSize} = dimensions;
59 | const path = createPath(
60 | radius,
61 | radius,
62 | radius - width / 2,
63 | (startAngle / 180) * Math.PI,
64 | (arcAngle / 180) * Math.PI,
65 | isBezian,
66 | innerRadius,
67 | );
68 | const strokeWidth = isBezian ? arcAngle * 5 : width;
69 | return (
70 |
76 | );
77 | };
78 |
79 | //The initial band to set the backgroundColor behind the pie chart
80 | const Background = ({dimensions, color}) => {
81 | return (
82 |
88 | );
89 | };
90 |
91 | const getArcAngle = percentage => (percentage / 100) * 360;
92 | const shouldShowDivider = (sections, dividerSize) =>
93 | sections.length > 1 && !Number.isNaN(dividerSize);
94 |
95 | const Sections = ({
96 | dimensions,
97 | paintedSections,
98 | sections,
99 | shouldShowRoundDividers,
100 | strokeCapForLargeBands,
101 | }) => {
102 | let startValue = 0;
103 | const {radius, width, dividerSize} = dimensions;
104 | const showDividers = shouldShowDivider(sections, dividerSize);
105 | paintedSections = sections.map((section, idx) => {
106 | const {percentage, color} = section;
107 | const startAngle = (startValue / 100) * 360;
108 | const arcAngle = getArcAngle(percentage);
109 | startValue += percentage;
110 | shouldShowRoundDividers &&
111 | paintedSections.push({percentage, color, startAngle, arcAngle});
112 | return (
113 |
121 | );
122 | });
123 | return paintedSections;
124 | };
125 |
126 | // These are the rounded dividers when strokeCap='round'
127 | const RoundDividers = ({
128 | dimensions,
129 | paintedSections,
130 | backgroundColor,
131 | visible,
132 | }) => {
133 | const {dividerSize, radius, innerRadius, width} = dimensions;
134 | const dividerOffSet = dividerSize * 2 + 6;
135 | const strokeCap = 'butt';
136 | const isBezian = true;
137 | let dividerColorOverlayArray = [];
138 | let dividerArray = [];
139 |
140 | if (paintedSections.length > 1 && visible) {
141 | paintedSections.forEach((section, index) => {
142 | const {color, startAngle} = section;
143 |
144 | for (let i = 0; i < dividerSize + 2; i++) {
145 | dividerArray.push(
146 | ,
157 | );
158 | dividerColorOverlayArray.push(
159 | ,
170 | );
171 | }
172 | });
173 | }
174 | return (
175 |
176 | {dividerArray}
177 | {dividerColorOverlayArray}
178 |
179 | );
180 | };
181 |
182 | // These circles clean up the strokes left over from the bezian curves
183 | const CleanUpCircles = ({dimensions, backgroundColor, visible}) => {
184 | const {radius, innerRadius, width} = dimensions;
185 | const innerBackgroundPath = createPath(
186 | radius,
187 | radius,
188 | innerRadius - width / 2,
189 | 0,
190 | 360,
191 | );
192 | const outerBackgroundPath = createPath(
193 | radius,
194 | radius,
195 | radius + width / 2,
196 | 0,
197 | 360,
198 | );
199 | if (width < 100 && visible) {
200 | return (
201 | <>
202 |
207 |
212 | >
213 | );
214 | }
215 | return null;
216 | };
217 |
218 | const Pie = ({
219 | sections,
220 | radius,
221 | innerRadius,
222 | backgroundColor,
223 | strokeCap,
224 | dividerSize,
225 | }) => {
226 | strokeCapForLargeBands =
227 | dividerSize > 0 || strokeCap == 'butt' ? 'butt' : 'butt';
228 | const shouldShowRoundDividers = strokeCap === 'round';
229 | let paintedSections = [];
230 |
231 | // This is the width for the arc
232 | const width = radius - innerRadius;
233 | const dimensions = {radius, innerRadius, width, dividerSize};
234 |
235 | return (
236 |
237 |
238 |
239 |
246 |
252 |
257 |
258 |
259 | );
260 | };
261 |
262 | export default Pie;
263 |
264 | Pie.propTypes = {
265 | sections: PropTypes.arrayOf(
266 | PropTypes.exact({
267 | percentage: PropTypes.number.isRequired,
268 | color: PropTypes.string.isRequired,
269 | }),
270 | ).isRequired,
271 | radius: PropTypes.number.isRequired,
272 | innerRadius: PropTypes.number,
273 | backgroundColor: PropTypes.string,
274 | strokeCap: PropTypes.string,
275 | dividerSize: PropTypes.number,
276 | };
277 |
278 | Pie.defaultProps = {
279 | dividerSize: 0,
280 | innerRadius: 0,
281 | backgroundColor: '#fff',
282 | strokeCap: 'butt',
283 | };
284 |
--------------------------------------------------------------------------------