webgme-dss
Version:
Design Studio for Dynamic Systems with Modelica as backend
249 lines (211 loc) • 7.31 kB
JSX
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import update from 'immutability-helper';
import IconButton from '@material-ui/core/IconButton';
import OpenInNew from '@material-ui/icons/OpenInNew';
import AddCircle from '@material-ui/icons/AddCircle';
import PortalWindow from '../gme/PortalWindow';
import Plotter from './Plotter';
import CheckboxList from '../gme/CheckboxList';
import colorHash from '../gme/utils/colorHash';
class PlotManager extends Component {
static propTypes = {
variables: PropTypes.arrayOf(PropTypes.string).isRequired,
simRes: PropTypes.object.isRequired,
};
state = {
docked: true,
latestWindowId: null,
plotWindows: {},
};
componentWillReceiveProps(nextProps) {
const {plotWindows, latestWindowId} = this.state;
const windowIds = Object.keys(plotWindows);
if (windowIds.length > 0) {
// Filter invalid ones and add new ones.
const newPlotVariables = nextProps.variables.filter(varName => !this.props.variables.includes(varName));
const updateDesc = {};
windowIds.forEach((windowId) => {
let windowVariables = plotWindows[windowId].variables
.filter(varName => nextProps.variables.includes(varName));
if (windowId === latestWindowId) {
windowVariables = windowVariables.concat(newPlotVariables);
}
updateDesc[windowId] = {
$set: {
variables: windowVariables,
},
};
});
this.setState({plotWindows: update(this.state.plotWindows, updateDesc)});
}
}
toggleDocked = () => {
const {variables} = this.props;
const {docked} = this.state;
const newState = {
docked: !docked,
latestWindowId: null,
plotWindows: {},
};
if (docked) {
newState.plotWindows['1'] = {
variables,
};
newState.latestWindowId = '1';
}
this.setState(newState);
};
addPlotWindow = () => {
const {plotWindows} = this.state;
let id;
for (let i = 1; i <= Object.keys(plotWindows).length + 1; i += 1) {
if (!plotWindows[i]) {
id = i.toString();
break;
}
}
this.setState({
plotWindows: update(plotWindows, {
[id]: {
$set: {variables: []},
},
}),
latestWindowId: id,
});
}
removePlotWindow = (id) => {
const {plotWindows, latestWindowId} = this.state;
const windowIds = Object.keys(plotWindows);
if (windowIds.length === 1) {
// Last window is removed - we are no longer undocked.
this.toggleDocked();
return;
}
const newState = {
plotWindows: update(plotWindows, {
$unset: [id],
}),
};
if (id === latestWindowId) {
newState.latestWindowId = windowIds.find(windowId => windowId !== id);
}
this.setState(newState);
}
plotVariableCheckChange = windowId => (varName, event, checked) => {
const {plotWindows} = this.state;
let varAddOrRemove;
if (checked) {
varAddOrRemove = {
$push: [varName],
};
} else {
varAddOrRemove = {
$splice: [[plotWindows[windowId].variables.indexOf(varName), 1]],
};
}
this.setState({
latestWindowId: windowId,
plotWindows: update(plotWindows, {
[windowId]: {
variables: varAddOrRemove,
},
}),
});
}
render() {
const {variables, simRes} = this.props;
const {docked, plotWindows} = this.state;
// FIXME: Problem mutating there? It's only sorting though...
variables.sort();
const toggleDockedBtn = (
<IconButton
style={{
position: 'absolute',
top: 0,
right: 5,
}}
onClick={this.toggleDocked}
>
<OpenInNew style={{
transform: `rotate(${docked ? 0 : 180}deg)`,
}}
/>
</IconButton>
);
if (docked) {
return (
<div>
{toggleDockedBtn}
<Plotter variables={variables} simRes={simRes}/>
</div>);
}
const windowIds = Object.keys(plotWindows).sort();
const portals = windowIds.map(windowId => (
<PortalWindow
key={windowId}
onClose={() => this.removePlotWindow(windowId)}
windowFeatures={{
height: 400,
width: 800,
}}
>
<title>{`Plot window ${windowId}`}</title>
<h1>{`Plot window ${windowId}`}:</h1>
<Plotter variables={plotWindows[windowId].variables} simRes={simRes}/>
</PortalWindow>
));
const selectors = windowIds.map((windowId) => {
const checkBoxes = variables.map(varName => ({
id: varName,
isChecked: plotWindows[windowId].variables.includes(varName),
cbStyle: {
color: colorHash(varName).rgb,
height: 36,
},
}));
return (
<CheckboxList
key={windowId}
title={`Plot window ${windowId}:`}
items={checkBoxes}
onCheckedChange={this.plotVariableCheckChange(windowId)}
/>
);
});
const addWindowBtn = (
<IconButton
style={{
position: 'absolute',
top: 0,
left: 0,
}}
onClick={this.addPlotWindow}
>
<AddCircle/>
</IconButton>
);
return (
<div style={{
height: 300,
}}
>
{toggleDockedBtn}
{addWindowBtn}
<div style={{
display: 'inline-flex',
paddingLeft: 50,
paddingTop: 20,
height: 'calc(100% - 20px)',
width: 'calc(100% - 50px)',
overflow: 'auto',
}}
>
{selectors}
</div>
{portals}
</div>
);
}
}
export default PlotManager;