胜利本机饼图动画

Victory Native Pie Chart Animation

我正在尝试为我的 Victory Native Pie Chart 中的数据变化设置动画。我在 ComponentDidMount 方法中设置的重复超时从 API 获取数据。检索到数据后,我将其设置为状态变量,该变量传递给 VictoryPie 组件中的数据道具,并启用了动画道具,如文档所示。

我正在关注此 article and the Victory Chart docs for animations,但我的行为与这些示例不同。

目前它设置数据正确但没有任何流畅的动画。它立即从初始状态值跳转到获取的数据值。只有一次我看到动画是当获取的数据 returns 在上一次获取的值不为零之后的零值时。

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>
        );
    }
}

最初尝试将 endAngle 设置为 0,并在加载数据时将其设置为 360,如 this GitHub issue:

中所述

注意:饼图在数据更改时会显示动画。因此,最初将数据设置为空,并在延迟后设置实际数据。如果您的数据来自服务调用,它会执行此操作。

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}
   />
)