我正在制作一个允许在同一画布上显示多个图的组件。
当显示单个图形时,一切都完美运行。
在真实代码上,我也可以在不需要时使用foo删除圆圈。
在我的代码中,我还可以使用clean-uf useEffect钩摆脱圈子。
return () => {
svg.selectAll('circle').remove();
}
不幸的是,当我尝试绘制更多图时,我失败了。发生此问题,因为每个后续的绘图使用前一个绘图中的圆。目前,我找不到任何可以让我一起查看所有地块的东西。
编写良好的代码应允许您在画布上一起绘制三个点图。然后您应该可以同时看到红色,绿色和蓝色的点图。
const useState = React.useState;
const useRef = React.useRef;
const useEffect = React.useEffect;
const select = d3.select;
const scaleLinear = d3.scaleLinear;
const axisBottom = d3.axisBottom;
const axisLeft = d3.axisLeft;
const DotsPlot = () => {
const [xAxisData] = useState({
min: 100,
max: 700
});
const [yAxisData] = useState({
min: 200,
max: 500
});
const [meta] = useState({
xWidth: 600,
yWidth: 300,
});
const [plots] = useState([
[{
x: '120',
y: '210',
r: '4px',
color: 'red'
}, {
x: '220',
y: '230',
r: '4px',
color: 'red'
}, {
x: '320',
y: '250',
r: '4px',
color: 'red'
}, {
x: '380',
y: '270',
r: '4px',
color: 'red'
}, {
x: '450',
y: '290',
r: '4px',
color: 'red'
}],
[{
x: '220',
y: '310',
r: '4px',
color: 'blue'
}, {
x: '320',
y: '330',
r: '4px',
color: 'blue'
}, {
x: '420',
y: '350',
r: '4px',
color: 'blue'
}, {
x: '520',
y: '370',
r: '4px',
color: 'blue'
}, {
x: '620',
y: '410',
r: '4px',
color: 'blue'
}],
[{
x: '305',
y: '370',
r: '4px',
color: 'green'
}, {
x: '370',
y: '420',
r: '4px',
color: 'green'
}, {
x: '440',
y: '410',
r: '4px',
color: 'green'
}, {
x: '490',
y: '400',
r: '4px',
color: 'green'
}, {
x: '600',
y: '490',
r: '4px',
color: 'green'
}],
]);
const svgRef = useRef();
useEffect(() => {
if (svgRef.current) {
const svg = select(svgRef.current);
// X-AXIS
const xScale = scaleLinear()
.domain([xAxisData.min, xAxisData.max])
.range([0, meta.xWidth]);
const xAxis = axisBottom(xScale);
svg
.select(".x-axis")
.style("transform", `translateY(${meta.yWidth}px)`)
.call(xAxis);
// Y-AXIS
const yScale = scaleLinear()
.domain([yAxisData.min, yAxisData.max])
.range([meta.yWidth, 0]);
const yAxis = axisLeft(yScale);
svg
.select(".y-axis")
.call(yAxis);
// DOT PLOT
plots.map(points => {
svg
.selectAll("circle")
.data(points)
.join("circle")
.attr("cx", value => xScale(value.x))
.attr("cy", value => yScale(value.y))
.attr("r", value => value.r)
.attr("fill", value => value.color)
.attr("stroke", value => value.color);
});
}
}, [xAxisData, yAxisData, meta, plots]);
return ( <
svg viewBox = {
`0 0 ${meta.xWidth} ${meta.yWidth}`
}
ref = {
svgRef
} >
<
g className = "x-axis" / >
<
g className = "y-axis" / >
<
/svg>
);
}
ReactDOM.render(< DotsPlot />, document.querySelector("body"));
svg {
width: 80%;
height: auto;
background: #eee;
overflow: visible;
margin: 5%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
答案 0 :(得分:1)
尝试以下方法。您一直选择相同的圈子并进行更新。我在plots
中为每个条目使用一个组,并为每个组添加圆圈。这样,其他圈子不会被删除。
另一种解决方法是使用plots
展平Array.prototype.flat()
,然后仅除去plots.map(
部分。
const useState = React.useState;
const useRef = React.useRef;
const useEffect = React.useEffect;
const select = d3.select;
const scaleLinear = d3.scaleLinear;
const axisBottom = d3.axisBottom;
const axisLeft = d3.axisLeft;
const DotsPlot = () => {
const [xAxisData] = useState({
min: 100,
max: 700
});
const [yAxisData] = useState({
min: 200,
max: 500
});
const [meta] = useState({
xWidth: 600,
yWidth: 300,
});
const [plots] = useState([
[{
x: '120',
y: '210',
r: '4px',
color: 'red'
}, {
x: '220',
y: '230',
r: '4px',
color: 'red'
}, {
x: '320',
y: '250',
r: '4px',
color: 'red'
}, {
x: '380',
y: '270',
r: '4px',
color: 'red'
}, {
x: '450',
y: '290',
r: '4px',
color: 'red'
}],
[{
x: '220',
y: '310',
r: '4px',
color: 'blue'
}, {
x: '320',
y: '330',
r: '4px',
color: 'blue'
}, {
x: '420',
y: '350',
r: '4px',
color: 'blue'
}, {
x: '520',
y: '370',
r: '4px',
color: 'blue'
}, {
x: '620',
y: '410',
r: '4px',
color: 'blue'
}],
[{
x: '305',
y: '370',
r: '4px',
color: 'green'
}, {
x: '370',
y: '420',
r: '4px',
color: 'green'
}, {
x: '440',
y: '410',
r: '4px',
color: 'green'
}, {
x: '490',
y: '400',
r: '4px',
color: 'green'
}, {
x: '600',
y: '490',
r: '4px',
color: 'green'
}],
]);
const svgRef = useRef();
useEffect(() => {
if (svgRef.current) {
const svg = select(svgRef.current);
// X-AXIS
const xScale = scaleLinear()
.domain([xAxisData.min, xAxisData.max])
.range([0, meta.xWidth]);
const xAxis = axisBottom(xScale);
svg
.select(".x-axis")
.style("transform", `translateY(${meta.yWidth}px)`)
.call(xAxis);
// Y-AXIS
const yScale = scaleLinear()
.domain([yAxisData.min, yAxisData.max])
.range([meta.yWidth, 0]);
const yAxis = axisLeft(yScale);
svg
.select(".y-axis")
.call(yAxis);
// DOT PLOT
svg
.selectAll("g.plots")
.data(plots)
.join("g")
.selectAll("circle")
.data(d => d)
.join("circle")
.attr("cx", value => xScale(value.x))
.attr("cy", value => yScale(value.y))
.attr("r", value => value.r)
.attr("fill", value => value.color)
.attr("stroke", value => value.color);
}
}, [xAxisData, yAxisData, meta, plots]);
return ( <
svg viewBox = {
`0 0 ${meta.xWidth} ${meta.yWidth}`
}
ref = {
svgRef
} >
<
g className = "x-axis" / >
<
g className = "y-axis" / >
<
/svg>
);
}
ReactDOM.render(< DotsPlot />, document.querySelector("body"));
svg {
width: 80%;
height: auto;
background: #eee;
overflow: visible;
margin: 5%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>