Как использовать React Router с графиками d3. js для перенаправления на другой экран - PullRequest
0 голосов
/ 02 апреля 2020

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 { connect } from "react-redux";
import "../../css/styles.css";
import { NavLink } from "react-router-dom";

class JarvisDonutChart extends Component {
  constructor(props) {
    super(props);
    this.state = {
      uid: props.uid,
      width: props.width,
      height: props.height,
      title: props.title,
      colorscheme: props.colorscheme,
      Dates: props.CalendarDates,
      fromDate: props.CalendarDates.fromDate,
      toDate: props.CalendarDates.toDate,
      graphTitle: props.graphTitle,
      chartData: []
    };
  }

  componentDidMount() {
    this.getChartData();
  }

  getChartData = () => {
    ApiHelper.GetDonutChartData(
      this.state.uid,
      this.state.fromDate,
      this.state.toDate
    )
      .then(response => {
        console.log(
          "<--- Request is successfull and below is the response -->"
        );
        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);
        }
      });
  };

  drawChart() {
    const data = this.state.chartData;
    // const data = ApiHelper.GetDonutChartData(
    //   "abeab3cb-778e-4a19-a957-43bc74248b04179"
    // );
    const colorscheme = this.state.colorscheme;
    console.log("Inside Donut Chart Component");
    console.log(data);

    var width = this.state.width;
    var height = this.state.height;
    var margin = Math.min(this.state.width, this.state.height) * 0.01;

    // The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
    var radius = Math.min(this.state.width, this.state.height) / 2 - margin;

    // append the svg object to the div called 'my_dataviz'
    const svg = d3
      // .select("#abeab3cb-778e-4a19-a957-43bc74248b04")
      .select("[uid=" + this.state.uid + "]")
      .attr("width", this.state.width)
      .attr("height", this.state.height)
      .append("g")
      .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

    // Compute the position of each group on the pie:
    var pie = d3.pie().value(function(d) {
      //console.log(d.value.value);
      //d.value.(responsefield)
      return d.value.value;
    });
    var data_ready = pie(d3.entries(data));

    console.log("<-- Checking data-ready  --> ");
    console.log(data_ready);

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

    // console.log(data_ready);
    // console.log(colorscheme);

    // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
    svg
      .selectAll("whatever")
      .data(data_ready)
      .enter()
      .append("a")
      .attr(
        "href",
        (d, i) =>
          `/drilldown-page/${this.state.title}/${this.state.graphTitle}/${data_ready[i].data.value.name}`
      )
      .append("path")
      .attr(
        "d",
        d3
          .arc()
          .innerRadius(radius * 0.45) // This is the size of the donut hole
          .outerRadius(radius)
          .cornerRadius(radius * 0.03) // sets how rounded the corners are on each slice
          .padAngle(radius * 0.0001) // effectively dictates the gap between slices
      )
      .attr("fill", (d, i) => this.state.colorscheme[i])

      .attr("stroke", "black")
      .style("stroke-width", "0.7px")
      .style("opacity", 0.9)
      .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("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("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");
      });
  }

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

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

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

Первый экран

После нажатия на график, он приводит к этому экрану ( Второй экран)

В d3. js Я использую код ниже

.attr ("xlink: href", (d, i) => /drilldown-page/${this.state.title}/${this.state.graphTitle}/${data_ready[i].data.value.name})

Проблема, с которой я сейчас сталкиваюсь, заключается в том, что если страница обновляется, и все хранилище редуксов снова загружается, то есть все данные в хранилище, такие как календарные даты, исчезли.

ТАК как Могу ли я использовать React-роутер с этой идеей ???

Ответы [ 2 ]

0 голосов
/ 04 апреля 2020

Я понял это сам, и решение, которое я реализовал, приведено ниже.

D3. js предоставляет метод обработчика событий, то есть selection.on (). поэтому прикрепите обработчик событий для щелчка по элементу графа и вызовите функцию внутри функции обратного вызова.

И в новой функции используйте history.pu sh для перенаправления на другой URL.

Код прилагается

.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}`
      );
    };

Надеюсь, мой ответ принесет пользу кому-то, кто использует React и d3. js и застрял с перенаправлением.

0 голосов
/ 02 апреля 2020

Я не вижу ваш код, но вы можете добавить onClick реквизит к некоторой оболочке / контейнеру графа с помощью метода, подобного этому

// At the top
import { useHistory } from 'react-router-dom'

// In wrapper component
const history = useHistory();
const redirect = () => {
   history.push(`/drilldown-page/${this.state.title}/${this.state.graphTitle}/${data_ready[i].data.value.name}`);
}

и передать его в prop OnClick = {} перенаправление

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...