Как обновить график d3. js при обновлении хранилища React-Redux для отражения изменений - PullRequest
0 голосов
/ 04 апреля 2020

Я использую d3. js в React для построения интерактивных графиков. Я хотел, чтобы моя гистограмма показывала данные на основе даты, выбранной в календаре. Я храню дату в хранилище Redux и подключил свой компонент графика к хранилищу, чтобы при каждом изменении даты он вызывал Backend API с этой датой, чтобы получить желаемый набор данных для этого интервала.

Я использую компонент класса ComponentdidUpdate метод жизненного цикла, чтобы сделать обновление. Но я думаю, нам нужно внести некоторые изменения в код d3, чтобы обработать обновление.

import React, { Component } from "react";
import * as d3 from "d3";
import ApiHelper from "../../api/ApiHelper";
import { scaleLinear } from "d3-scale";
import { max } from "d3-array";
import "../../css/styles.css";
import { NavLink, withRouter } from "react-router-dom";
import { connect } from "react-redux";
class JarvisBarChart extends Component {
  constructor(props) {
    super(props);
    this.state = {
      uid: props.uid,
      width: props.width,
      height: props.height,
      title: props.title,
      colorscheme: props.colorscheme,
      graphTitle: props.GraphTitle,
      chartData: [],
      Dates: props.CalendarDates
    };
  }

  componentDidMount() {
    this.getChartData();
  }
  getChartData = () => {
    ApiHelper.GetBarChartData(
      this.state.uid,
      this.props.fromDate,
      this.props.toDate
    )
      .then(response => {
        console.log(
          "<--- Request is successfull and below is the response  for bar graph-->"
        );
        console.log(response.data.responses);
        const res = response.data.responses;
        this.setState({ chartData: res }, this.drawChart);
        // setloading(false);
      })
      .catch(error => {
        this.setState({ chartData: [] });
        switch (error.response.status) {
          case 403:
            console.log("Error code --> " + 403);
            this.props.history.push("/unAuthorizedPage");
            break;
          default:
            console.log("Error String --->" + error);
        }
      });
  };
  componentDidUpdate(prevProps, prevState) {
    if (
      prevProps.fromDate !== this.props.fromDate ||
      prevProps.toDate !== this.props.toDate
    ) {
      console.log("<--- If Statement Entered -->");
      d3.select("[uid=" + this.state.uid + "]").remove();
      this.getChartData();
      console.log(prevProps.fromDate !== this.props.fromDate);
    }
  }
  drawChart() {

    const data = this.state.chartData;
    console.log("Bar chart Data");
    console.log(data);

    const colorscheme = this.state.colorscheme;
    const margin = this.state.width * 0.04;
    const bartobaroffset = margin * 0.25;
    const dataMax = max(data, function(d) {
      return d.value;
    });
    const yScale = scaleLinear()
      .domain([0, dataMax])
      .range([0, parseInt(this.state.height, 10) - margin * 4]);
    const xScale = scaleLinear()
      .domain([0, data.length])
      .range([margin * 5, parseInt(this.state.width, 10) - margin * 5]); //Add 50px as buffer on both the ends
    const barwidth = xScale(1) - xScale(0) - bartobaroffset;

    const svg = d3
      .select("[uid=" + this.state.uid + "]")
      .attr("width", this.state.width)
      .attr("height", this.state.height);

    // Define the div for the tooltip
    var div = d3
      .select("#" + this.props.uid + "_tooltip")
      .attr("rx", 3)
      .attr("ry", 3);

    svg
      // .append("g")
      .append("rect")
      .attr("rx", 6)
      .attr("ry", 6)
      .attr("x", 0)
      .attr("y", 0)
      .attr("width", this.state.width)
      .attr("height", this.state.height)
      .style("opacity", 0)
      .attr("fill", "lightgrey");
    //Axis
    svg
      .append("line")
      .attr("x1", margin * 2)
      .attr("y1", this.state.height - margin)
      .attr("x2", this.state.width - margin * 2)
      .attr("y2", this.state.height - margin)
      .style("stroke", "black");

    // Creation of Bars
    svg
      .selectAll("rect1")
      .data(data)
      .enter()
      .append("rect")
      .attr("rx", 3)
      .attr("ry", 3)
      .attr("x", (d, i) => xScale(i))
      .attr(
        "y",
        (d, i) => this.state.height - yScale(d.value) - bartobaroffset - margin
      )
      .attr("width", barwidth - bartobaroffset)
      .attr("height", (d, i) => yScale(d.value))
      .attr("fill", (d, i) => this.state.colorscheme[i])
      .attr("stroke", "black")
      .attr("stroke-width", 0.8)
      .style("opacity", 1)
      .on("mouseover", function(d) {
        d3.select(this)
          .attr("stroke", "white")
          .attr("stroke-width", 1.5);
        d3.select(this).style("cursor", "pointer");
        div.style("display", "inline");
        // console.log("mouseover event triggered");
      })
      .on("mousemove", function(d) {
        div
          .text(d.value)
          .style("left", d3.mouse(d3.select("body").node())[0] + 15 + "px")
          .style("top", d3.mouse(d3.select("body").node())[1] + 20 + "px");
        // console.log("mouseover event triggered");
      })
      .on("mouseout", function(d, i) {
        d3.select(this)
          .attr("fill", colorscheme[i])
          .attr("stroke", "black")
          .attr("stroke-width", 0.5);
        d3.select(this).style("cursor", "default");
        div.style("display", "none");
        // console.log("mouseout event triggered");
      })
      .on("click", function(d) {
        console.log("<--- Inside Event generator --->");
        console.log(d);
        clickHandler(d);
      });
    const clickHandler = d => {
      console.log("<-- Inside Event Handler function --->");
      console.log(d.name);
      this.props.history.push(
        `/drilldown-page/${this.state.title}/${this.state.graphTitle}/${d.name}`
      );
    };
  

  render() {
    return (
      <>
        <svg
          uid={this.props.uid}
          width={this.state.width}
          height={this.state.height}
        />
        <div id={this.props.uid + "_tooltip"} className="jarvis_tooltip" />
      </>
    );
  }
}

function mapStateToProps(state) {
  return {
    CalendarDates: state.calendarDates,
    fromDate: state.calendarDates.fromDate,
    toDate: state.calendarDates.toDate
  };
}
export default withRouter(connect(mapStateToProps)(JarvisBarChart));

Точно так же я использую и кольцевую диаграмму, надеюсь, то же самое можно реализовать и для этого.

...