import React, { memo, useMemo } from 'react'; import cloneDeep from 'lodash/cloneDeep'; import { Cell, Pie, PieChart as RePieChart, Tooltip } from 'recharts'; import Box from '@mui/material/Box'; import Grid from '@mui/material/Grid'; import Typography from '@mui/material/Typography'; import { useTheme } from '@mui/material/styles'; import { CustomTooltip } from './CustomTooltip'; import createClasses from './styles'; import type { DonutProps } from './types'; const Donut = (props: DonutProps) => { const { title = '', subtitle, size, half, data = [], tooltip, tooltipPostfix } = props; const classes = createClasses({ size, title }); const theme = useTheme(); const [chartWidth, lineWidth] = useMemo(() => { // here the 88, 120 and 160 are widths of all variants of donuts, and // 2 added for correct view (if we didn't add it the donut will be cut) switch (size) { case 'xsmall': return [88 + 2, 5]; case 'small': default: return [128 + 2, 8]; case 'large': return [160 + 2, 8]; } }, [size]); const chartHeight = chartWidth / (half ? 2 : 1); // chartHeight - it calculated because if we need to use half donut we need only half of height const outerRadius = (chartWidth - 2) / 2; // here hardcoded "- 2" for correct size because we added in chartWidth 2 const innerRadius = outerRadius - lineWidth; // subtract the thickness of the donut line const margin = half ? chartHeight - 1 : 0; // it need for half donut correct position const textPosition = half ? 'flex-end' : 'center'; // this is for text position, because it not the same for donut and half donut const newData = useMemo(() => { // these calculations are done because in the design of the chart we use rounding // and they close the visibility of the empty option if it is small, for example 49 is filled in and 1 is empty const tempArr = cloneDeep(data); const index = tempArr.findIndex(item => item.name === 'Empty'); if (index > -1) { tempArr[index].color = theme.palette.secondary[200]; } if ( tempArr.length === 2 && tempArr[1].name === 'Empty' && tempArr[1].value !== 0 && tempArr[0].value >= 40 ) { const stepValue = +(tempArr[0].value / 40).toFixed(0) + 1; tempArr[1].value = stepValue > tempArr[1].value ? stepValue : data[1].value; } return [...tempArr].reverse(); }, [data, theme.palette.secondary]); return ( {(title || subtitle) && ( {title && ( {title} )} {subtitle && ( {subtitle} )} )} {newData?.map((entry, index) => ( ))} {tooltip && ( } position={{ y: half ? 10 : undefined }} /> )} ); }; Donut.defaultProps = { size: 'small', data: [ { name: 'Empty', value: 10, color: '#E5EAF6' } ], half: false, tooltip: false }; const m = memo(Donut); export { m as Donut };