Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions src/polar/Pie.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ interface PieDef {
/** The inner radius of sectors */
innerRadius?: number | string;
/** The outer radius of sectors */
outerRadius?: number | string;
outerRadius?: number | string | ((dataPoint: any) => number);
cornerRadius?: number | string;
}

Expand Down Expand Up @@ -340,22 +340,36 @@ const getTextAnchor = (x: number, cx: number) => {
return 'middle';
};

const getOuterRadius = (
dataPoint: any,
outerRadius?: number | string | ((element: any) => number),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: for consistent interface this should be updated too

But it's not outward facing so all good

maxPieRadius?: number,
) => {
if (typeof outerRadius === 'function') {
return outerRadius(dataPoint);
}
return getPercentValue(outerRadius, maxPieRadius, maxPieRadius * 0.8);
};

const parseCoordinateOfPie = (
item: {
cx?: number | string;
cy?: number | string;
innerRadius?: number | string;
outerRadius?: number | string;
outerRadius?: number | string | ((dataPoint: any) => number);
maxRadius?: number;
},
offset: ChartOffset,
dataPoint: any,
): PieCoordinate => {
const { top, left, width, height } = offset;
const maxPieRadius = getMaxRadius(width, height);
const cx = left + getPercentValue(item.cx, width, width / 2);
const cy = top + getPercentValue(item.cy, height, height / 2);
const innerRadius = getPercentValue(item.innerRadius, maxPieRadius, 0);
const outerRadius = getPercentValue(item.outerRadius, maxPieRadius, maxPieRadius * 0.8);

const outerRadius = getOuterRadius(dataPoint, item.outerRadius, maxPieRadius);

const maxRadius = item.maxRadius || Math.sqrt(width * width + height * height) / 2;

return { cx, cy, innerRadius, outerRadius, maxRadius };
Expand Down Expand Up @@ -423,15 +437,14 @@ export function computePieSectors({
paddingAngle?: number;
minAngle?: number;
innerRadius?: number | string;
outerRadius?: number | string;
outerRadius?: number | string | ((dataPoint: any) => number);
cornerRadius?: number | string;
presentationProps?: Record<string, string>;
};
offset: ChartOffset;
}): { sectors: ReadonlyArray<PieSectorDataItem>; coordinate: PieCoordinate } {
}): { sectors: ReadonlyArray<PieSectorDataItem> } {
const { cornerRadius, startAngle, endAngle, dataKey, nameKey, tooltipType } = pieSettings;
const minAngle = Math.abs(pieSettings.minAngle);
const coordinate = parseCoordinateOfPie(pieSettings, offset);
const deltaAngle = parseDeltaAngle(startAngle, endAngle);
const absDeltaAngle = Math.abs(deltaAngle);
const paddingAngle = displayedData.length <= 1 ? 0 : (pieSettings.paddingAngle ?? 0);
Expand All @@ -451,6 +464,7 @@ export function computePieSectors({
sectors = displayedData.map((entry: any, i: number) => {
const val = getValueByDataKey(entry, dataKey, 0);
const name = getValueByDataKey(entry, nameKey, i);
const coordinate = parseCoordinateOfPie(pieSettings, offset, entry);
const percent = (isNumber(val) ? val : 0) / sum;
let tempStartAngle;

Expand Down Expand Up @@ -497,12 +511,10 @@ export function computePieSectors({
payload: entryWithCellInfo,
paddingAngle: mathSign(deltaAngle) * paddingAngle,
};

return prev;
});
}

return { sectors, coordinate };
return { sectors };
}

export class PieWithState extends PureComponent<InternalProps, State> {
Expand Down
2 changes: 1 addition & 1 deletion src/state/selectors/pieSelectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export type ResolvedPieSettings = {
paddingAngle?: number;
minAngle?: number;
innerRadius?: number | string;
outerRadius?: number | string;
outerRadius?: number | string | ((element: any) => number);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Same here

cornerRadius?: number | string;
presentationProps?: Record<string, string>;
};
Expand Down
6 changes: 3 additions & 3 deletions storybook/stories/API/polar/Pie.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ const GeneralProps: Args = {
},
outerRadius: {
description: `The outer radius of all the sectors. If set a percentage, the final value is
obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy.`,
obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy.
If set a function, the function will be called to return customized radius.`,
table: {
type: { summary: 'percentage | number', defaultValue: '80%' },
type: { summary: 'percentage | number | Function', defaultValue: '80%' },
category: 'General',
},
},

startAngle: {
description: 'The start angle of first sector.',
table: {
Expand Down
40 changes: 40 additions & 0 deletions storybook/stories/Examples/Pie/PieWithStep.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import { Args } from '@storybook/react';
import { Pie, PieChart, ResponsiveContainer } from '../../../../src';

const data = [
{ value: 'Luck', percent: 10, customRadius: 140 },
{ value: 'Skill', percent: 20, customRadius: 160 },
{ value: 'Concentrated power of will', percent: 15, customRadius: 150 },
{ value: 'Pleasure', percent: 50, customRadius: 190 },
{ value: 'Pain', percent: 50, customRadius: 190 },
{ value: 'Reason to remember the name', percent: 100, customRadius: 220 },
];

export default {
component: Pie,
};

export const PieWithStep = {
render: (args: Args) => {
return (
<ResponsiveContainer width="100%" height={500}>
<PieChart width={400} height={400}>
<Pie dataKey="percent" {...args} />
</PieChart>
</ResponsiveContainer>
);
},
args: {
cx: '50%',
cy: '50%',
data,
dataKey: 'percent',
nameKey: 'value',
fill: '#8884d8',
label: true,
outerRadius: (element: any) => {
return element.customRadius;
},
},
};
62 changes: 62 additions & 0 deletions test/chart/PieChart.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -406,4 +406,66 @@ describe('<PieChart />', () => {
expect(container.querySelectorAll('.label-custom-className')).toHaveLength(6);
expect(container.querySelectorAll('.label-line-custom-className')).toHaveLength(6);
});

describe('PieChart sector radius rendering', () => {
const assertSectorRadius = (element: Element, radius: number) => {
// Checks if the 'd' attribute has an arc with the specified radius.
const dAttribute = element.getAttribute('d');
const arcRadius = new RegExp(`A ${radius},${radius}`);
expect(dAttribute).toMatch(arcRadius);
};

it('renders sectors with a constant radius', () => {
const outerRadius = 80;
const { container } = render(
<PieChart width={800} height={400}>
<Pie
dataKey="value"
isAnimationActive={false}
data={[
{ name: 'Group A', value: 400 },
{ name: 'Group B', value: 300 },
]}
cx={200}
cy={200}
outerRadius={outerRadius}
fill="#ff7300"
/>
</PieChart>,
);

const elementA = container.querySelector('path[name="Group A"]');
assertSectorRadius(elementA, outerRadius);

const elementB = container.querySelector('path[name="Group B"]');
assertSectorRadius(elementB, outerRadius);
});

it('renders sectors with radius based on outerRadius function', () => {
const { container } = render(
<PieChart width={800} height={400}>
<Pie
dataKey="value"
isAnimationActive={false}
data={[
{ name: 'Group A', value: 400 },
{ name: 'Group B', value: 300 },
]}
cx={200}
cy={200}
outerRadius={(element: any) => {
return element.value / 10;
}}
fill="#ff7300"
/>
</PieChart>,
);

const elementA = container.querySelector('path[name="Group A"]');
assertSectorRadius(elementA, 40);

const elementB = container.querySelector('path[name="Group B"]');
assertSectorRadius(elementB, 30);
});
});
});
Loading