@figliolia/rn-donut-chart
Version:
An animated donut/pie chart library
58 lines (57 loc) • 2.52 kB
JavaScript
import { memo, useCallback, useMemo, useState } from "react";
import { Easing, View } from "react-native";
import { Controller } from "./Controller.js";
import { Gradient } from "./Gradient/index.js";
import { Section } from "./Section/index.js";
import { Styles } from "./Styles.js";
import { useController } from "./useController.js";
/**
* ### Donut Chart
*
* A component for creating beautiful responsive
* donuts using React Native
*
* ```tsx
* <DonutChart
* delay={0}
* duration={1500}
* strokeWidth={12}
* strokeLinecap="round"
* style={Styles.yourContrainerStyles}
* data={[{
* label: "rent",
* value: 2000,
* stroke: "rgb(228, 69, 69)",
* style: Styles.yourSVGStyles // such as shadow and stuff
* }]}
* easing={Easing.out(Easing.exp)}
* onMeasure={(dimensions: number) => {}}>
* {children}
* </DonutChart>
* ```
*/
export const DonutChart = memo(function DonutChart({ data, style, children, onMeasure, delay = 0, duration = 1500, strokeWidth = 25, strokeLinecap = "round", easing = Easing.inOut(Easing.exp), }) {
const [width, setWidth] = useState(0);
const gap = useMemo(() => (data.length < 2 ? 0 : strokeWidth * 2), [strokeWidth, data.length]);
const center = useMemo(() => width / 2, [width]);
const radius = useMemo(() => (width - strokeWidth) / 2, [width, strokeWidth]);
const circumference = useMemo(() => 2 * Math.PI * radius, [radius]);
const controller = useController(new Controller(data));
controller.update(data);
const onLayout = useCallback((e) => {
const { width } = e.nativeEvent.layout;
setWidth(width);
onMeasure?.(width);
}, [onMeasure]);
return (<View onLayout={onLayout} style={[Styles.container, style, { height: width }]}>
<View style={Styles.inner}>
{width !== 0 &&
controller.data.map(({ label, style, stroke = "#000" }, i) => {
return (<Section gap={gap} key={label} size={width} delay={delay} style={style} easing={easing} radius={radius} center={center} duration={duration} strokeWidth={strokeWidth} strokeLinecap={strokeLinecap} circumference={circumference} rotation={controller.angles[i]} value={controller.percentages[i]} renderPhase={controller.renderPhase} stroke={Controller.parseStroke(label, stroke)}>
{Controller.renderGradient(stroke) && (<Gradient label={label} colors={stroke}/>)}
</Section>);
})}
</View>
{children}
</View>);
});