I am trying to animate the changing of data in my Victory Native Pie Chart. I fetch the data from an API on a recurring timeout set up in the ComponentDidMount method. Once the data is retrieved I set it to a state variable which is passed to the data prop in the VictoryPie component with the animate props enabled as the docs show.
I am following this article and the Victory Chart docs for animations but mine does not behave in the same way as these examples.
Currently it sets the data correctly but without any smooth animation. It instantly jumps from initial state value to the fetched data value. Only time I see an animation is when the fetched data returns a zero value after the previous fetch had a value that wasn't zero.
export default class HaloXPChart extends Component {
constructor(props) {
super(props);
this.state = {
gamertag: this.props.gamertag ? this.props.gamertag : '',
dateRetrievalInterval: 1,
totalXp: 0,
startXp: 0,
spartanRank: 0,
xpChartData: [
{x: 'xp earned', y: 0},
{x: 'xp remaining', y: 1}
],
loading: false
};
}
componentDidMount() {
this.setState({loading: true});
this.recursiveGetData();
}
async recursiveGetData(){
this.setState({indicator: true}, async () => {
await this.getData()
this.setState({indicator: false});
let timeout = setTimeout(() => {
this.recursiveGetData();
}, this.state.dateRetrievalInterval * 60 * 1000);
});
}
async getData(){
await Promise.all([
fetch('https://www.haloapi.com/stats/h5/servicerecords/arena?players=' + this.state.gamertag, fetchInit),
fetch('https://www.haloapi.com/metadata/h5/metadata/spartan-ranks', fetchInit)
])
.then(([res1, res2]) => {
return Promise.all([res1, res2.json()])
}).then(([res1, res2) => {
const xp = res1.Results[0].Result.Xp;
const spartanRank = res1.Results[0].Result.SpartanRank;
this.setState({totalXp: xp});
const currentRank = res2.filter(r => r.id == this.state.spartanRank);
this.setState({startXp: currentRank[0].startXp});
this.setState({loading: false}, () => {
this.setState({xpChartData: [
{x: 'xp earned', y: this.state.totalXp - this.state.startXp},
{x: 'xp remaining', y: 15000000 - (this.state.totalXp - this.state.startXp)}
]});
});
})
.catch((error) => {
console.log(JSON.stringify(error));
})
}
render() {
return(
<View>
<Svg viewBox="0 0 400 400" >
<VictoryPie
standalone={false}
width={400} height={400}
data={this.state.xpChartData}
animate={{
easing: 'exp',
duration: 2000
}}
innerRadius={120} labelRadius={100}
style={{
labels: { display: 'none'},
data: {
fill: ({ datum }) =>
datum.x === 'xp earned' ? '#00f2fe' : 'black'
}
}}
/>
</Svg>
</View>
);
}
}
Try setting endAngle
to 0
initially and set it to 360
when you load the data as described in this GitHub issue:
Note: Pie chart animates when it's data is changed. So set the data initially empty and set the actual data after a delay. If your data is coming from a service call it will do it already.
const PieChart = (props: Props) => {
const [data, setData] = useState<Data[]>([]);
const [endAngle, setEndAngle] = useState(0);
useEffect(() => {
setTimeout(() => {
setData(props.pieData);
setEndAngle(360);
}, 100);
}, []);
return (
<VictoryPie
animate={{
duration: 2000,
easing: "bounce"
}}
endAngle={endAngle}
colorScale={props.pieColors}
data={data}
height={height}
innerRadius={100}
labels={() => ""}
name={"pie"}
padding={0}
radius={({ datum, index }) => index === selectedIndex ? 130 : 120}
width={width}
/>
)