1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-09 00:00:01 +01:00

Add plot-table widget

Bug: Width of plot in new widget is not correct resized
This commit is contained in:
Markus Grigull 2017-03-16 12:25:54 +01:00
parent 5bf9ad9f8d
commit 73a576ab88
5 changed files with 205 additions and 62 deletions

View file

@ -19,7 +19,8 @@ class TableColumn extends Component {
link: '/',
linkKey: '',
dataIndex: false,
inlineEditable: false
inlineEditable: false,
clickable: false
};
render() {

View file

@ -11,13 +11,14 @@ import React, { Component } from 'react';
import { Table, Button, Glyphicon, FormControl } from 'react-bootstrap';
import { Link } from 'react-router';
import TableColumn from './table-column';
//import TableColumn from './table-column';
class CustomTable extends Component {
constructor(props) {
super(props);
this.state = {
rows: [],
editCell: [ -1, -1 ]
};
}
@ -30,78 +31,97 @@ class CustomTable extends Component {
this.setState({ editCell: [ column, row ]}); // x, y
}
addCell(data, index, child) {
// add data to cell
const dataKey = child.props.dataKey;
var cell = [];
if (dataKey && data[dataKey] != null) {
// get content
var content;
const modifier = child.props.modifier;
if (modifier) {
content = modifier(data[dataKey]);
} else {
content = data[dataKey].toString();
}
// check if cell should be a link
const linkKey = child.props.linkKey;
if (linkKey && data[linkKey] != null) {
cell.push(<Link to={child.props.link + data[linkKey]}>{content}</Link>);
} else if (child.props.clickable) {
cell.push(<a onClick={() => child.props.onClick(index)}>{content}</a>);
} else {
cell.push(content);
}
}
if (child.props.dataIndex) {
cell.push(index);
}
// add buttons
if (child.props.editButton) {
cell.push(<Button bsClass='table-control-button' onClick={() => child.props.onEdit(index)}><Glyphicon glyph='pencil' /></Button>);
}
if (child.props.deleteButton) {
cell.push(<Button bsClass='table-control-button' onClick={() => child.props.onDelete(index)}><Glyphicon glyph='remove' /></Button>);
}
return cell;
}
componentWillReceiveProps(nextProps) {
// check if data exists
if (nextProps.data == null) {
this.setState({ rows: [] });
return;
}
// create row data
var rows = nextProps.data.map((data, index) => {
// check if multiple columns
if (Array.isArray(nextProps.children)) {
var row = [];
nextProps.children.forEach(child => {
row.push(this.addCell(data, index, child));
});
return row;
} else {
// table only has a single column
return [ this.addCell(data, index, nextProps.children) ];
}
});
this.setState({ rows: rows });
}
render() {
// create sorted data for rows
var rows = [];
if (this.props.data) {
rows = this.props.data.map((row, index) => {
var array = [];
for (var i = 0; i < this.props.children.length; i++) {
// only handle table-column children
if (this.props.children[i].type === TableColumn) {
// add content to cell
var cell = [];
// add data to cell
const dataKey = this.props.children[i].props.dataKey;
if (dataKey && row[dataKey] != null) {
// get content
var content;
const modifier = this.props.children[i].props.modifier;
if (modifier) {
content = modifier(row[dataKey]);
} else {
content = row[dataKey].toString();
}
// check if cell should be a link
const linkKey = this.props.children[i].props.linkKey;
if (linkKey && row[linkKey] != null) {
cell.push(<Link to={this.props.children[i].props.link + row[linkKey]}>{content}</Link>);
} else {
cell.push(content);
}
}
if (this.props.children[i].props.dataIndex) {
cell.push(index);
}
// add buttons
if (this.props.children[i].props.editButton) {
const onEdit = this.props.children[i].props.onEdit;
cell.push(<Button bsClass='table-control-button' onClick={() => onEdit(index)}><Glyphicon glyph='pencil' /></Button>);
}
if (this.props.children[i].props.deleteButton) {
const onDelete = this.props.children[i].props.onDelete;
cell.push(<Button bsClass='table-control-button' onClick={() => onDelete(index)}><Glyphicon glyph='remove' /></Button>);
}
array.push(cell);
}
}
return array;
});
// get children
var children = this.props.children;
if (Array.isArray(this.props.children) === false) {
children = [ children ];
}
return (
<Table width={this.props.width} striped hover>
<Table style={{ width: this.props.width}} striped hover bordered>
<thead>
<tr>
{this.props.children}
</tr>
</thead>
<tbody>
{rows.map((row, rowIndex) => (
{this.state.rows.map((row, rowIndex) => (
<tr key={rowIndex}>
{row.map((cell, cellIndex) => (
<td key={cellIndex} onClick={this.props.children[cellIndex].props.inlineEditable === true ? (event) => this.onClick(event, rowIndex, cellIndex) : () => {}}>
<td key={cellIndex} onClick={children[cellIndex].props.inlineEditable === true ? (event) => this.onClick(event, rowIndex, cellIndex) : () => {}}>
{(this.state.editCell[0] === cellIndex && this.state.editCell[1] === rowIndex ) ? (
<FormControl type="text" value={cell} onChange={(event) => this.props.children[cellIndex].props.onInlineChange(event, rowIndex, cellIndex)} />
<FormControl type="text" value={cell} onChange={(event) => children[cellIndex].props.onInlineChange(event, rowIndex, cellIndex)} />
) : (
<span>
{cell.map((element, elementIndex) => (

View file

@ -0,0 +1,112 @@
/**
* File: widget-plot-table.js
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
* Date: 15.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
import React, { Component } from 'react';
import { LineChart } from 'rd3';
import { Col } from 'react-bootstrap';
import Table from './table';
import TableColumn from './table-column';
class WidgetPlotTable extends Component {
constructor(props) {
super(props);
this.state = {
signal: 0,
firstTimestamp: 0,
latestTimestamp: 0,
sequence: null,
rows: [],
values: []
};
}
componentWillReceiveProps(nextProps) {
// check data
const simulator = nextProps.widget.simulator;
if (nextProps.simulation == null || nextProps.data == null || nextProps.data[simulator] == null || nextProps.data[simulator].length === 0 || nextProps.data[simulator].values[0].length === 0) {
// clear values
this.setState({ values: [], sequence: null, rows: [] });
return;
}
// check if new data, otherwise skip
if (this.state.sequence >= nextProps.data[simulator].sequence) {
return;
}
// get simulation model
const simulationModel = nextProps.simulation.models.find((model) => {
return (model.simulator === simulator);
});
// get rows
var rows = [];
simulationModel.mapping.forEach((signal) => {
rows.push({ name: signal.name })
});
// get timestamps
var latestTimestamp = nextProps.data[simulator].values[0][nextProps.data[simulator].values[0].length - 1].x;
var firstTimestamp = latestTimestamp - nextProps.widget.time * 1000;
var firstIndex;
if (nextProps.data[simulator].values[0][0].x < firstTimestamp) {
// find element index representing firstTimestamp
firstIndex = nextProps.data[simulator].values[0].findIndex((value) => {
return value.x >= firstTimestamp;
});
} else {
firstIndex = 0;
firstTimestamp = nextProps.data[simulator].values[0][0].x;
latestTimestamp = firstTimestamp + nextProps.widget.time * 1000;
}
// copy all values for each signal in time region
var values = [{
values: nextProps.data[simulator].values[this.state.signal].slice(firstIndex, nextProps.data[simulator].values[this.state.signal].length - 1)
}];
this.setState({ values: values, firstTimestamp: firstTimestamp, latestTimestamp: latestTimestamp, sequence: nextProps.data[simulator].sequence, rows: rows });
}
render() {
return (
<div style={{ width: '100%', height: '100%' }} ref="wrapper">
<h4>{this.props.widget.name}</h4>
<Col xs={3}>
<Table data={this.state.rows}>
<TableColumn title="Signal" dataKey="name" clickable onClick={(index) => this.setState({ signal: index }) } />
</Table>
</Col>
<Col xs={4}>
{this.state.sequence &&
<LineChart
width={400}
height={this.props.widget.height - 20}
data={this.state.values}
gridHorizontal={true}
xAccessor={(d) => { if (d != null) { return new Date(d.x); } }}
hoverAnimation={false}
circleRadius={0}
domain={{ x: [this.state.firstTimestamp, this.state.latestTimestamp] }}
/>
}
</Col>
</div>
);
}
}
export default WidgetPlotTable;

View file

@ -118,7 +118,7 @@ class Visualization extends Component {
} else if (item.name === 'Plot') {
widget.simulator = this.state.simulation.models[0].simulator;
widget.signals = [ 0 ];
widget.time = 300;
widget.time = 60;
widget.width = 400;
widget.height = 200;
} else if (item.name === 'Table') {
@ -127,6 +127,11 @@ class Visualization extends Component {
widget.height = 200;
} else if (item.name === 'Label') {
} else if (item.name === 'PlotTable') {
widget.simulator = this.state.simulation.models[0].simulator;
widget.width = 500;
widget.height = 400;
widget.time = 60
}
var visualization = this.state.visualization;
@ -276,6 +281,7 @@ class Visualization extends Component {
<ToolboxItem name="Table" type="widget" />
<ToolboxItem name="Label" type="widget" />
<ToolboxItem name="Image" type="widget" disabled />
<ToolboxItem name="PlotTable" type="widget" />
</div>
}

View file

@ -18,6 +18,7 @@ import WidgetValue from '../components/widget-value';
import WidgetPlot from '../components/widget-plot';
import WidgetTable from '../components/widget-table';
import WidgetLabel from '../components/widget-label';
import WidgetPlotTable from '../components/widget-plot-table';
import '../styles/widgets.css';
@ -83,6 +84,7 @@ class Widget extends Component {
const widget = this.props.data;
var element = null;
// dummy is passed to widgets to keep updating them while in edit mode
if (widget.type === 'Value') {
element = <WidgetValue widget={widget} data={this.state.simulatorData} dummy={this.state.sequence} simulation={this.props.simulation} />
} else if (widget.type === 'Plot') {
@ -91,6 +93,8 @@ class Widget extends Component {
element = <WidgetTable widget={widget} data={this.state.simulatorData} dummy={this.state.sequence} simulation={this.props.simulation} />
} else if (widget.type === 'Label') {
element = <WidgetLabel widget={widget} />
} else if (widget.type === 'PlotTable') {
element = <WidgetPlotTable widget={widget} data={this.state.simulatorData} dummy={this.state.sequence} simulation={this.props.simulation} />
}
if (this.props.editing) {