【发布时间】:2022-08-24 20:10:09
【问题描述】:
我正在使用 d3.js 库在 React 中绘制条形图。我实现了this 示例,但我无法添加播放/暂停功能来停止和恢复动画而不重新渲染整个图表。 这是我的代码:
export default function RacerBar(){
const ref = useRef()
const [animationEnabled, setAnimationEnabled] = useState(true);
const [isFetched, setIsFetched] = useState(false);
const [data, setData] = useState([{}]);
const [selectedIndicator, setSelectedIndicator] = useState(\"indicator_1\");
useEffect(()=>{
const fetchData = async () => {
await fetch(\"/api/chart\").then(
res => res.json())
.then((data) => {
setData(data)
setIsFetched(true)
})
}
fetchData()
},[])
useEffect(()=>{
if (isFetched) {
const names = new Set(data.map(d => d.client))
const datavalues = Array.from(d3.rollup(data, ([d]) => d[selectedIndicator], d => +d.year, d => d.client))
const svg = d3.select(ref.current)
svg.selectAll(\"*\").remove()
//other svg settings
const ticker = 2500;
async function plotChart(data) {
const dateList = new Set(data.map(d=>d.year));
const fontSize = 16;
const rectProperties = {height: 20, padding: 10}
const container = svg.append(\"g\")
.classed(\"container\", true)
.style(\"transform\", \"translateY(25px)\")
const widthScale = d3.scaleLinear()
const axisTop = svg
.append(\'g\')
.classed(\'axis\', true)
.style(\"transform\", \"translate(10px, 20px)\")
.call(d3.axisTop(widthScale))
//This part is responsible for the animation.
const update = (date) => {
const presentData = [];
for (var i=0; i < data.length; i++){
if (data[i].year === date){
var key=data[i].client;
var value = data[i][selectedIndicator]
presentData.push({\"key\": key, \"value\": value})
}
}
//svg maniplation, drawing bars and labels similar to the example
}
// iterating through the data
for (const date of dateList) {
update(date)
await new Promise(done => setTimeout(() => done(), ticker));
}
}
plotChart(data)
}
},[isFetched, selectedIndicator])
const handleIndicatorChange = (event) => {
setSelectedIndicator(event.target.value);
}
return (
<div className=\"RacerBar\">
<Dropdown label=\"Chooes option\"
options={dropDownItems}
value={selectedIndicator}
onChange={handleIndicatorChange}/>
<div className=\"container\">
<svg
ref={ref}
style={{width: parseInt(width, 10) || 1000,
height: parseInt(height, 10) || 1000}}
id={`racerbar_chart`}
/>
</div>
<Button
onClick={() => { setAnimationEnabled(!animationEnabled) }}>
{animationEnabled ? \"Pause\" : \"Play\"}
</Button>
</div>
)
}
这是一个小解释:
我必须等到数据提取完毕。为此,我使用了 useEffect。这段代码运行良好。
提取完成后,触发了另一个调用 plotChart 函数的 useEffect。 该函数的第一部分对 svg 对象进行了进一步的操作,然后是 updater 函数。这部分负责绘制条形图、创建标签等。
此更新器函数由循环调用数据端更新图表的 for 循环。 我尝试了多种可能性,但我找不到合适的解决方案来隔离更新程序功能并通过 useEffect 调用它。
不用说,但我是 React 的初学者,我并不完全了解它的 DOM 管理。
先感谢您!
编辑
感谢 DBK 的帮助。我可以找到我的问题的可接受的解决方案。我在我的Github 页面上上传了最终代码,请随时查看或评论。 谢谢!
-
欢迎来到 StackOverflow!
selectedIndicator在哪里声明? -
感谢你的回复!我很抱歉,但是当我试图意外地减少我的代码时,我删除了它。我在代码开头使用 setState 函数声明了它。我还忘了提到代码运行良好,它正在为图表设置动画,但是当我更改指标时,它当然会重新渲染整个图表。
-
只需从 useEffect 依赖数组中删除
selectedIndicator,它不应该在每次更改时重新渲染 -
谢谢!当然,你是对的,但我的目标是停止或重新开始迭代而不重新渲染 SVG 对象。为了激活这个,我想,我想修改第二个 useEffect 函数。
标签: javascript reactjs d3.js