[英]How can I render a d3 chart, export it as an image, then load the next data set, plot the next chart and export again
[英]How can I stop D3 chart from Duplicating on First Render in React App?
出於某種原因,我的 D3 圖表僅在第一次渲染時重復。 它將在第一個圖表的下方垂直堆疊第二個圖表。
但是當我點擊刷新時,它再也不會重復了。 有沒有辦法讓.forEach循環一次或放置某種中斷或條件來防止第一次重復渲染?
還是我需要修改useEffect() ?
export default function BarChart() {
useEffect(() => {
db.collection('revenue').get().then(res => {
let data = [];
res.docs.forEach(doc => {
data.push(doc.data());
});
console.log(data);
const svg = d3.select('.canvas')
.append('svg')
.attr('width', '640')
.attr('height', '400');
const margin = { top: 20, right: 20, bottom: 100, left: 100 };
const graphWidth = 600 - margin.left - margin.right;
const graphHeight = 400 - margin.top - margin.bottom;
const graph = svg.append('g')
.attr('width', graphWidth)
.attr('height', graphHeight)
.attr('transform', `translate(${margin.left}, ${margin.top})`);
// create axes groups
const xAxisGroup = graph.append('g')
.attr('transform', `translate(0, ${graphHeight})`)
const yAxisGroup = graph.append('g');
const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.amount)])
.range([graphHeight, 0]);
const x = d3.scaleBand()
.domain(data.map(item => item.date))
.range([0, graphWidth])
.paddingInner(0.2)
.paddingOuter(0.2);
// join the data to circs
const rects = graph.selectAll('rect')
.data(data);
// add attrs to circs already in the DOM
rects.attr('width', '50')
.attr("height", d => graphHeight - y(d.amount))
.attr('fill', 'Red')
.attr('x', d => x(d.date))
.attr('y', d => y(d.amount));
// append the enter selection to the DOM
rects.enter()
.append('rect')
.attr('width', '50')
.attr("height", 0)
.attr('fill', 'Red')
.attr('id', d => (d.id))
.attr('x', (d) => x(d.date))
.attr('y', graphHeight)
.transition().duration(500)
.attr('y', d => y(d.amount))
.attr("height", d => graphHeight - y(d.amount))
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y)
.ticks(4)
.tickFormat(d => d + ' dollars');
xAxisGroup.call(xAxis);
yAxisGroup.call(yAxis);
// Bottom Chart Text
xAxisGroup.selectAll('text')
.attr('fill', 'Teal')
//.attr('font-weight', 'bold')
.attr('transform', 'rotate(-40)')
.attr('text-anchor', 'end')
});
}, []); // Array for data
return (
<div>
<h1">Title</h1>
</div>
);
}
您可以嘗試將 SVG 添加到組件中,以便
return (
<div>
<h1">Title</h1>
<svg className="svg-canvas" width="640px" height="400px" />
</div>
);
和改變
const svg = d3.select('.canvas')
.append('svg')
.attr('width', '640')
.attr('height', '400');
//to
const svg = d3.select('.svg-canvas')
svg.selectAll("*").remove()
這將確保在重新渲染之前 SVG 始終為空。 盡管如果您的數據更新,它將重新渲染所有內容。
我簡單地這樣做:
// UseEffect
React.useEffect(()=> {
// Hide first svg
let svg = document.getElementsByTagName('svg');
// If data present create chart
if(data){
// Create chart
D3Chart(chartDiv.current, data);
// Hide first empty svg
svg[0].style.display='none';
}
},[data]);
你可以試試這個:
export function component_name {data, ...props} {
const yourRef = useRef()
useEffect(() => {
/*All your code here*/
yourRef.current.append(X) /*"X" is your first SVG element that contains the others*/
return() => X.remove()
}, [data])}
無論您在哪里調用組件:
<component_name data={data} />
每當您的數據發生更改時,您的組件都會被刪除。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.