Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: New: ignoreZeroSegments prop on pie #4107

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 44 additions & 9 deletions demo/component/PieChart.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { Component, ReactElement, ReactSVGElement } from 'react';
import React, { Component } from 'react';
// eslint-disable-next-line import/no-unresolved
import { PieChart, Pie, Legend, Cell, Tooltip, ResponsiveContainer, Sector, Label, LabelList } from 'recharts';
import { scaleOrdinal } from 'victory-vendor/d3-scale';
import { schemeCategory10 } from 'd3-scale-chromatic';
import * as _ from 'lodash';
import mapValues from 'lodash/mapValues';
import { changeNumberOfData } from './utils';

const colors = scaleOrdinal(schemeCategory10).range();
Expand Down Expand Up @@ -50,6 +51,12 @@ const data04 = [
{ name: 'Group B', value: 300, v: 100 },
];

const dataUniqueKey = [
{ name: 'Group A', value: 400, v: 89 },
{ name: 'Group B', value: 0, v: 100 },
{ name: 'Group B', value: 0, v: 100 },
];

const initialState = { data01, data02, data03 };

const renderLabelContent: React.FunctionComponent = (props: any) => {
Expand Down Expand Up @@ -110,10 +117,11 @@ const renderActiveShape: React.FunctionComponent = (props: any) => {
);
};

// eslint-disable-next-line import/no-default-export
export default class Demo extends Component {
static displayName = 'PieChartDemo';

onPieEnter = (data: any, index: number, e: React.MouseEvent) => {
onPieEnter = (data: any, index: number) => {
this.setState({
activeIndex: index,
});
Expand All @@ -126,7 +134,7 @@ export default class Demo extends Component {
};

handleChangeData = () => {
this.setState(() => _.mapValues(initialState, changeNumberOfData));
this.setState(() => mapValues(initialState, changeNumberOfData));
};

handleChangeAnimation = () => {
Expand All @@ -142,21 +150,22 @@ export default class Demo extends Component {
handleLeave = () => this.setState({ activeIndex: -1 });

render() {
const { data01, data02, data03 } = this.state;

return (
<div className="pie-charts">
<a href="javascript: void(0);" className="btn update" onClick={this.handleChangeData}>
<button className="btn update" onClick={this.handleChangeData} type="button">
change data
</a>
</button>
<br />
<p>Simple PieChart</p>
<div className="pie-chart-wrapper">
<button onClick={this.handleChangeAnimation}>change animation</button>
<button onClick={this.handleChangeAnimation} type="button">
change animation
</button>
<PieChart width={800} height={400}>
<Legend />
<Pie data={data01} dataKey="value" cx={200} cy={200} startAngle={180} endAngle={0} outerRadius={80} label>
{data01.map((entry, index) => (
// eslint-disable-next-line react/no-array-index-key
<Cell key={`slice-${index}`} fill={colors[index % 10] as string} />
))}
<Label value="test" position="outside" />
Expand All @@ -176,6 +185,7 @@ export default class Demo extends Component {
isAnimationActive={this.state.animation}
>
{data02.map((entry, index) => (
// eslint-disable-next-line react/no-array-index-key
<Cell key={`slice-${index}`} fill={colors[index % 10] as string} />
))}
<Label width={50} position="center">
Expand Down Expand Up @@ -220,6 +230,7 @@ export default class Demo extends Component {
isAnimationActive={false}
>
{data01.map((entry, index) => (
// eslint-disable-next-line react/no-array-index-key
<Cell key={`slice-${index}`} fill={colors[index % 10] as string} />
))}
<Label value="test" />
Expand All @@ -242,6 +253,7 @@ export default class Demo extends Component {
>
{data01.map((entry, index) => (
<Cell
// eslint-disable-next-line react/no-array-index-key
key={`slice-${index}`}
fill={colors[index % 10] as string}
fillOpacity={this.state.activeIndex === index ? 1 : 0.25}
Expand Down Expand Up @@ -276,6 +288,29 @@ export default class Demo extends Component {
</Pie>
</PieChart>
</div>

<div>
<p>Pie chart with key prop.</p>
<PieChart width={800} height={400}>
<Legend />
<Pie
data={dataUniqueKey}
uniqueKey={({ name, value }) => `${name}-${value}`}
dataKey="value"
// isAnimationActive={false}
cx={200}
cy={200}
startAngle={180}
endAngle={0}
outerRadius={80}
label
ignoreZeroSegments
>
<Cell key="slice-1" fill="green" />
<Cell key="slice-2" fill="blue" />
</Pie>
</PieChart>
</div>
</div>
);
}
Expand Down
147 changes: 82 additions & 65 deletions src/polar/Pie.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ interface PieProps extends PieDef {
onMouseLeave?: (data: any, index: number, e: React.MouseEvent) => void;
onClick?: (data: any, index: number, e: React.MouseEvent) => void;
rootTabIndex?: number;
/** skip rendering elements with "zero" value */
ignoreZeroSegments?: boolean;
}

export interface PieLabelRenderProps extends PieDef {
Expand Down Expand Up @@ -436,80 +438,94 @@ export class Pie extends PureComponent<Props, State> {
const customLabelLineProps = filterProps(labelLine, false);
const offsetRadius = (label && (label as any).offsetRadius) || 20;

const labels = sectors.map((entry, i) => {
const midAngle = (entry.startAngle + entry.endAngle) / 2;
const endPoint = polarToCartesian(entry.cx, entry.cy, entry.outerRadius + offsetRadius, midAngle);
const labelProps = {
...pieProps,
...entry,
stroke: 'none',
...customLabelProps,
index: i,
textAnchor: Pie.getTextAnchor(endPoint.x, entry.cx),
...endPoint,
};
const lineProps = {
...pieProps,
...entry,
fill: 'none',
stroke: entry.fill,
...customLabelLineProps,
index: i,
points: [polarToCartesian(entry.cx, entry.cy, entry.outerRadius, midAngle), endPoint],
key: 'line',
};
let realDataKey = dataKey;
// TODO: compatible to lower versions
if (isNil(dataKey) && isNil(valueKey)) {
realDataKey = 'value';
} else if (isNil(dataKey)) {
realDataKey = valueKey;
}
const labels = sectors
.map((entry, i) => {
if (entry?.value === 0 && this.props.ignoreZeroSegments) return null;
const midAngle = (entry.startAngle + entry.endAngle) / 2;
const endPoint = polarToCartesian(entry.cx, entry.cy, entry.outerRadius + offsetRadius, midAngle);
const labelProps = {
...pieProps,
...entry,
stroke: 'none',
...customLabelProps,
index: i,
textAnchor: Pie.getTextAnchor(endPoint.x, entry.cx),
...endPoint,
};
const lineProps = {
...pieProps,
...entry,
fill: 'none',
stroke: entry.fill,
...customLabelLineProps,
index: i,
points: [polarToCartesian(entry.cx, entry.cy, entry.outerRadius, midAngle), endPoint],
key: 'line',
};
let realDataKey = dataKey;
// TODO: compatible to lower versions
if (isNil(dataKey) && isNil(valueKey)) {
realDataKey = 'value';
} else if (isNil(dataKey)) {
realDataKey = valueKey;
}

return (
<Layer key={`label-${entry.startAngle}-${entry.endAngle}`}>
{labelLine && Pie.renderLabelLineItem(labelLine, lineProps)}
{Pie.renderLabelItem(label, labelProps, getValueByDataKey(entry, realDataKey))}
</Layer>
);
});
return (
<Layer key={`label-${entry.startAngle}-${entry.endAngle}`}>
{labelLine && Pie.renderLabelLineItem(labelLine, lineProps)}
{Pie.renderLabelItem(label, labelProps, getValueByDataKey(entry, realDataKey))}
</Layer>
);
})
.filter(d => d);

return <Layer className="recharts-pie-labels">{labels}</Layer>;
}

renderSectorsStatically(sectors: PieSectorDataItem[]) {
const { activeShape, blendStroke, inactiveShape: inactiveShapeProp } = this.props;
return sectors.map((entry, i) => {
if (entry?.startAngle === 0 && entry?.endAngle === 0 && sectors.length !== 1) return null;
const isActive = this.isActiveIndex(i);
const inactiveShape = inactiveShapeProp && this.hasActiveIndex() ? inactiveShapeProp : null;
const sectorOptions = isActive ? activeShape : inactiveShape;
const sectorProps = {
...entry,
stroke: blendStroke ? entry.fill : entry.stroke,
tabIndex: -1,
};
return (
<Layer
ref={(ref: HTMLElement) => {
if (ref && !this.sectorRefs.includes(ref)) {
this.sectorRefs.push(ref);
}
}}
tabIndex={-1}
className="recharts-pie-sector"
{...adaptEventsOfChild(this.props, entry, i)}
// eslint-disable-next-line react/no-array-index-key
key={`sector-${entry?.startAngle}-${entry?.endAngle}-${entry.midAngle}-${i}`}
>
<Shape option={sectorOptions} isActive={isActive} shapeType="sector" {...sectorProps} />
</Layer>
);
});
const { activeShape, blendStroke, inactiveShape: inactiveShapeProp, ignoreZeroSegments } = this.props;
return sectors
.map((entry, i) => {
if (entry?.startAngle === 0 && entry?.endAngle === 0 && sectors.length !== 1) return null;
if (entry?.value === 0 && ignoreZeroSegments) return null;
const isActive = this.isActiveIndex(i);
const inactiveShape = inactiveShapeProp && this.hasActiveIndex() ? inactiveShapeProp : null;
const sectorOptions = isActive ? activeShape : inactiveShape;
const sectorProps = {
...entry,
stroke: blendStroke ? entry.fill : entry.stroke,
tabIndex: -1,
};
return (
<Layer
ref={(ref: HTMLElement) => {
if (ref && !this.sectorRefs.includes(ref)) {
this.sectorRefs.push(ref);
}
}}
tabIndex={-1}
className="recharts-pie-sector"
{...adaptEventsOfChild(this.props, entry, i)}
// eslint-disable-next-line react/no-array-index-key
key={`sector-${entry?.startAngle}-${entry?.endAngle}-${entry.midAngle}-${i}`}
>
<Shape option={sectorOptions} isActive={isActive} shapeType="sector" {...sectorProps} />
</Layer>
);
})
.filter(d => d);
}

renderSectorsWithAnimation() {
const { sectors, isAnimationActive, animationBegin, animationDuration, animationEasing, animationId } = this.props;
const {
sectors,
isAnimationActive,
animationBegin,
animationDuration,
animationEasing,
animationId,
ignoreZeroSegments,
} = this.props;

const { prevSectors, prevIsAnimationActive } = this.state;

Expand Down Expand Up @@ -552,6 +568,7 @@ export class Pie extends PureComponent<Props, State> {
...entry,
startAngle: curAngle + paddingAngle,
endAngle: curAngle + deltaAngle + paddingAngle,
ignoreZeroSegments: Boolean(ignoreZeroSegments),
};

stepData.push(latest);
Expand Down