import React from "react";
import { useEffect, useState, useRef } from "react";
import * as ANI from "anichart";
import {format} from 'd3';
import PlayButton from "./PlayButton/PlayButton";
interface DynamicBarProps {
theme: "light" | "dark";
width: number;
height: number;
barNumber: number;
digitNumber: number;
dataUrl: string;
duration: number;
dateLabelSize: number;
}
const DynamicBar: React.FC<DynamicBarProps> = (props) => {
const { theme, width, height, barNumber, digitNumber, dataUrl, duration, dateLabelSize } = props;
const canvasEL = useRef(null);
const [playing, setPlaying] = useState(false);
let stage: ANI.Stage;
const play = () => {
stage.interval = null; // 黑技巧:stage.doPlay()需要stage.interval=null
stage.sec = 0; // 回到第1帧
stage.play(); // 加载Recourse中的数据后调用stage.doPlay()
setPlaying(true);
// 没有提供播放结束的回调,自己黑一个
setTimeout(() => {
setPlaying(false);
}, (duration + 1) * 1000);
};
// 载入数据到Recourse数据中心
useEffect(() => {
let idSet = new Set<string>();
ANI.recourse.loadCSV(dataUrl, "data").then(() => {
// 迫不得已调用了setup,之后stage.play()时还会调用一次
ANI.recourse.setup().then(() => {
// 提取id集合在BarChart.ts中实现过了,但是为private方法,没法直接调用
ANI.recourse.data
.get("data")
.forEach((item: any) => idSet.add(item.id));
// 遍历idSet载入头像图片到Recourse数据中心
idSet.forEach((username) => {
// Github获取用户头像的api,先写死在这里,以后再做得更通用
ANI.recourse.loadImage(
`https://avatars.githubusercontent.com/${username}?s=128&v=4`,
username
);
});
});
});
}, []);
useEffect(() => {
stage = new ANI.Stage(canvasEL.current as any);
stage.options.fps = 30;
stage.options.sec = duration;
stage.output = false;
const barChart = new ANI.BarChart({
dataName: "data", // 使用的数据的名称,默认就是“data”
idField: "id", // 别换成“username”之类的,因为源码一些地方写死了
showDateLabel: true, // 是否显示右下角的日期
itemCount: barNumber, // bar的数量,就算没有bar也会占位相应数量
aniTime: [0, duration], //动画起始、终止时刻,总时间不要超过stage.options.sec
swapDurationMS: 300, // 排名变动时,bar交换时的动画时间
showRankLabel: false, // 是否在左边显示排名序号
margin: {left: 20, right: 20, top: 20, bottom: 20},
dateLabelOptions: {
fontSize: dateLabelSize,
fillStyle: "#777",
textAlign: "right",
fontWeight: "bolder",
textBaseline: "alphabetic",
position: {
x: stage.canvas.width - 20,
y: stage.canvas.height - 20
},
},
valueFormat: (cData: any) => {return format(`,.${digitNumber}f`)(cData["value"]);},
interpolateInitValue: 0,
});
stage.addChild(barChart);
});
// 初次渲染时,显示播放结束时的帧
useEffect(() => {
stage.render(duration);
}, []);
return (
<div style={{ position: "relative" }}>
<canvas width={width} height={height} ref={canvasEL} />
<PlayButton
isShow={!playing}
theme={theme}
size={dateLabelSize * 0.8}
play={play}
/>
</div>
);
};
export default DynamicBar;