mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
Increase widget performance
Make rest-api more universal usable
This commit is contained in:
parent
913280af2e
commit
42e4afbed8
8 changed files with 135 additions and 88 deletions
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return (<div></div>);
|
||||
if (this.state.sequence == null) {
|
||||
return (<div>Empty</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}
|
||||
gridHorizontal={true}
|
||||
xAccessor={(d) => {return new Date(d.x);}}
|
||||
hoverAnimation={false}
|
||||
circleRadius={0}
|
||||
domain={{ x: [latestTimestamp - 10000, latestTimestamp] }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (<div>Error</div>);
|
||||
}
|
||||
return (
|
||||
<div style={{ width: '100%', height: '100%' }} ref="wrapper">
|
||||
<LineChart
|
||||
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: [this.state.firstTimestamp, this.state.latestTimestamp] }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,27 +39,34 @@ class SimulationDataStore extends ReduceStore {
|
|||
state[action.identifier].values.push([]);
|
||||
}
|
||||
|
||||
console.log('Socket opened');
|
||||
|
||||
return state;
|
||||
|
||||
case 'simulatorData/data-changed':
|
||||
// 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] });
|
||||
// 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] });
|
||||
|
||||
// erase old values
|
||||
if (state[action.identifier].values[i].length > MAX_VALUES) {
|
||||
const pos = state[action.identifier].values[i].length - MAX_VALUES;
|
||||
state[action.identifier].values[i].splice(0, pos);
|
||||
// erase old values
|
||||
if (state[action.identifier].values[i].length > MAX_VALUES) {
|
||||
const pos = state[action.identifier].values[i].length - MAX_VALUES;
|
||||
state[action.identifier].values[i].splice(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
// update metadata
|
||||
state[action.identifier].timestamp = action.data.timestamp;
|
||||
state[action.identifier].sequence = action.data.sequence;
|
||||
|
||||
// explicit call to prevent array copy
|
||||
this.__emitChange();
|
||||
} else {
|
||||
console.log('same sequence');
|
||||
}
|
||||
|
||||
// update metadata
|
||||
state[action.identifier].timestamp = action.data.timestamp;
|
||||
state[action.identifier].sequence = action.data.sequence;
|
||||
|
||||
// explicit call to prevent array copy
|
||||
this.__emitChange();
|
||||
|
||||
return state;
|
||||
|
||||
case 'simulatorData/closed':
|
||||
|
|
Loading…
Add table
Reference in a new issue