Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/toomuchdesign/react-minimal-pie-chart

🍰 Lightweight but versatile SVG pie/donut charts for React. < 2kB gzipped.
https://github.com/toomuchdesign/react-minimal-pie-chart

pie-chart react-components recharts svg-path typescript

Last synced: about 2 months ago
JSON representation

🍰 Lightweight but versatile SVG pie/donut charts for React. < 2kB gzipped.

Awesome Lists containing this project

README

        

# 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].


React minimal pie chart preview

## Why?

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 (_v8.4.0_) | [![Bundle size: React minimal pie chart][bundlephobia-badge]][bundlephobia] | 1.93 KB | ~39 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](https://github.com/ai/size-limit) with a "real-world" setup: see [benchmark repo](https://github.com/toomuchdesign/react-pie-charts-size). (What matter here are not absolute values but the relation between magnitudes)

## Features

- **< 2kB** gzipped
- Versatile: **Pie**, **Donut**, **Loading**, **Completion** charts (see [Demo][storybook])
- Customizable chart **labels** and **CSS animations**
- Written in **Typescript**
- No dependencies

## Installation

```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`

## Usage

```js
import { PieChart } from 'react-minimal-pie-chart';

;
```

## Options

| Property | Type | Description | Default |
| --------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| [**data**][data-props-docs] | `DataEntry[]` | Source data. Each entry represents a chart segment | [] |
| **lineWidth** | `number` (%) | Line width of each segment. Percentage of chart's radius | 100 |
| **startAngle** | `number` | Start angle of first segment | 0 |
| **lengthAngle** | `number` | Total angle taken by the chart _(can be negative to make the chart clockwise!)_ | 360 |
| **totalValue** | `number` | Total value represented by the full chart | - |
| **paddingAngle** | `number` | Angle between two segments | - |
| **rounded** | `boolean` | Round line caps of each segment | - |
| **segmentsShift** | `number`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)_ | - |
| **segmentsStyle** | `CSSObject`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])*. | - |
| **segmentsTabIndex** | `number` | [`tabindex` attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/tabindex) assigned to segments | - |
| [**label**][label-props-docs] | `(labelRenderProps) => string \| number \| ReactElement` | A function returning a label value or the [SVG element][svg-elements] to be rendered as label | - |
| **labelPosition** | `number` (%) | Label position from origin. Percentage of chart's radius _(50 === middle point)_ | 50 |
| **labelStyle** | `CSSObject`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])*. | - |
| **animate** | `boolean` | Animate segments on component mount | - |
| **animationDuration** | `number` | Animation duration in ms | 500 |
| **animationEasing** | `string` | A [CSS easing function](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-function) | ease-out |
| **reveal** | `number` (%) | Turn on CSS animation and reveal just a percentage of each segment | - |
| **background** | `string` | Segments' background color | - |
| **children** | `ReactElement` (svg) | Elements rendered as children of [SVG element][svg-elements] (eg. SVG `defs` and gradient elements) | - |
| **radius** | `number` (user units) | Radius of the pie (relative to `viewBoxSize` space) | 50 |
| **center** | `[number, number]` | x and y coordinates of center (relative to `viewBoxSize` space) | [50, 50] |
| **viewBoxSize** | `[number, number]` | `width` and `height` of SVG `viewBox` attribute | [100, 100] |
| **onBlur** | `(e, segmentIndex) => void` | `onBlur` event handler for each segment | - |
| **onClick** | `(e, segmentIndex) => void` | `onClick` event handler for each segment | - |
| **onFocus** | `(e, segmentIndex) => void` | `onFocus` event handler for each segment | - |
| **onKeyDown** | `(e, segmentIndex) => void` | `onKeyDown` event handler for each segment | - |
| **onMouseOut** | `(e, segmentIndex) => void` | `onMouseOut` event handler for each segment | - |
| **onMouseOver** | `(e, segmentIndex) => void` | `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';
```

### About `data` prop

`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](https://reactjs.org/docs/lists-and-keys.html)

- **`title`**: [`title` element](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title) rendered as segment's child

### Custom labels with `label` render prop

`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: string;
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
label={({ dataEntry }) => `${Math.round(dataEntry.percentage)} %`}
```

See examples in the [demo source][demo-label-source].

## How to

### User interactions with the chart

See [demo][demo-interaction] and relative source [here][demo-interaction-source] and [here][demo-interaction-2-source].

### Custom tooltip

See [demo][demo-tooltip] and [relative source][demo-tooltip-source].

## Browsers support

Here is an updated [browsers support list πŸ”](https://github.com/toomuchdesign/react-minimal-pie-chart/issues/129).

The main requirement of this library is an accurate rendering of [SVG Stroke properties](https://www.w3schools.com/graphics/svg_stroking.asp).

Please consider that [`Math.sign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign) and [`Object.assign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) polyfills are required to support legacy browsers.

## Misc

### How svg arc paths work?

- http://xahlee.info/js/svg_circle_arc.html
- https://codepen.io/lingtalfi/pen/yaLWJG

### How SVG animations work?

This library uses the `stroke-dasharray` + `stroke-dashoffset` animation strategy [described here](https://css-tricks.com/svg-line-animation-works/).

## Todo's

- Consider moving storybook deployment to CI
- Consider using `transform` to mutate segments/labels positions
- Consider abstracting React bindings to re-use business logic with other frameworks
- Provide a way to supply `svg` element with any extra prop
- Find a better solution to assign default props

## Contributors

Thanks to you all ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):



Andrea Carraro

πŸ’» πŸ“– πŸš‡ ⚠️ πŸ‘€

Stephane Rufer

πŸ› πŸ’»

JΓΈrgen Aaberg

πŸ’»

Tobiah Rex

πŸ›

Edward Xiao

πŸ›

David Konsumer

πŸ’» πŸ“– πŸ’‘ πŸ€”

Ori

πŸ€”



Emmanouil Konstantinidis

πŸ›

yuruc

πŸ’»

luca-esse

πŸ›

Oscar Mendoza

πŸ› πŸ’»

damien-git

πŸ› πŸ€”

Vianney Stroebel

πŸ› πŸ€”

Maxime Zielony

πŸ› πŸ’»



Raz Kedem

πŸ›

Blocksmith

πŸ›

Jamie Talbot

πŸ›

Oscar Yixuan Chen

πŸ›

RuiRocha1991

πŸ›

Roman Kushyn

πŸ›

Divjot Singh

πŸ’»

[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
[demo-interaction]: https://toomuchdesign.github.io/react-minimal-pie-chart/index.html?path=/story/interaction--click-mouseover-mouseout-callbacks
[demo-interaction-source]: https://github.com/toomuchdesign/react-minimal-pie-chart/blob/v8.0.0/stories/InteractionStory.tsx
[demo-interaction-2-source]: https://github.com/toomuchdesign/react-minimal-pie-chart/blob/v8.0.0/stories/InteractionTabStory.tsx
[demo-tooltip]: https://toomuchdesign.github.io/react-minimal-pie-chart/index.html?path=/story/misc--tooltip-integration
[demo-tooltip-source]: https://github.com/toomuchdesign/react-minimal-pie-chart/blob/master/stories/Tooltip.tsx
[demo-label-source]: https://github.com/toomuchdesign/react-minimal-pie-chart/blob/v8.2.0/stories/index.tsx#L81
[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