-
Notifications
You must be signed in to change notification settings - Fork 2
/
Donut.js
104 lines (98 loc) · 2.81 KB
/
Donut.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import * as React from 'react';
import {View} from 'react-native';
import Svg, {G, Circle} from 'react-native-svg';
import {useEffect, useState} from 'react';
export default function Donut(props = []) {
const {
data,
radius = 80,
fill = 'transparent',
strokeWidth = 10,
strokeLinejoin = 'round',
gap = 3,
bgStrokeColor = 'green',
bgStrokeOpacity = '.1',
bgStrokePadding = 0,
} = props;
const halfCircle = radius + strokeWidth;
let lastOffsetRotation = 0;
const [state, setState] = useState({
max: 100,
circumference: 33,
radius: 80,
fill: 'transparent',
strokeWidth: 10,
strokeLinejoin: 'round',
gap: 3,
bgStrokeColor: 'green',
bgStrokeOpacity: '.1',
bgStrokePadding: 0,
});
useEffect(() => {
if (!data) {
return;
}
const newMax = data.reduce((p, c) => {
return p + c.value;
}, 0);
const circumference = 2 * Math.PI * radius;
setState({
max: newMax,
circumference,
radius,
fill,
strokeWidth,
strokeLinejoin,
gap,
bgStrokeColor,
bgStrokeOpacity,
bgStrokePadding
});
}, [data, props, radius]);
return (
<View style={{width: state.radius * 2, height: state.radius * 2}}>
<Svg
height={state.radius * 2}
width={state.radius * 2}
viewBox={`0 0 ${halfCircle * 2} ${halfCircle * 2}`}>
<G rotation="-90" origin={`${halfCircle}, ${halfCircle}`}>
<Circle
cx="50%"
cy="50%"
r={state.radius}
fill={state.fill}
stroke={state.bgStrokeColor}
strokeWidth={state.strokeWidth + bgStrokePadding}
strokeLinejoin={state.strokeLinejoin}
strokeOpacity={state.bgStrokeOpacity}
/>
{!!data && data.map((p, i) => {
const totalGap = state.gap * data.length;
const startOffset = state.circumference - totalGap;
const endOffset = (p.value * state.circumference) / state.max;
const currentRotation =
(p.value * 360) / state.max + lastOffsetRotation;
lastOffsetRotation = currentRotation;
return (
<Circle
key={i}
cx="50%"
cy="50%"
r={state.radius}
originX={state.radius + state.strokeWidth}
originY={state.radius + state.strokeWidth}
rotation={currentRotation}
stroke={p.color}
strokeWidth={state.strokeWidth}
strokeLinecap={state.strokeLinejoin}
strokeDashoffset={startOffset + endOffset}
strokeDasharray={state.circumference}
// fill="red"
/>
);
})}
</G>
</Svg>
</View>
);
}