elstat/priv/frontend/src/Graph.js

95 lines
2.2 KiB
JavaScript

import React, { Component } from 'react';
import './Graph.css';
import { curveNatural } from '@vx/curve';
import { GradientOrangeRed } from '@vx/gradient';
import { AxisLeft, AxisBottom } from '@vx/axis';
import { Group } from '@vx/group';
import { AreaClosed } from '@vx/shape';
import { scaleTime, scaleLinear } from '@vx/scale';
import { extent, max } from 'd3-array';
const x = ([timestamp,]) => new Date(timestamp);
const y = ([, latency]) => latency;
const margin = {
top: 0,
bottom: 50,
left: 50,
right: 0,
};
const tick = {
textAnchor: 'middle',
fontSize: 8,
fontFamily: 'system-ui, sans-serif',
};
const leftTick = {
...tick,
dx: '-0.25em',
dy: '0.25em',
textAnchor: 'end',
};
const label = {
...tick,
fontSize: 10,
};
export default class Graph extends Component {
constructor(props) {
super(props);
const { width, height, data } = props;
this.xMax = width - margin.left - margin.right;
this.yMax = height - margin.top - margin.bottom;
this.xScale = scaleTime({
range: [0, this.xMax],
domain: extent(data, x),
});
this.yScale = scaleLinear({
range: [this.yMax, 0],
domain: [0, max(data, y)],
nice: true,
});
}
render() {
return (
<svg className="graph" width={this.props.width} height={this.props.height}>
<GradientOrangeRed id="gradient"/>
<Group top={margin.top} left={margin.left}>
<AreaClosed
data={this.props.data}
xScale={this.xScale} yScale={this.yScale}
x={x} y={y}
stroke=""
fill="url(#gradient)"
curve={curveNatural}
/>
<AxisLeft
scale={this.yScale}
top={0} left={0}
labelProps={label}
tickFormat={(value, index) => `${value}ms`}
tickLabelProps={(value, index) => leftTick}
label=''
/>
<AxisBottom
scale={this.xScale}
top={this.yMax}
tickFormat={(value, index) => `${value.toLocaleTimeString()}`}
labelProps={label}
tickLabelProps={(value, index) => tick}
label=''
/>
</Group>
</svg>
);
}
}