322 lines
11 KiB
JavaScript
322 lines
11 KiB
JavaScript
import React, { Component } from 'react';
|
|
import { withStyles } from '@material-ui/styles';
|
|
import Services from './services/Services';
|
|
import { blueGrey } from '@material-ui/core/colors';
|
|
import { Box, Grid, IconButton, Paper, Typography } from '@material-ui/core';
|
|
import DonutChart from './charts/DonutChart';
|
|
import HeatmapChart from './charts/HeatmapChart';
|
|
import BarChart from './charts/BarChart';
|
|
import LineChart from './charts/LineChart';
|
|
import DevicesContext from '../../contexts/DevicesContext';
|
|
import C from '../../common/Constants';
|
|
|
|
const styles = theme => ({
|
|
root: {
|
|
flexGrow: 1,
|
|
padding: '64px',
|
|
backgroundColor: theme.palette.primary.dark,
|
|
},
|
|
typo: {
|
|
fontSize: theme.typography.pxToRem(20),
|
|
fontWeight: theme.typography.fontWeightRegular,
|
|
},
|
|
paper: {
|
|
backgroundColor: blueGrey[50],
|
|
padding: '16px',
|
|
}
|
|
});
|
|
|
|
class Dashboard extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
deviceSeries: [],
|
|
sensorSeries: [],
|
|
heatmapSecondsSeries: [],
|
|
heatmapMinutesSeries: [],
|
|
barSeries: [],
|
|
barCategories: [],
|
|
lineSeries: [],
|
|
};
|
|
|
|
this.updateSeries = this.updateSeries.bind(this);
|
|
this.updateDynamic = this.updateDynamic.bind(this);
|
|
this.performTask = this.performTask.bind(this);
|
|
}
|
|
|
|
static contextType = DevicesContext;
|
|
|
|
componentDidMount() {
|
|
this.context.addHandler(C.update_all_method_name, this.updateSeries);
|
|
this.context.addHandler(C.update_method_name, this.updateSeries);
|
|
this.updateSeries();
|
|
this.updateDynamic();
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.context.removeHandler(C.update_all_method_name, this.updateSeries);
|
|
this.context.removeHandler(C.update_method_name, this.updateSeries);
|
|
}
|
|
|
|
getItemsWithStatus(iterate, status) {
|
|
const items = [];
|
|
|
|
for (var d of iterate) {
|
|
if (d.status == status) {
|
|
items.push(d);
|
|
}
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
getDevicesWithStatus(status) {
|
|
return this.getItemsWithStatus(this.context.devices, status);
|
|
}
|
|
|
|
getSensorsWithStatus(status) {
|
|
const sensors = [];
|
|
|
|
for (var d of this.context.devices) {
|
|
sensors.push(...d.sensors)
|
|
}
|
|
|
|
return this.getItemsWithStatus(sensors, status);
|
|
}
|
|
|
|
getDeviceSeries() {
|
|
var online = this.getDevicesWithStatus("Online").length;
|
|
var offline = this.getDevicesWithStatus("Offline").length;
|
|
var error = this.getDevicesWithStatus("Error").length;
|
|
|
|
return [online, offline, error]
|
|
}
|
|
|
|
getSensorSeries() {
|
|
var online = this.getSensorsWithStatus("Online").length;
|
|
var offline = this.getSensorsWithStatus("Offline").length;
|
|
var unknown = this.getSensorsWithStatus("Unknown").length;
|
|
|
|
return [online, offline, unknown]
|
|
}
|
|
|
|
updateSeries() {
|
|
this.setState({
|
|
deviceSeries: this.getDeviceSeries(),
|
|
sensorSeries: this.getSensorSeries()
|
|
});
|
|
}
|
|
|
|
updateDynamic = () => {
|
|
const secondAgo = new Date();
|
|
secondAgo.setMilliseconds(0);
|
|
const minuteAgo = new Date( Date.now() - 1000 * 60 );
|
|
const hourAgo = new Date( Date.now() - 1000 * 60 * 60 );
|
|
|
|
const minuteDevicePoints = {};
|
|
const hourDevicePoints = {};
|
|
const barDevicePoints = {};
|
|
const linePoints = {};
|
|
|
|
for (var d of this.context.devices) {
|
|
minuteDevicePoints[d.id] = Array(60).fill(0);
|
|
hourDevicePoints[d.id] = Array(60).fill(0);
|
|
barDevicePoints[d.id] = Array(3).fill(0);
|
|
}
|
|
|
|
const processMethod = (items, index) => {
|
|
const p = items[index];
|
|
if (p.date > minuteAgo) {
|
|
var seconds = Math.floor((p.date.getTime() - minuteAgo.getTime()) / 1000);
|
|
var oldProb = minuteDevicePoints[p.deviceId][seconds];
|
|
if (oldProb < p.prob) {
|
|
minuteDevicePoints[p.deviceId][seconds] = p.prob;
|
|
}
|
|
}
|
|
|
|
if (p.date > hourAgo) {
|
|
var minutes = Math.floor((p.date.getTime() - hourAgo.getTime()) / (1000 * 60));
|
|
var oldProb = hourDevicePoints[p.deviceId][minutes];
|
|
if (oldProb < p.prob) {
|
|
hourDevicePoints[p.deviceId][minutes] = p.prob;
|
|
}
|
|
}
|
|
|
|
if (p.prob > 0.5 && p.prob <= 0.7) {
|
|
barDevicePoints[p.deviceId][0] += 1;
|
|
}
|
|
if (p.prob > 0.7 && p.prob <= 0.9) {
|
|
barDevicePoints[p.deviceId][1] += 1;
|
|
}
|
|
if (p.prob > 0.9) {
|
|
barDevicePoints[p.deviceId][2] += 1;
|
|
}
|
|
|
|
if (p.date < secondAgo) {
|
|
var shortDate = p.date.toUTCString();
|
|
var point = linePoints[shortDate];
|
|
if (point === undefined) {
|
|
linePoints[shortDate] = 1;
|
|
} else {
|
|
linePoints[shortDate] += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
const finishMethod = () => {
|
|
const minuteHeatmapSeries = [];
|
|
|
|
var i = 0;
|
|
for (var p in minuteDevicePoints) {
|
|
minuteHeatmapSeries.push({
|
|
name: "Device " + i,
|
|
data: minuteDevicePoints[p].map((value, index) => ({
|
|
x: new Date( Date.now() - (60 - index) * 1000 ).toLocaleTimeString('hu-HU'),
|
|
y: value
|
|
})),
|
|
});
|
|
i++;
|
|
};
|
|
|
|
const hourHeatmapSeries = [];
|
|
|
|
var i = 0;
|
|
for (var p in hourDevicePoints) {
|
|
hourHeatmapSeries.push({
|
|
name: "Device " + i,
|
|
data: hourDevicePoints[p].map((value, index) => ({
|
|
x: new Date( Date.now() - (60 - index) * 1000 * 60 ).toLocaleTimeString('hu-HU').substring(0, 5),
|
|
y: value
|
|
})),
|
|
});
|
|
i++;
|
|
};
|
|
|
|
const barSeries = [];
|
|
|
|
const getCount = column => {
|
|
var counts = [];
|
|
|
|
for (var p in barDevicePoints) {
|
|
counts.unshift(barDevicePoints[p][column]);
|
|
}
|
|
|
|
return counts;
|
|
};
|
|
|
|
barSeries.push({
|
|
name: "Prob > 0.5",
|
|
data: getCount(0),
|
|
});
|
|
barSeries.push({
|
|
name: "Prob > 0.7",
|
|
data: getCount(1),
|
|
});
|
|
barSeries.push({
|
|
name: "Prob > 0.9",
|
|
data: getCount(2),
|
|
});
|
|
|
|
const lineSeries = [{name: "message/sec", data: []}];
|
|
for (var m in linePoints) {
|
|
lineSeries[0].data.push({
|
|
x: new Date(m).getTime(),
|
|
y: linePoints[m],
|
|
})
|
|
}
|
|
|
|
const getBarCategories = () => {
|
|
const categories = [];
|
|
|
|
for (var i = this.context.devices.length - 1; i >= 0; i--) {
|
|
categories.push("Device " + i)
|
|
}
|
|
|
|
return categories;
|
|
}
|
|
|
|
this.setState({
|
|
heatmapSecondsSeries: minuteHeatmapSeries,
|
|
heatmapMinutesSeries: hourHeatmapSeries,
|
|
barSeries: barSeries,
|
|
barCategories: getBarCategories(),
|
|
lineSeries: lineSeries,
|
|
});
|
|
|
|
setTimeout(this.updateDynamic, 1000);
|
|
}
|
|
|
|
const processHeatmapItem = processMethod.bind(this);
|
|
const onFinished = finishMethod.bind(this)
|
|
|
|
this.performTask(this.context.heatmapPoints, Math.ceil(this.context.heatmapPoints.length / 100), 10,
|
|
processHeatmapItem, onFinished);
|
|
}
|
|
|
|
performTask(items, numToProcess, wait, processItem, onFinished) {
|
|
var pos = 0;
|
|
// This is run once for every numToProcess items.
|
|
function iteration() {
|
|
// Calculate last position.
|
|
var j = Math.min(pos + numToProcess, items.length);
|
|
// Start at current position and loop to last position.
|
|
for (var i = pos; i < j; i++) {
|
|
processItem(items, i);
|
|
}
|
|
// Increment current position.
|
|
pos += numToProcess;
|
|
// Only continue if there are more items to process.
|
|
if (pos < items.length)
|
|
setTimeout(iteration, wait); // Wait 10 ms to let the UI update.
|
|
else
|
|
onFinished();
|
|
}
|
|
iteration();
|
|
}
|
|
|
|
render() {
|
|
const { classes } = this.props;
|
|
return (
|
|
<Box className={classes.root}>
|
|
<Grid container spacing={3}>
|
|
<Grid item xs={12}>
|
|
<Services isAdmin={this.props.isAdmin}/>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<Paper className={classes.paper}>
|
|
<DonutChart totalLabel="Devices" series={this.state.deviceSeries}/>
|
|
</Paper>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<Paper className={classes.paper}>
|
|
<DonutChart totalLabel="Sensors" series={this.state.sensorSeries}/>
|
|
</Paper>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<Paper className={classes.paper}>
|
|
<HeatmapChart label="Highest probability per second by devices" series={this.state.heatmapSecondsSeries}/>
|
|
</Paper>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<Paper className={classes.paper}>
|
|
<HeatmapChart label="Highest probability per minute by devices" series={this.state.heatmapMinutesSeries}/>
|
|
</Paper>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<Paper className={classes.paper}>
|
|
<BarChart label="# of messages by devices" series={this.state.barSeries} categories={this.state.barCategories}/>
|
|
</Paper>
|
|
</Grid>
|
|
<Grid item xs={6}>
|
|
<Paper className={classes.paper}>
|
|
<LineChart label="# of messages per second" series={this.state.lineSeries}/>
|
|
</Paper>
|
|
</Grid>
|
|
</Grid>
|
|
</Box>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default withStyles(styles)(Dashboard); |