Donut

Donut Charts are Circular charts which represent a variation of the Pie Charts and are capable of displaying multiple nested series.

You can utilize the blank center of a Donut Chart to show additional information in it.

Basic Usage

The following example demonstrates the Donut Chart in action.

import React from 'react';
import ReactDOM from 'react-dom';

import {
  Chart,
  ChartLegend,
  ChartSeries,
  ChartSeriesItem,
  ChartSeriesLabels
} from '@progress/kendo-react-charts';

import data from './power-distribution-data.json';

const labelContent = (e) => (e.category);

const ChartContainer = () => (
  <Chart>
    <ChartSeries>
      <ChartSeriesItem type="donut" data={data} categoryField="kind" field="share">
        <ChartSeriesLabels color="#fff" background="none" content={labelContent} />
      </ChartSeriesItem>
    </ChartSeries>
    <ChartLegend visible={false} />
  </Chart>
);

ReactDOM.render(
  <ChartContainer />,
  document.querySelector('my-app')
);
[ {
    "kind": "Hydroelectric", "share": 0.175
}, {
    "kind": "Nuclear", "share": 0.238
}, {
    "kind": "Coal", "share": 0.118
}, {
    "kind": "Solar", "share": 0.052
}, {
    "kind": "Wind", "share": 0.225
}, {
    "kind": "Other", "share": 0.192
} ]

Displaying Multiple Series

The Donut Chart renders multiple series in the form of concentric rings. This behavior is different from the behavior of the Pie Chart, which supports only one series.

import React from 'react';
import ReactDOM from 'react-dom';

import internetGrowthData from './donut-series-data.json';

import {
  Chart,
  ChartTitle,
  ChartLegend,
  ChartArea,
  ChartTooltip,
  ChartSeries,
  ChartSeriesItem,
  ChartSeriesLabels
} from '@progress/kendo-react-charts';

const labelContent = (e) => (`${ e.category }: \n ${e.value}%`);

const ChartContainer = () => {
    const mapSeries = (series, index, array) => (
      <ChartSeriesItem
        type="donut"
        startAngle={150}
        name={series.name}
        data={series.data}
        field="value"
        categoryField="category"
        colorField="color"
      >
        {
          index === array.length - 1
          && <ChartSeriesLabels
                position="outsideEnd"
                background="none"
                content={labelContent} />
        }
      </ChartSeriesItem>
    );
    const renderTooltip = (context) => {
        const { category, series, value } = context.point || context;
        return (<div>{category} ({series.name}): {value}%</div>);
    };

    return (
      <Chart>
        <ChartTooltip render={renderTooltip} />
        <ChartTitle text="Share of Internet Population Growth" />
        <ChartLegend visible={false} />
        <ChartArea background="none" />
        <ChartSeries>
          {internetGrowthData.map(mapSeries)}
        </ChartSeries>
      </Chart>
    );
};

ReactDOM.render(
  <ChartContainer />,
  document.querySelector('my-app')
);
[{
  "name": "2011",
  "data": [{
    "category": "Asia",
    "value": 30.8,
    "color": "#9de219"
  }, {
    "category": "Europe",
    "value": 21.1,
    "color": "#90cc38"
  }, {
    "category": "Latin America",
    "value": 16.3,
    "color": "#068c35"
  }, {
    "category": "Africa",
    "value": 17.6,
    "color": "#006634"
  }, {
    "category": "Middle East",
    "value": 9.2,
    "color": "#004d38"
  }, {
    "category": "North America",
    "value": 4.6,
    "color": "#033939"
  }]
}, {
  "name": "2012",
  "data": [{
    "category": "Asia",
    "value": 53.8,
    "color": "#9de219"
  }, {
    "category": "Europe",
    "value": 16.1,
    "color": "#90cc38"
  }, {
    "category": "Latin America",
    "value": 11.3,
    "color": "#068c35"
  }, {
    "category": "Africa",
    "value": 9.6,
    "color": "#006634"
  }, {
    "category": "Middle East",
    "value": 5.2,
    "color": "#004d38"
  }, {
    "category": "North America",
    "value": 3.6,
    "color": "#033939"
  }]
}]

Displaying Information in the Center

To display content in the center of the Donut Chart, either:

Using the Center Template

The center template is an HTML overlay that is positioned over the center of the Donut Chart. To implement the content use the donutCenterRender render prop of the Chart component.

While documents which are exported through the HTML Drawing API display the content of the center template, vector graphics and exported files do not render it.

import React from 'react';
import ReactDOM from 'react-dom';

import {
  Chart,
  ChartLegend,
  ChartSeries,
  ChartSeriesItem,
  ChartSeriesLabels
} from '@progress/kendo-react-charts';

import data from './power-distribution-data.json';

const donutCenterRenderer = () => (<span><h3>22.5%</h3> of which renewables</span>);
const labelContent = (e) => (e.category);

const ChartContainer = () => (
  <Chart donutCenterRender={donutCenterRenderer}>
    <ChartSeries>
      <ChartSeriesItem type="donut" data={data} categoryField="kind" field="share">
        <ChartSeriesLabels color="#fff" background="none" content={labelContent} />
      </ChartSeriesItem>
    </ChartSeries>
    <ChartLegend visible={false} />
  </Chart>
);

ReactDOM.render(
  <ChartContainer />,
  document.querySelector('my-app')
);
[ {
    "kind": "Hydroelectric", "share": 0.175
}, {
    "kind": "Nuclear", "share": 0.238
}, {
    "kind": "Coal", "share": 0.118
}, {
    "kind": "Solar", "share": 0.052
}, {
    "kind": "Wind", "share": 0.225
}, {
    "kind": "Other", "share": 0.192
} ]

Using Drawing Visuals

Similar to the other Chart types, you can overlay the Donut series with custom drawing elements. The approach of using drawing visuals is more flexible than using the donut center template and also has the advantage that the overlay is part of the chart drawing surface. As a result, all exported files render the content of the donut center as an integral element of the component.

import React from 'react';
import ReactDOM from 'react-dom';

import { Circle as CircleGeometry } from '@progress/kendo-drawing/geometry';
import { Layout, Text } from '@progress/kendo-drawing';

import {
  Chart,
  ChartLegend,
  ChartSeries,
  ChartSeriesItem,
  ChartSeriesLabels
} from '@progress/kendo-react-charts';

import data from './power-distribution-data.json';

let center;
let radius;

const labelContent = (e) => (e.category);
const visualHandler = (e) => {
    // Obtain parameters for the segments
    center = e.center;
    radius = e.innerRadius;

    // Create default visual
    return e.createVisual();
};
const onRender = (e) => {
    // The center and radius are populated by now.
    // We can ask a circle geometry to calculate the bounding rectangle for us.
    //
    // http://www.telerik.com/kendo-react-ui/components/drawing/api/geometry/Circle/
    const circleGeometry = new CircleGeometry(center, radius);
    const bbox = circleGeometry.bbox();

    // Render the text
    //
    // http://www.telerik.com/kendo-react-ui/components/drawing/api/Text/
    const heading = new Text('22.5%', [ 0, 0 ], {
        font: '28px Verdana,Arial,sans-serif'
    });

    const line1 = new Text('of which', [ 0, 0 ], {
        font: '16px Verdana,Arial,sans-serif'
    });

    const line2 = new Text('renewables', [ 0, 0 ], {
        font: '16px Verdana,Arial,sans-serif'
    });

    // Reflow the text in the bounding box
    //
    // http://www.telerik.com/kendo-react-ui/components/drawing/api/Layout
    // http://www.telerik.com/kendo-react-ui/components/drawing/api/LayoutOptions
    const layout = new Layout(bbox, {
        alignContent: 'center',
        alignItems: 'center',
        justifyContent: 'center',
        spacing: 5
    });

    layout.append(heading, line1, line2);
    layout.reflow();

    // Draw it on the Chart drawing surface
    //
    // http://www.telerik.com/kendo-react-ui/components/charts/api/Chart/#toc-surface
    e.target.surface.draw(layout);
};

const ChartContainer = () => (
  <Chart onRender={onRender}>
    <ChartSeries>
      <ChartSeriesItem type="donut" data={data} categoryField="kind" field="share" visual={visualHandler}>
        <ChartSeriesLabels color="#fff" background="none" content={labelContent} />
      </ChartSeriesItem>
    </ChartSeries>
    <ChartLegend visible={false} />
  </Chart>
);

ReactDOM.render(
  <ChartContainer />,
  document.querySelector('my-app')
);
[ {
    "kind": "Hydroelectric", "share": 0.175
}, {
    "kind": "Nuclear", "share": 0.238
}, {
    "kind": "Coal", "share": 0.118
}, {
    "kind": "Solar", "share": 0.052
}, {
    "kind": "Wind", "share": 0.225
}, {
    "kind": "Other", "share": 0.192
} ]

In this article