Skip to content

Commit c76ead9

Browse files
committedJan 29, 2019
Added download as SVG option and some re-org of components
1 parent 5d7ada0 commit c76ead9

9 files changed

+179
-43
lines changed
 

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"dependencies": {
66
"@cloudseam/machine-validator": "^1.0.0",
77
"@material-ui/core": "^3.9.1",
8+
"@material-ui/icons": "^3.0.2",
89
"react": "^16.7.0",
910
"react-ace": "^6.3.2",
1011
"react-dom": "^16.7.0",

‎src/App.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ import Editor from './editor/Editor';
33
import AppBar from '@material-ui/core/AppBar';
44
import Toolbar from '@material-ui/core/Toolbar';
55
import Typography from '@material-ui/core/Typography';
6-
import Grid from '@material-ui/core/Grid';
76
import './App.css';
8-
import MachineInfoDisplay from './MachineInfoDisplay';
7+
import MachineInfoDisplay from './machineInfo/MachineInfoDisplay';
98
import SplitPane from 'react-split-pane';
109

1110
import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider';
+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import React, { Component, Fragment } from 'react';
2+
import PropTypes from 'prop-types';
3+
import List from '@material-ui/core/List';
4+
import ListItem from '@material-ui/core/ListItem';
5+
import ListItemText from '@material-ui/core/ListItemText';
6+
import MenuItem from '@material-ui/core/MenuItem';
7+
import Menu from '@material-ui/core/Menu';
8+
import { ArrowDropDown } from '@material-ui/icons';
9+
10+
const options = [
11+
{ key : 'left-right', display : 'Horizontal' },
12+
{ key : 'top-down', display : 'Vertical' },
13+
];
14+
15+
class GraphDirectionSelection extends Component {
16+
state = {
17+
anchorEl: null,
18+
selectedIndex: 0,
19+
};
20+
21+
handleListItemClick = (event) => {
22+
this.setState({ anchorEl: event.currentTarget });
23+
};
24+
25+
handleMenuItemClick = (event, index) => {
26+
this.setState({ selectedIndex: index, anchorEl: null });
27+
this.props.onDirectionChange(options[index].key);
28+
};
29+
30+
handleMenuClose = (direction) => {
31+
this.setState({ anchorEl : null });
32+
};
33+
34+
render() {
35+
const { anchorEl, selectedIndex } = this.state;
36+
37+
return (
38+
<Fragment>
39+
<List component="nav">
40+
<ListItem
41+
button
42+
aria-haspopup="true"
43+
aria-controls="lock-menu"
44+
aria-label="Graph Direction"
45+
onClick={this.handleListItemClick}
46+
>
47+
<ListItemText
48+
secondary={options[selectedIndex].display}
49+
>
50+
Graph Direction <ArrowDropDown style={{fontSize:"16px"}} />
51+
</ListItemText>
52+
</ListItem>
53+
</List>
54+
<Menu
55+
id="lock-menu"
56+
anchorEl={anchorEl}
57+
open={Boolean(anchorEl)}
58+
onClose={this.handleMenuClose}
59+
>
60+
{options.map((option, index) => (
61+
<MenuItem
62+
key={option.key}
63+
selected={index === selectedIndex}
64+
onClick={event => this.handleMenuItemClick(event, index)}
65+
>
66+
{option.display}
67+
</MenuItem>
68+
))}
69+
</Menu>
70+
</Fragment>
71+
);
72+
}
73+
}
74+
75+
GraphDirectionSelection.propTypes = {
76+
direction : PropTypes.string.isRequired,
77+
onDirectionChange : PropTypes.func.isRequired,
78+
};
79+
80+
export default GraphDirectionSelection;
File renamed without changes.

‎src/GraphDisplay.js ‎src/machineInfo/GraphDisplay.js

+17-40
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
import React, { Component } from 'react';
22
import PropTypes from 'prop-types';
33
import machineToSmcat from './machineToSmcat';
4-
import Button from '@material-ui/core/Button';
5-
import Menu from '@material-ui/core/Menu';
6-
import MenuItem from '@material-ui/core/MenuItem';
4+
import Grid from '@material-ui/core/Grid';
75
import Typography from '@material-ui/core/Typography';
6+
import GraphDirectionSelection from './GraphDirectionSelection';
7+
import GraphDownloadOptions from './GraphDownloadOptions';
88
import './GraphDisplay.css';
99
import svgPanZoom from 'svg-pan-zoom';
1010

1111
class GraphDisplay extends Component {
1212
state = {
1313
smCatConfig : null,
1414
direction : 'Left-Right',
15-
anchorEl: null,
1615
};
1716

1817
svgPanObject = null;
@@ -42,6 +41,9 @@ class GraphDisplay extends Component {
4241
}
4342

4443
updateGraphDisplay = () => {
44+
if (!this.refs.graph)
45+
return;
46+
4547
const svg = this.refs.graph.querySelector("svg");
4648
if (svg) {
4749
if (this.svgPanObject)
@@ -50,53 +52,28 @@ class GraphDisplay extends Component {
5052
}
5153
};
5254

53-
handleMenuClick = event => {
54-
this.setState({ anchorEl: event.currentTarget });
55-
};
56-
57-
handleMenuClose = (direction) => {
58-
if (!direction) direction = this.state.direction;
59-
this.setState({ anchorEl: null, direction });
60-
};
61-
62-
download = () => {
63-
const canvas = document.createElement('canvas');
64-
window.canvg(canvas, this.state.svg);
65-
66-
const link = document.createElement('a');
67-
link.download = 'state-chart.png';
68-
link.href = canvas.toDataURL();
69-
link.click();
55+
onDirectionChange = (direction) => {
56+
this.setState({ direction });
7057
};
7158

7259
render() {
73-
const { svg, anchorEl, direction } = this.state;
60+
const { svg, direction } = this.state;
7461

7562
return (
7663
<div id='graph-display'>
7764

7865
<Typography variant="h5" color="inherit">
7966
State Machine Graph
80-
{ svg && <Button variant="contained" color="primary" style={{marginLeft:"20px"}} onClick={this.download}>Download</Button> }
8167
</Typography>
8268

83-
Direction:
84-
<Button
85-
aria-owns={anchorEl ? 'direction-menu' : undefined}
86-
aria-haspopup="true"
87-
onClick={this.handleMenuClick}
88-
>
89-
{ direction }
90-
</Button>
91-
<Menu
92-
id="direction-menu"
93-
anchorEl={anchorEl}
94-
open={Boolean(anchorEl)}
95-
onClose={() => this.handleMenuClose()}
96-
>
97-
<MenuItem onClick={() => this.handleMenuClose('Left-Right')}>Left-Right</MenuItem>
98-
<MenuItem onClick={() => this.handleMenuClose('Top-Down')}>Top-Down</MenuItem>
99-
</Menu>
69+
<Grid container spacing={16} alignItems="center">
70+
<Grid item sm={3}>
71+
<GraphDirectionSelection direction={direction} onDirectionChange={this.onDirectionChange} />
72+
</Grid>
73+
<Grid item sm={3}>
74+
<GraphDownloadOptions svg={svg} />
75+
</Grid>
76+
</Grid>
10077

10178
{ svg && <div id="graph-output" ref="graph" dangerouslySetInnerHTML={{ __html: svg }} /> }
10279
</div>
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import Button from '@material-ui/core/Button';
4+
import MenuItem from '@material-ui/core/MenuItem';
5+
import Menu from '@material-ui/core/Menu';
6+
import { ArrowDropDown } from '@material-ui/icons';
7+
8+
class GraphDownloadOptions extends Component {
9+
state = {
10+
anchorEl: null,
11+
};
12+
13+
handleClick = event => {
14+
this.setState({ anchorEl: event.currentTarget });
15+
};
16+
17+
handleClose = () => {
18+
this.setState({ anchorEl: null });
19+
};
20+
21+
downloadPng = () => {
22+
const canvas = document.createElement('canvas');
23+
window.canvg(canvas, this.props.svg);
24+
25+
const link = document.createElement('a');
26+
link.download = 'state-chart.png';
27+
link.href = canvas.toDataURL();
28+
link.click();
29+
};
30+
31+
downloadSvg = () => {
32+
const link = document.createElement('a');
33+
link.download = 'state-chart.svg';
34+
link.href = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(this.props.svg);
35+
link.click();
36+
}
37+
38+
render() {
39+
const { anchorEl } = this.state;
40+
const { svg } = this.props;
41+
42+
return (
43+
<div>
44+
<Button
45+
variant="contained"
46+
aria-owns={anchorEl ? 'simple-menu' : undefined}
47+
aria-haspopup="true"
48+
onClick={this.handleClick}
49+
disabled={!!!svg}
50+
>
51+
Download <ArrowDropDown />
52+
</Button>
53+
<Menu
54+
id="simple-menu"
55+
anchorEl={anchorEl}
56+
open={Boolean(anchorEl)}
57+
disableAutoFocusItem={true}
58+
onClose={this.handleClose}
59+
>
60+
<MenuItem onClick={this.downloadPng}>As PNG</MenuItem>
61+
<MenuItem onClick={this.downloadSvg}>As SVG</MenuItem>
62+
</Menu>
63+
</div>
64+
);
65+
}
66+
}
67+
68+
GraphDownloadOptions.propTypes = {
69+
svg : PropTypes.string.isRequired,
70+
};
71+
72+
export default GraphDownloadOptions;

‎src/MachineInfoDisplay.js ‎src/machineInfo/MachineInfoDisplay.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { Component, Fragment } from 'react';
1+
import React, { Component } from 'react';
22
import PropTypes from 'prop-types';
33
import GraphDisplay from './GraphDisplay';
44
import machineValidator from '@cloudseam/machine-validator';
File renamed without changes.

‎yarn.lock

+7
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,13 @@
832832
recompose "0.28.0 - 0.30.0"
833833
warning "^4.0.1"
834834

835+
"@material-ui/icons@^3.0.2":
836+
version "3.0.2"
837+
resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-3.0.2.tgz#d67a6dd1ec8312d3a88ec97944a63daeef24fe10"
838+
dependencies:
839+
"@babel/runtime" "^7.2.0"
840+
recompose "0.28.0 - 0.30.0"
841+
835842
"@material-ui/system@^3.0.0-alpha.0":
836843
version "3.0.0-alpha.2"
837844
resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-3.0.0-alpha.2.tgz#096e80c8bb0f70aea435b9e38ea7749ee77b4e46"

0 commit comments

Comments
 (0)
Please sign in to comment.