仅绘制最后一个图的圆

时间:2020-11-09 15:08:27

标签: reactjs d3.js react-hooks

我正在制作一个允许在同一画布上显示多个图的组件。

当显示单个图形时,一切都完美运行。

在真实代码上,我也可以在不需要时使用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>

1 个答案:

答案 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>