Lightweight but versatile SVG pie/donut charts for React
npm install react-minimal-pie-chart[![Build Status][ci-badge]][ci]
[![Npm version][npm-version-badge]][npm]
[![Coveralls][coveralls-badge]][coveralls]
[![Bundle size][bundlephobia-badge]][bundlephobia]
Lightweight React SVG pie charts, with versatile options and CSS animation included. ~2kB gzipped. [π Demo π][storybook].
width="350px"
src="docs/chart.gif?raw=true"
alt="React minimal pie chart preview"
/>
Because [Recharts][recharts-github] is awesome, but when you just need a simple pie/donought chart, 2kB are usually enough.
| | Size
by Bundlefobia | Benchmark Size \ | Loading time
on a slow 3g \ |
| :----------------------------------------------------: | :-----------------------------------------------------------------------------------------------------: | :---------------: | :-----------------------------: |
| react-minimal-pie-chart (_v9.0.0_) | [![Bundle size: React minimal pie chart][bundlephobia-badge]][bundlephobia] | 1.99 KB | ~40 ms |
| [rechart][recharts-github] (_v1.8.5_) | [![Bundle size: Recharts][recharts-bundlephobia-badge]][recharts-bundlephobia] | 96.9 KB | ~1900 ms |
| [victory-pie][victory-pie-github] (_v34.1.3_) | [![Bundle size: Victory pie][victory-pie-bundlephobia-badge]][victory-pie-bundlephobia] | 50.5 KB | ~1100 ms |
| [react-apexcharts][react-apexcharts-github] (_v1.3.7_) | [![Bundle size: React apec charts][react-apexcharts-bundlephobia-badge]][react-apexcharts-bundlephobia] | 114.6 KB | ~2300 ms |
| [react-vis][react-vis-github] (_v1.11.7_) | [![Bundle size: React vis][react-vis-bundlephobia-badge]][react-vis-bundlephobia] | 78.3 KB | ~1600 ms |
\* Benchmark carried out with size-limit with a "real-world" setup: see benchmark repo. (What matter here are not absolute values but the relation between magnitudes)
- < 2kB gzipped
- Versatile: Pie, Donut, Loading, Completion charts (see [Demo][storybook])
- Customizable chart labels and CSS animations
- Written in Typescript
- No dependencies
``console`
npm install react-minimal-pie-chart
If you don't use a package manager, react-minimal-pie-chart exposes also an UMD module ready for the browser.
``
https://unpkg.com/react-minimal-pie-chart/dist/index.js
Minimum supported Typescript version: >= 3.8
`js
import { PieChart } from 'react-minimal-pie-chart';
{ title: 'One', value: 10, color: '#E38627' },
{ title: 'Two', value: 15, color: '#C13C37' },
{ title: 'Three', value: 20, color: '#6A2135' },
]}
/>;
`
| Property | Type | Description | Default |
| --------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| [data][data-props-docs] | DataEntry[] | Source data. Each entry represents a chart segment | [] |number
| lineWidth | (%) | Line width of each segment. Percentage of chart's radius | 100 |number
| startAngle | | Start angle of first segment | 0 |number
| lengthAngle | | Total angle taken by the chart _(can be negative to make the chart clockwise!)_ | 360 |number
| totalValue | | Total value represented by the full chart | - |number
| paddingAngle | | Angle between two segments | - |boolean
| rounded | | Round line caps of each segment | - |number
| segmentsShift | or:(segmentIndex) => number | Translates segments radially. If number set, provide shift value relative to viewBoxSize space. If function, return a value for each segment._(radius prop might be adjusted to prevent segments from overflowing chart's boundaries)_ | - |CSSObject
| segmentsStyle | or:(segmentIndex) => CSSObject | Style object assigned to each segment. If function, return a value for each segment. (Warning: SVG only supports [its own CSS props][svg-css]). | - |number
| segmentsTabIndex | | tabindex attribute assigned to segments | - |(labelRenderProps) => string \| number \| ReactElement
| [label][label-props-docs] | | A function returning a label value or the [SVG element][svg-elements] to be rendered as label | - |number
| labelPosition | (%) | Label position from origin. Percentage of chart's radius _(50 === middle point)_ | 50 |CSSObject
| labelStyle | or:(segmentIndex) => CSSObject | Style object assigned to each label. If function set, return style for each label. (Warning: SVG only supports [its own CSS props][svg-css]). | - |boolean
| animate | | Animate segments on component mount | - |number
| animationDuration | | Animation duration in ms | 500 |string
| animationEasing | | A CSS easing function | ease-out |number
| reveal | (%) | Turn on CSS animation and reveal just a percentage of each segment | - |string
| background | | Segments' background color | - |ReactElement
| children | (svg) | Elements rendered as children of [SVG element][svg-elements] (eg. SVG defs and gradient elements) | - |number
| radius | (user units) | Radius of the pie (relative to viewBoxSize space) | 50 |[number, number]
| center | | x and y coordinates of center (relative to viewBoxSize space) | [50, 50] |[number, number]
| viewBoxSize | | width and height of SVG viewBox attribute | [100, 100] |(e, segmentIndex) => void
| onBlur | | onBlur event handler for each segment | - |(e, segmentIndex) => void
| onClick | | onClick event handler for each segment | - |(e, segmentIndex) => void
| onFocus | | onFocus event handler for each segment | - |(e, segmentIndex) => void
| onKeyDown | | onKeyDown event handler for each segment | - |(e, segmentIndex) => void
| onMouseOut | | onMouseOut event handler for each segment | - |(e, segmentIndex) => void
| onMouseOver | | onMouseOver event handler for each segment | - |.oOo.oOo.oOo.oOo.oOo.oOo.oOo.
| | | | |
Prop types are exposed for convenience:
`ts`
import type { PieChartProps } from 'react-minimal-pie-chart';
data prop expects an array of chart entries as follows:
`typescript`
type Data = {
color: string;
value: number;
key?: string | number;
title?: string | number;
[key: string]: any;
}[];
Each entry accepts any custom property plus the following optional ones:
- key: custom value to be used as segments element keys
- title: title element rendered as segment's child
label prop accepts a function returning the string, number or element rendered as label for each segment:
`js`
number | string | React.ReactElement | undefined | null
}
/>
The function receives labelRenderProps object as single argument:
`typescript`
type LabelRenderProps = {
x: number;
y: number;
dx: number;
dy: number;
textAnchor: 'start' | 'middle' | 'end' | 'inherit' | undefined;
dataEntry: {
...props.data[dataIndex]
// props.data entry relative to the label extended with:
startAngle: number;
degrees: number;
percentage: number;
};
dataIndex: number;
style: React.CSSProperties;
};
#### Label prop, common scenarios
Render entries' values as labels:
`js`
label={({ dataEntry }) => dataEntry.value}
Render segment's percentage as labels:
`js${Math.round(dataEntry.percentage)} %
label={({ dataEntry }) => }`
See examples in the demo source.
See demo and relative source here and here.
See demo and relative source.
Here is an updated browsers support list π.
The main requirement of this library is an accurate rendering of SVG Stroke properties.
Please consider that Math.sign and Object.assign polyfills are required to support legacy browsers.
- http://xahlee.info/js/svg_circle_arc.html
- https://codepen.io/lingtalfi/pen/yaLWJG
This library uses the stroke-dasharray + stroke-dashoffset animation strategy described here.
- Consider moving storybook deployment to CI
- Consider using transform to mutate segments/labels positionssvg` element with any extra prop
- Consider abstracting React bindings to re-use business logic with other frameworks
- Provide a way to supply
- Find a better solution to assign default props
Thanks to you all (emoji key):
[ci-badge]: https://github.com/toomuchdesign/react-minimal-pie-chart/actions/workflows/ci.yml/badge.svg
[ci]: https://github.com/toomuchdesign/react-minimal-pie-chart/actions/workflows/ci.yml
[coveralls-badge]: https://coveralls.io/repos/github/toomuchdesign/react-minimal-pie-chart/badge.svg?branch=master
[coveralls]: https://coveralls.io/github/toomuchdesign/react-minimal-pie-chart?branch=master
[npm]: https://www.npmjs.com/package/react-minimal-pie-chart
[npm-version-badge]: https://img.shields.io/npm/v/react-minimal-pie-chart.svg
[bundlephobia-badge]: https://badgen.net/bundlephobia/minzip/react-minimal-pie-chart
[bundlephobia]: https://bundlephobia.com/result?p=react-minimal-pie-chart
[recharts-bundlephobia-badge]: https://badgen.net/bundlephobia/minzip/recharts
[recharts-bundlephobia]: https://bundlephobia.com/result?p=recharts
[recharts-github]: https://github.com/recharts/recharts
[victory-pie-bundlephobia-badge]: https://badgen.net/bundlephobia/minzip/victory-pie
[victory-pie-bundlephobia]: https://bundlephobia.com/result?p=victory-pie
[victory-pie-github]: https://github.com/FormidableLabs/victory
[react-apexcharts-bundlephobia-badge]: https://badgen.net/bundlephobia/minzip/apexcharts
[react-apexcharts-bundlephobia]: https://bundlephobia.com/result?p=apexcharts
[react-apexcharts-github]: https://github.com/apexcharts/apexcharts.js
[react-vis-bundlephobia-badge]: https://badgen.net/bundlephobia/minzip/react-vis
[react-vis-bundlephobia]: https://bundlephobia.com/result?p=react-vis
[react-vis-github]: https://github.com/uber/react-vis
[storybook]: https://toomuchdesign.github.io/react-minimal-pie-chart/index.html
[data-props-docs]: #about-data-prop
[label-props-docs]: #custom-labels-with-label-render-prop
[svg-elements]: https://developer.mozilla.org/en-US/docs/Web/SVG/Element
[svg-css]: https://css-tricks.com/svg-properties-and-css/#aa-properties-shared-between-css-and-svg