211 lines
7.6 KiB
JavaScript
211 lines
7.6 KiB
JavaScript
import React, { Component } from 'react';
|
|
import * as d3 from 'd3';
|
|
import moment from 'moment';
|
|
import { sgg } from 'ml-savitzky-golay-generalized';
|
|
import { FaBeer, FaInfoCircle } from "react-icons/fa";
|
|
|
|
import './TestAnalyticsGraph.css';
|
|
|
|
class TestAnalyticsGraph extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = {
|
|
data: this.props.data,
|
|
show: this.props.show,
|
|
showCardInfo: false
|
|
};
|
|
}
|
|
componentDidMount() {
|
|
// this.drawChart(this.state.data);
|
|
this.drawBar(this.state.data);
|
|
}
|
|
|
|
drawBar(data) {
|
|
if (!data) return;
|
|
|
|
data.reverse();
|
|
|
|
var margin = { top: 30, right: 20, bottom: 50, left: 15 },
|
|
width = 1500 - margin.left - margin.right,
|
|
height = 180 - margin.top - margin.bottom;
|
|
|
|
var svg = d3.select("#tests-count-graph").append('svg')
|
|
.attr("width", width + margin.left + margin.right)
|
|
.attr("height", height + margin.top + margin.bottom)
|
|
.append("g").attr("transform",
|
|
"translate(" + margin.left + "," + margin.top + ")");
|
|
|
|
|
|
var xScale = d3.scaleBand().range([0, width]).padding(0.4),
|
|
yScale = d3.scaleLinear().range([height, 0]);
|
|
|
|
var g = svg.append("g")
|
|
.attr("transform", "translate(" + 10 + "," + 10 + ")");
|
|
|
|
|
|
xScale.domain(data.map(function (d) { return moment(d.date).format("MM-DD"); }));
|
|
yScale.domain([0, d3.max(data, function (d) { return d.count; })]);
|
|
|
|
|
|
g.append("g")
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(xScale));
|
|
|
|
g.append("g")
|
|
.call(d3.axisLeft(yScale).tickFormat(function (d) {
|
|
return " " + d;
|
|
}).ticks(10))
|
|
.append("text")
|
|
.attr("y", 6)
|
|
.attr("dy", "0.71em")
|
|
.attr("text-anchor", "end")
|
|
.text("value");
|
|
|
|
g.selectAll(".bar")
|
|
.data(data)
|
|
.enter().append("rect")
|
|
.attr("class", "bar")
|
|
.on("mouseover", (event, d) => {
|
|
// console.log("event", event);
|
|
d3.select(event.srcElement).attr('class', 'highlight');
|
|
d3.select(event.srcElement).transition()
|
|
.duration(400)
|
|
.attr('width', xScale.bandwidth() + 5)
|
|
.attr("y", function (d) { return yScale(d.count) - 10; })
|
|
.attr("height", function (d) { return height - yScale(d.count) + 10; });
|
|
|
|
g.append("text")
|
|
.attr('class', 'val') // add class to text label
|
|
.attr('x', function () {
|
|
return xScale(moment(d.date).format("MM-DD"));
|
|
})
|
|
.attr('y', function () {
|
|
return yScale(d.count) - 15;
|
|
})
|
|
.text(function () {
|
|
return [' ' + d.count]; // Value of the text
|
|
});
|
|
})
|
|
.on("mouseout", (event, d) => {
|
|
d3.select(event.srcElement).attr('class', 'bar');
|
|
d3.select(event.srcElement)
|
|
.transition() // adds animation
|
|
.duration(400)
|
|
.attr('width', xScale.bandwidth())
|
|
.attr("y", function (d) { return yScale(d.count); })
|
|
.attr("height", function (d) { return height - yScale(d.count); });
|
|
|
|
d3.selectAll('.val')
|
|
.remove()
|
|
})
|
|
.attr("x", function (d) { return xScale(moment(d.date).format("MM-DD")); })
|
|
.attr("y", function (d) { return yScale(d.count); })
|
|
.attr("width", xScale.bandwidth())
|
|
.transition()
|
|
.ease(d3.easeLinear)
|
|
.duration(400)
|
|
.delay(function (d, i) {
|
|
return i * 50;
|
|
})
|
|
.attr("height", function (d) { return height - yScale(d.count); });
|
|
}
|
|
|
|
drawChart(data) {
|
|
if (!data) return;
|
|
var margin = { top: 20, right: 20, bottom: 30, left: 50 },
|
|
width = 960 - margin.left - margin.right,
|
|
height = 500 - margin.top - margin.bottom;
|
|
|
|
const INNER_WIDTH = width;// - margin.left - margin.right;
|
|
const INNER_HEIGHT = height - margin.top - margin.bottom;
|
|
|
|
// set the ranges
|
|
var x = d3.scaleTime().range([0, width]);
|
|
var y = d3.scaleLinear().range([height, 0]);
|
|
|
|
const xAxis = d3.axisBottom(x).ticks(10);
|
|
const yAxis = d3.axisLeft(y).ticks(10);
|
|
const xAxisGrid = d3.axisBottom(x).tickSize(-INNER_HEIGHT).tickFormat('').ticks(10);
|
|
const yAxisGrid = d3.axisLeft(y).tickSize(-INNER_WIDTH).tickFormat('').ticks(10);
|
|
|
|
// define the line
|
|
var valueline = d3.line()
|
|
.curve(d3.curveCatmullRom.alpha(0.5)) // curve
|
|
.x(function (d) { return x(moment(d.date)); })
|
|
.y(function (d) { return y(d.count); });
|
|
|
|
var svg = d3.select("#tests-count-graph").append("svg")
|
|
.attr("width", width + margin.left + margin.right)
|
|
.attr("height", height + margin.top + margin.bottom)
|
|
.append("g").attr("transform",
|
|
"translate(" + margin.left + "," + margin.top + ")");
|
|
// var g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
|
|
|
// const options = {
|
|
// windowSize: 5,
|
|
// derivative: 0,
|
|
// polynomial: 3,
|
|
// };
|
|
// const sggResult = sgg(data.map(x => x.count), (Math.PI * 2) / data.length, options);
|
|
|
|
// data.forEach(function (d, index) {
|
|
// d.date = d.date;
|
|
// d.count = sggResult[index];
|
|
// });
|
|
// data.forEach(function (d) {
|
|
// d.date = d.date;
|
|
// d.count = +d.count;
|
|
// });
|
|
|
|
x.domain(d3.extent(data, function (d) { return moment(d.date); }));
|
|
y.domain([0, d3.max(data, function (d) { return d.count; })]);
|
|
|
|
svg.append("path")
|
|
.data([data])
|
|
.attr("class", "line")
|
|
.attr("d", valueline(data));
|
|
|
|
svg.append("g")
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x))
|
|
.append("text")
|
|
// .attr("transform", "rotate(-90)")
|
|
.attr("x", 400)
|
|
.attr("y", 30)
|
|
.attr("dx", "0.71em")
|
|
.attr("fill", "#000")
|
|
.text("Test time");
|
|
|
|
svg.append("g")
|
|
.attr('class', 'y axis-grid')
|
|
.call(yAxisGrid)
|
|
// .call(d3.axisLeft(y))
|
|
.append("text")
|
|
.attr("transform", "rotate(-90)")
|
|
.attr("x", -160)
|
|
.attr("y", -36)
|
|
.attr("dy", "0.71em")
|
|
.attr("fill", "#000")
|
|
.text("Tests Count");
|
|
|
|
svg.append('g')
|
|
.attr('class', 'y axis')
|
|
.call(yAxis);
|
|
|
|
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<div>
|
|
<div className='tests-count-card'>
|
|
<div className='testcount-graph-title'>Daily test counts<span className='testcount-info-icon' onClick={() => !this.setState({ showCardInfo: !this.state.showCardInfo })}><FaInfoCircle /></span></div>
|
|
{this.state.showCardInfo && <div className='testcount-info-card'>Daily test counts are shown. While off days are not taken into consideration</div>}
|
|
<div id="tests-count-graph" style={{ margin: '1em' }}>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
};
|
|
}
|
|
export default TestAnalyticsGraph; |