react-minimal-pie-chart

Lightweight but versatile SVG pie/donut charts for React

Usage no npm install needed!

<script type="module">
  import reactMinimalPieChart from 'https://cdn.skypack.dev/react-minimal-pie-chart';
</script>

README

React minimal pie chart

Build Status Npm version Coveralls Bundle size

Lightweight React SVG pie charts, with versatile options and CSS animation included. < 2kB gzipped. πŸ‘ Demo πŸ‘.

React minimal pie chart preview

Why?

Because Recharts is awesome, but when you just need a simple pie/donought chart, 3kB 2kB are usually enough.

Size
by Bundlefobia
Benchmark Size * Loading time
on a slow 3g *
react-minimal-pie-chart (v8.2.0) Bundle size: React minimal pie chart 1.83 KB ~38 ms
rechart (v1.8.5) Bundle size: Recharts 96.9 KB ~1900 ms
victory-pie (v34.1.3) Bundle size: Victory pie 50.5 KB ~1100 ms
react-apexcharts (v1.3.7) Bundle size: React apec charts 114.6 KB ~2300 ms
react-vis (v1.11.7) Bundle size: React vis 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)

Features

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

Installation

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

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

<PieChart
  data={[
    { title: 'One', value: 10, color: '#E38627' },
    { title: 'Two', value: 15, color: '#C13C37' },
    { title: 'Three', value: 20, color: '#6A2135' },
  ]}
/>;

Options

Property Type Description Default
data 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 -
segmentsTabIndex number tabindex attribute assigned to segments -
label (labelRenderProps) => string \| number \| ReactElement A function returning a label value or the SVG element 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 -
animate boolean Animate segments on component mount -
animationDuration number Animation duration in ms 500
animationEasing string A CSS easing 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 (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.

About data prop

data prop expects an array of chart entries as follows:

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:

Custom labels with label render prop

label prop accepts a function returning the string, number or element rendered as label for each segment:

<PieChart
  label={(labelRenderProps: LabelRenderProps) =>
    number | string | React.ReactElement | undefined | null
  }
/>

The function receives labelRenderProps object as single argument:

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:

label={({ dataEntry }) => dataEntry.value}

Render segment's percentage as labels:

label={({ dataEntry }) => `${Math.round(dataEntry.percentage)} %`}

See examples in the demo source.

How to

User interactions with the chart

See demo and relative source here and here.

Custom tooltip

See demo and relative source.

Browsers support

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.

Misc

How svg arc paths work?

How SVG animations work?

This library uses the stroke-dasharray + stroke-dashoffset animation strategy described here.

Todo's

  • Consider moving storybook deployment to CI
  • Consider using transform to mutate segments/labels positions
  • Consider exposing a reduced chart variation including just a subset of the features
  • Consider abstracting React bindings to re-use business logic with other frameworks
  • Remove defaultProps in favour of JS default arguments
  • Provide a way to supply svg element with any extra prop
  • Consider removing import type declaration from generated type definition files (if possible) to ensure Typescript 3.0+ backward compatibility

Contributors

Thanks to you all (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

πŸ’»