Я использую 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));
Точно так же я использую и кольцевую диаграмму, надеюсь, то же самое можно реализовать и для этого.