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

Increase widget performance

Make rest-api more universal usable
This commit is contained in:
Markus Grigull 2017-03-14 19:00:13 +01:00
parent 913280af2e
commit 42e4afbed8
8 changed files with 135 additions and 88 deletions

View file

@ -10,17 +10,10 @@
import request from 'superagent/lib/client';
import Promise from 'es6-promise';
const API_URL = 'http://localhost:4000/api/v1';
function makeURL(part) {
// TODO: Add / if missing at front of part
return API_URL + part;
}
class RestAPI {
get(url) {
return new Promise(function (resolve, reject) {
request.get(makeURL(url)).end(function (error, res) {
request.get(url).set('Access-Control-Allow-Origin', '*').end(function (error, res) {
if (res == null || res.status !== 200) {
reject(error);
} else {
@ -32,7 +25,7 @@ class RestAPI {
post(url, body) {
return new Promise(function (resolve, reject) {
request.post(makeURL(url)).send(body).end(function (error, res) {
request.post(url).send(body).end(function (error, res) {
if (res == null || res.status !== 200) {
reject(error);
} else {
@ -44,7 +37,7 @@ class RestAPI {
delete(url) {
return new Promise(function (resolve, reject) {
request.delete(makeURL(url)).end(function (error, res) {
request.delete(url).end(function (error, res) {
if (res == null || res.status !== 200) {
reject(error);
} else {
@ -56,7 +49,7 @@ class RestAPI {
put(url, body) {
return new Promise(function (resolve, reject) {
request.put(makeURL(url)).send(body).end(function (error, res) {
request.put(url).send(body).end(function (error, res) {
if (res == null || res.status !== 200) {
reject(error);
} else {

View file

@ -11,55 +11,73 @@ import React, { Component } from 'react';
import { LineChart } from 'rd3';
class WidgetPlot extends Component {
constructor(props) {
super(props);
this.state = {
values: [],
firstTimestamp: 0,
latestTimestamp: 0,
sequence: null
};
}
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 });
return;
}
// check if new data, otherwise skip
if (this.state.sequence >= nextProps.data[simulator].sequence) {
return;
}
// get timestamps
const latestTimestamp = nextProps.data[simulator].values[0][nextProps.data[simulator].values[0].length - 1].x;
const firstTimestamp = latestTimestamp - nextProps.widget.time * 100;
// find element index representing firstTimestamp
const firstIndex = nextProps.data[simulator].values[0].findIndex((value) => {
return value.x >= firstTimestamp;
});
// copy all values for each signal in time region
var values = [];
nextProps.widget.signals.forEach((signal) => {
values.push({
values: nextProps.data[simulator].values[signal].slice(firstIndex, nextProps.data[simulator].values[signal].length - 1)
});
});
this.setState({ values: values, firstTimestamp: firstTimestamp, latestTimestamp: latestTimestamp, sequence: nextProps.data[simulator].sequence });
}
render() {
// get selected simulation model
const widget = this.props.widget;
var simulationModel;
if (this.props.simulation && this.props.simulation.models && this.props.data[widget.simulator]) {
this.props.simulation.models.forEach((model) => {
if (model.simulator === widget.simulator) {
simulationModel = model;
if (this.state.sequence == null) {
return (<div>Empty</div>);
}
});
} else {
return (<div></div>);
}
if (widget.plotType === 'table') {
return (
<div>Table</div>
);
} else if (widget.plotType === 'multiple') {
// get selected data
var lineData = [];
const latestTimestamp = this.props.data[widget.simulator].values[0][this.props.data[widget.simulator].values[0].length - 1].x;
widget.signals.forEach((signal) => {
lineData.push({
name: simulationModel.mapping[signal].name,
values: this.props.data[widget.simulator].values[signal]
});
});
return (
<div style={{ width: '100%', height: '100%' }} ref="wrapper">
<LineChart
width={widget.width}
height={widget.height - 20}
data={lineData}
title={widget.name}
width={this.props.widget.width}
height={this.props.widget.height - 20}
data={this.state.values}
title={this.props.widget.name}
gridHorizontal={true}
xAccessor={(d) => {return new Date(d.x);}}
hoverAnimation={false}
circleRadius={0}
domain={{ x: [latestTimestamp - 10000, latestTimestamp] }}
domain={{ x: [this.state.firstTimestamp, this.state.latestTimestamp] }}
/>
</div>
);
} else {
return (<div>Error</div>);
}
}
}

View file

@ -10,19 +10,34 @@
import React, { Component } from 'react';
class WidgetValue extends Component {
render() {
// calculate value
var value = null;
const widget = this.props.widget;
constructor(props) {
super(props);
if (this.props.data && this.props.data[widget.simulator] && this.props.data[widget.simulator].values) {
const signalArray = this.props.data[widget.simulator].values[widget.signal];
value = signalArray[signalArray.length - 1].y;
this.state = {
value: ''
};
}
componentWillReceiveProps(nextProps) {
// update value
const simulator = nextProps.widget.simulator;
if (nextProps.data == null || nextProps.data[simulator] == null || nextProps.data[simulator].values == null) {
this.setState({ value: '' });
return;
}
// check if value has changed
const signal = nextProps.data[simulator].values[nextProps.widget.signal];
if (this.state.value !== signal[signal.length - 1].y) {
this.setState({ value: signal[signal.length - 1].y });
}
}
render() {
return (
<div>
{widget.name}: {value}
{this.props.widget.name}: {this.state.value}
</div>
);
}

View file

@ -117,8 +117,10 @@ class Visualization extends Component {
widget.signal = 0;
} else if (item.name === 'Plot') {
widget.simulator = this.state.simulation.models[0].simulator;
widget.plotType = 'multiple';
widget.signals = [ 0 ];
widget.time = 300;
widget.width = 400;
widget.height = 200;
}
var visualization = this.state.visualization;

View file

@ -69,9 +69,9 @@ class Widget extends Component {
var element = null;
if (widget.type === 'Value') {
element = <WidgetValue widget={widget} data={this.state.simulatorData} sequence={this.state.sequence} simulation={this.props.simulation} />
element = <WidgetValue widget={widget} data={this.state.simulatorData} dummy={this.state.sequence} simulation={this.props.simulation} />
} else if (widget.type === 'Plot') {
element = <WidgetPlot widget={widget} data={this.state.simulatorData} sequence={this.state.sequence} simulation={this.props.simulation} />
element = <WidgetPlot widget={widget} data={this.state.simulatorData} dummy={this.state.sequence} simulation={this.props.simulation} />
}
if (this.props.editing) {

View file

@ -10,16 +10,22 @@
import RestAPI from '../api/rest-api';
import AppDispatcher from '../app-dispatcher';
const API_URL = 'http://localhost:4000/api/v1';
class RestDataManager {
constructor(type, url) {
this.url = url;
this.type = type;
}
makeURL(part) {
return API_URL + part;
}
load(id) {
if (id != null) {
// load single object
RestAPI.get(this.url + '/' + id).then(response => {
RestAPI.get(this.makeURL(this.url + '/' + id)).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/loaded',
data: response[this.type]
@ -32,7 +38,7 @@ class RestDataManager {
});
} else {
// load all objects
RestAPI.get(this.url).then(response => {
RestAPI.get(this.makeURL(this.url)).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/loaded',
data: response[this.type + 's']
@ -50,7 +56,7 @@ class RestDataManager {
var obj = {};
obj[this.type] = object;
RestAPI.post(this.url, obj).then(response => {
RestAPI.post(this.makeURL(this.url), obj).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/added',
data: response[this.type]
@ -64,7 +70,7 @@ class RestDataManager {
}
remove(object) {
RestAPI.delete(this.url + '/' + object._id).then(response => {
RestAPI.delete(this.makeURL(this.url + '/' + object._id)).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/removed',
data: response[this.type],
@ -82,7 +88,7 @@ class RestDataManager {
var obj = {};
obj[this.type] = object;
RestAPI.put(this.url + '/' + object._id, obj).then(response => {
RestAPI.put(this.makeURL(this.url + '/' + object._id), obj).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/edited',
data: response[this.type]

View file

@ -23,9 +23,13 @@ class SimulatorDataDataManager {
this._sockets.close();
this._sockets[identifier] = WebsocketAPI.addSocket(endpoint, { onOpen: (event) => this.onOpen(event, identifier, signals), onClose: (event) => this.onClose(event, identifier), onMessage: (event) => this.onMessage(event, identifier) });
console.log('Modified socket');
}
} else {
this._sockets[identifier] = WebsocketAPI.addSocket(endpoint, { onOpen: (event) => this.onOpen(event, identifier, signals), onClose: (event) => this.onClose(event, identifier), onMessage: (event) => this.onMessage(event, identifier) });
console.log('New socket');
}
}
@ -47,6 +51,8 @@ class SimulatorDataDataManager {
onMessage(event, identifier) {
var message = this.bufferToMessage(event.data);
//console.log(message);
AppDispatcher.dispatch({
type: 'simulatorData/data-changed',
data: message,

View file

@ -12,7 +12,7 @@ import { ReduceStore } from 'flux/utils';
import AppDispatcher from '../app-dispatcher';
import SimulatorDataDataManager from '../data-managers/simulator-data-data-manager';
const MAX_VALUES = 100;
const MAX_VALUES = 1000;
class SimulationDataStore extends ReduceStore {
constructor() {
@ -39,9 +39,13 @@ class SimulationDataStore extends ReduceStore {
state[action.identifier].values.push([]);
}
console.log('Socket opened');
return state;
case 'simulatorData/data-changed':
// only add data, if newer than current
if (state[action.identifier].sequence < action.data.sequence) {
// add data to simulator
for (i = 0; i < state[action.identifier].signals; i++) {
state[action.identifier].values[i].push({ x: action.data.timestamp, y: action.data.values[i] });
@ -59,6 +63,9 @@ class SimulationDataStore extends ReduceStore {
// explicit call to prevent array copy
this.__emitChange();
} else {
console.log('same sequence');
}
return state;