Files
MaxWaterSystem-Electron/app/src/components/Main.js
2018-04-12 18:33:35 -05:00

294 lines
7.2 KiB
JavaScript

import React, { Component } from "react";
import _ from "lodash";
import { connect } from "react-redux";
import { FlexibleWidthXYPlot, LineSeries, VerticalGridLines, HorizontalGridLines, XAxis, YAxis, DiscreteColorLegend } from "react-vis";
// import "../../../node_modules/react-vis/dist/style.css";
import { color } from "d3-color";
import { interpolateRgb } from "d3-interpolate";
import LiquidFillGauge from "react-liquid-gauge";
import { RadialGauge } from "react-canvas-gauges";
/** Class for Main Page
*
* @extends React.Component
*/
class Main extends Component {
/**
* Map an array of objects to a graph-usable array of objects
*
* @param {Array} values - list of objects with timestame and value properties
*
* @returns {Array} list of objects with x and y properties
*/
mapTimestampAndValuePropToXY(values){
return _.map(values, (val) => {
return {x: val.timestamp, y: val.value};
});
}
/**
* Renders a Liquid Gauge.
*
* @param {object} tag - the tag structure
* @param {string} units - units for the tag
* @param {number} maxValue - maximum value to be displayed
* @param {number} label - label for the value (typically the tag name)
* @returns {ReactElement} liquidGauge
*/
renderLiquidGauge(tag, units, maxValue, label){
if (!tag){
return <span></span>;
}
const tagValue = tag.value;
const endColor = "#1F4788";
const startColor = "#dc143c";
const radius = 100;
const interpolate = interpolateRgb(startColor, endColor);
const fillColor = interpolate(tagValue / maxValue);
const gradientStops = [
{
key: "0%",
stopColor: color(fillColor).darker(0.5).toString(),
stopOpacity: 1,
offset: "0%"
},
{
key: "50%",
stopColor: fillColor,
stopOpacity: 0.75,
offset: "50%"
},
{
key: "100%",
stopColor: color(fillColor).brighter(0.5).toString(),
stopOpacity: 0.5,
offset: "100%"
}
];
return (
<div className="col" style={{textAlign: "center"}}>
<h3>{label}</h3>
<LiquidFillGauge
style={{ margin: "0 auto" }}
width={radius * 2}
height={radius * 2}
value={tagValue / maxValue * 100}
percent={units}
textSize={1}
textOffsetX={0}
textOffsetY={0}
textRenderer={(props) => {
const value = Math.round(tagValue);
const radius = Math.min(props.height / 2, props.width / 2);
const textPixels = (props.textSize * radius / 2);
const valueStyle = {
fontSize: textPixels
};
const percentStyle = {
fontSize: textPixels * 0.6
};
return (
<tspan>
<tspan className="value" style={valueStyle}>{value}</tspan>
<tspan style={percentStyle}>{props.percent}</tspan>
</tspan>
);
}}
riseAnimation
waveAnimation
waveFrequency={3}
waveAmplitude={2}
gradient
gradientStops={gradientStops}
circleStyle={{
fill: fillColor
}}
waveStyle={{
fill: fillColor
}}
textStyle={{
fill: color("#444").toString(),
fontFamily: "Arial"
}}
waveTextStyle={{
fill: color("#fff").toString(),
fontFamily: "Arial"
}}
/>
</div>
);
}
/**
* Renders a radial gauge.
*
* @param {Object} tag - the tag structure
* @param {string} units - units for the tag
* @param {number} maxValue - maximum value to be displayed
* @param {number} label - label for the value (typically the tag name)
*/
renderRadialGauge(tag, units, maxValue, label){
if (!tag){
return <span></span>;
}
const ticks = [ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 ];
return (
<div className="col" style={{textAlign: "center"}}>
<h3>{label}</h3>
<RadialGauge
height={200}
width={200}
units={units}
title={label}
value={tag.value}
minValue={0}
maxValue={maxValue}
majorTicks={ticks.map((t) => t * maxValue)}
minorTicks={2}
></RadialGauge>
</div>
);
}
/**
* render
*
* @returns {ReactElement} markup
*/
render(){
if (!this.props.tagHistory){
return(
<div className="container">
<h1>Loading...</h1>
</div>
);
}
if (this.props.plc.error){
return(
<div className="container plc-error">
<h1>PLC Error</h1>
<h3>{this.props.plc.error}</h3>
</div>
);
}
if (Object.keys(this.props.tags).length === 0){
return(
<div className="container">
<h1>Waiting for data...</h1>
</div>
);
}
return (
<div className="container">
<h3>Process Values</h3>
<div className="row" style={{marginBottom: "20px"}}>
{this.renderLiquidGauge(this.props.tags.val_FluidLevel, "ft.", 500, "Level")}
{this.renderRadialGauge(this.props.tags.val_Flowmeter_BarrelsPerDay, "BPD", 5000, "Flow Rate")}
{this.renderRadialGauge(this.props.tags.val_TubingPressure, "PSI", 400, "Tubing Pressure")}
</div>
<FlexibleWidthXYPlot
height={300}
xType="time"
>
<VerticalGridLines />
<HorizontalGridLines />
<XAxis />
<YAxis />
<LineSeries
data={this.mapTimestampAndValuePropToXY(this.props.tagHistory.val_IntakePressure)}
/>
<LineSeries
data={this.mapTimestampAndValuePropToXY(this.props.tagHistory.val_Flowmeter)}
/>
<LineSeries
data={this.mapTimestampAndValuePropToXY(this.props.tagHistory.val_FluidLevel)}
/>
<LineSeries
data={this.mapTimestampAndValuePropToXY(this.props.tagHistory.val_IntakeTemperature)}
/>
<LineSeries
data={this.mapTimestampAndValuePropToXY(this.props.tagHistory.val_TubingPressure)}
/>
</FlexibleWidthXYPlot>
<DiscreteColorLegend
items={[
{title: "Intake Pressure"},
{title: "Flowmeter"},
{title: "Fluid Level"},
{title: "Intake Temp"},
{title: "Tubing Pressure"}
]}
orientation="horizontal"
/>
<hr />
<h3>VFD Data</h3>
<div className="row" style={{marginBottom: "20px"}}>
{this.renderRadialGauge(this.props.tags.VFD_OutCurrent, "A.", 100, "Current")}
{this.renderRadialGauge(this.props.tags.VFD_SpeedFdbk, "Hz", 60, "Frequency")}
</div>
<FlexibleWidthXYPlot
height={300}
xType="time"
>
<VerticalGridLines />
<HorizontalGridLines />
<XAxis />
<YAxis />
<LineSeries
data={this.mapTimestampAndValuePropToXY(this.props.tagHistory.VFD_OutCurrent)}
/>
<LineSeries
data={this.mapTimestampAndValuePropToXY(this.props.tagHistory.VFD_SpeedFdbk)}
/>
<LineSeries
data={this.mapTimestampAndValuePropToXY(this.props.tagHistory.VFD_OutPower)}
/>
<LineSeries
data={this.mapTimestampAndValuePropToXY(this.props.tagHistory.VFD_Temp)}
/>
</FlexibleWidthXYPlot>
<DiscreteColorLegend
items={[
{title: "VFD Current"},
{title: "VFD Speed Feedback"},
{title: "VFD Output Power"},
{title: "VFD Temp"}
]}
orientation="horizontal"
/>
</div>
);
}
}
/**
* Map Redux state to React props
*
* @param {Object} state
*
* @returns {Object} mapped state
*/
function mapStateToProps(state){
return {
tags: state.tags,
tagHistory: state.tagHistory,
plc: state.plc
};
}
export default connect(mapStateToProps)(Main);