Je crée une intrigue dans une application Web réalisée avec des crochets de réaction et de réaction. Le tracé est réalisé avec la librairie d3.js. Le tracé s'affiche parfaitement, mais lorsque je trace un tracé de ligne, la ligne de l'axe des x disparaît.

Le premier graphique est constitué d'un ensemble de points. Ce graphique met en évidence les points sur lesquels le graphique linéaire est basé. Le deuxième graphique est le graphique linéaire.

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 line = d3.line;
const curveCardinal = d3.curveCardinal;

const DummyPlot = () => {

  const [xAxisData] = useState({
    min: 0,
    max: 16
  });

  const [yAxisData] = useState({
    min: 1000,
    max: 1500
  });

  const [colorPalette] = useState({
    dots: "#1E90FF",
    line: "#8A2BE2"
  });

  const [meta] = useState({
    xWidth: 600,
    yWidth: 300,
    lineStroke: "3px",
    pointRadius: "4px"
  });

  const [points] = useState([{
      y: 1425,
      x: 1
    },
    {
      y: 1435,
      x: 2
    },
    {
      y: 1445,
      x: 3
    },
    {
      y: 1455,
      x: 4
    },
    {
      y: 1455,
      x: 5
    },
    {
      y: 1455,
      x: 6
    },
    {
      y: 1425,
      x: 7
    },
    {
      y: 1125,
      x: 8
    },
    {
      y: 1090,
      x: 9
    },
    {
      y: 1090,
      x: 10
    },
    {
      y: 1250,
      x: 11
    },
    {
      y: 1350,
      x: 12
    },
    {
      y: 1035,
      x: 13
    },
    {
      y: 1150,
      x: 14
    },
    {
      y: 1100,
      x: 15
    }
  ]);

  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);

      // LINE PLOT
      const myLine = line()
        .x(value => xScale(value.x))
        .y(value => yScale(value.y) - meta.yWidth)
        .curve(curveCardinal);

      svg
        .select("path")
        .data([points])
        .join("path")
        .attr("d", value => myLine(value))
        .attr("stroke", colorPalette.line)
        .attr("stroke-width", meta.lineStroke);

      // DOT PLOT
      svg
        .selectAll("circle")
        .data(points)
        .join("circle")
        .attr("cx", value => xScale(value.x))
        .attr("cy", value => yScale(value.y))
        .attr("r", () => meta.pointRadius)
        .attr("fill", () => colorPalette.dots)
        .attr("stroke", () => colorPalette.dots);
    }

  }, [xAxisData, yAxisData, meta, points, colorPalette]);

  return ( <
    svg viewBox = {
      `0 0 ${meta.xWidth} ${meta.yWidth}`
    }
    ref = {
      svgRef
    } >
    <
    g className = "x-axis" / >
    <
    g className = "y-axis" / >
    <
    /svg>
  );
}

ReactDOM.render(< DummyPlot />, 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
Stoic Lion 5 nov. 2020 à 17:40

1 réponse

Meilleure réponse

En utilisant svg.select("path"), vous réaffectiez votre domaine d'axe path en tant que ligne pour le graphique. L'ajout d'un nœud path séparé et l'attribution d'un nom de classe l'ont corrigé :

Maintenant, il n'est plus nécessaire de soustraire yWidth de la valeur y, ce que vous avez fait à cause du transform sur l'axe du bas.

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 line = d3.line;
const curveCardinal = d3.curveCardinal;

const DummyPlot = () => {

  const [xAxisData] = useState({
    min: 0,
    max: 16
  });

  const [yAxisData] = useState({
    min: 1000,
    max: 1500
  });

  const [colorPalette] = useState({
    dots: "#1E90FF",
    line: "#8A2BE2"
  });

  const [meta] = useState({
    xWidth: 600,
    yWidth: 300,
    lineStroke: "3px",
    pointRadius: "4px"
  });

  const [points] = useState([{
      y: 1425,
      x: 1
    },
    {
      y: 1435,
      x: 2
    },
    {
      y: 1445,
      x: 3
    },
    {
      y: 1455,
      x: 4
    },
    {
      y: 1455,
      x: 5
    },
    {
      y: 1455,
      x: 6
    },
    {
      y: 1425,
      x: 7
    },
    {
      y: 1125,
      x: 8
    },
    {
      y: 1090,
      x: 9
    },
    {
      y: 1090,
      x: 10
    },
    {
      y: 1250,
      x: 11
    },
    {
      y: 1350,
      x: 12
    },
    {
      y: 1035,
      x: 13
    },
    {
      y: 1150,
      x: 14
    },
    {
      y: 1100,
      x: 15
    }
  ]);

  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);

      // LINE PLOT
      const myLine = line()
        .x(value => xScale(value.x))
        .y(value => yScale(value.y))
        .curve(curveCardinal);

      svg
        .selectAll(".line")
        .data([points])
        .join(".line")
        .attr("d", value => myLine(value))
        .attr("fill", "none")
        .attr("stroke", colorPalette.line)
        .attr("stroke-width", meta.lineStroke);

      // DOT PLOT
      svg
        .selectAll("circle")
        .data(points)
        .join("circle")
        .attr("cx", value => xScale(value.x))
        .attr("cy", value => yScale(value.y))
        .attr("r", () => meta.pointRadius)
        .attr("fill", () => colorPalette.dots)
        .attr("stroke", () => colorPalette.dots);
    }

  }, [xAxisData, yAxisData, meta, points, colorPalette]);

  return ( <
    svg viewBox={`0 0 ${meta.xWidth} ${meta.yWidth}`}
        ref = {svgRef} >
      <g className = "x-axis" / >
      <g className = "y-axis" / >
      <path className = "line" / >
    </svg>
  );
}

ReactDOM.render(< DummyPlot />, 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
Ruben Helsloot 5 nov. 2020 à 14:53