Doodle3D-Core/src/components/App.js

274 lines
7.0 KiB
JavaScript
Raw Normal View History

2017-11-15 00:46:02 +01:00
import React from 'react';
import PropTypes from 'proptypes';
import injectSheet from 'react-jss';
import { connect } from 'react-redux';
2017-11-23 15:56:04 +01:00
import * as actions from '../actions/index.js';
2017-11-15 00:46:02 +01:00
import Logo from './Logo.js';
import D2Panel from './D2Panel.js';
import D3Panel from './D3Panel.js';
import SketcherToolbars from './SketcherToolbars.js';
2017-11-15 15:13:49 +01:00
import Button from './Button.js';
import vlineImageURL from '../../img/vline.png';
import btnUndoImageURL from '../../img/mainmenu/btnUndo.png';
import btnRedoImageURL from '../../img/mainmenu/btnRedo.png';
import InlineIconsLoader from './InlineIconsLoader.js';
2017-11-23 16:07:54 +01:00
import JSONToSketchData from '../shape/JSONToSketchData.js';
2017-12-14 10:59:06 +01:00
import keycode from 'keycode';
import bowser from 'bowser';
import * as d2Tools from '../constants/d2Tools.js';
2018-02-21 11:54:25 +01:00
import { isLoaded, load } from '../utils/loaded.js';
2021-05-20 04:16:53 +02:00
import { setConfig } from '@doodle3d/touch-events';
2018-04-24 16:01:42 +02:00
setConfig({ DRAG_THRESHOLD: 0 });
2017-11-15 00:46:02 +01:00
const styles = {
container: {
2017-11-15 15:13:49 +01:00
position: 'relative',
userSelect: 'none',
2017-11-15 00:46:02 +01:00
display: 'flex',
flexDirection: 'column',
alignItems: 'stretch',
height: '100%'
},
appContainer: {
flexGrow: 1,
display: 'flex',
alignItems: 'stretch',
overflow: 'hidden'
},
vLine: {
backgroundSize: '14px auto',
backgroundImage: `url('${vlineImageURL}')`,
width: '28px'
},
undoMenu: {
display: 'flex',
position: 'absolute',
top: 0,
left: '50%',
marginLeft: '-68px'
},
undo: {
cursor: 'pointer',
backgroundSize: '68px auto',
width: '68px',
height: '58px',
backgroundImage: `url('${btnUndoImageURL}')`
},
redo: {
cursor: 'pointer',
backgroundSize: '71px auto',
width: '71px',
height: '58px',
backgroundImage: `url('${btnRedoImageURL}')`
}
};
class App extends React.Component {
static propTypes = {
2017-11-23 15:56:04 +01:00
openSketch: PropTypes.func.isRequired,
addImage: PropTypes.func.isRequired,
2017-11-15 00:46:02 +01:00
undo: PropTypes.func.isRequired,
redo: PropTypes.func.isRequired,
2017-12-14 10:59:06 +01:00
classes: PropTypes.objectOf(PropTypes.string),
deleteSelection: PropTypes.func.isRequired,
selectAll: PropTypes.func.isRequired,
d2ChangeTool: PropTypes.func.isRequired,
moveSelection: PropTypes.func.isRequired,
2018-05-09 10:50:18 +02:00
selectedPen: PropTypes.string.isRequired,
preventScroll: PropTypes.bool.isRequired
2017-11-15 00:46:02 +01:00
};
2021-05-19 19:14:32 +02:00
constructor(props) {
super(props);
this.container = React.createRef();
}
2018-02-21 11:54:25 +01:00
state = {
loaded: isLoaded()
};
2017-11-23 15:56:04 +01:00
componentDidMount() {
2018-02-21 11:54:25 +01:00
if (!this.state.loaded) load.then(() => this.setState({ loaded: true }));
2021-05-19 19:14:32 +02:00
if (this.container.current) {
this.container.current.addEventListener('dragover', this.dragOver);
this.container.current.addEventListener('drop', this.onDrop);
this.container.current.addEventListener('wheel', this.onWheel);
window.addEventListener('keydown', this.onKeyDown);
}
2017-12-14 10:59:06 +01:00
}
componentWillUnmount() {
2021-05-19 19:14:32 +02:00
if (this.container.current) {
this.container.current.addEventListener('dragover', this.dragOver);
this.container.current.removeEventListener('drop', this.onDrop);
this.container.current.addEventListener('wheel', this.onWheel);
window.removeEventListener('keydown', this.onKeyDown);
}
2017-11-23 15:56:04 +01:00
}
2018-06-21 16:10:27 +02:00
dragOver = event => {
event.preventDefault();
};
2017-11-23 15:56:04 +01:00
onDrop = async event => {
const { openSketch, addImage } = this.props;
event.preventDefault();
for (const file of event.dataTransfer.files) {
2017-12-13 17:25:42 +01:00
const extentions = file.name.split('.').pop();
2017-11-23 15:56:04 +01:00
2017-12-13 17:25:42 +01:00
switch (extentions.toUpperCase()) {
2018-06-21 16:10:13 +02:00
case 'DOODLE3D':
2017-11-23 15:56:04 +01:00
case 'D3SKETCH':
case 'JSON':
const url = URL.createObjectURL(file);
const json = await fetch(url).then(result => result.json());
const data = await JSONToSketchData(json);
openSketch({ data });
2017-11-23 15:56:04 +01:00
break;
case 'JPG':
case 'JPEG':
case 'PNG':
case 'GIF':
await addImage(file);
break;
default:
break;
}
}
};
2017-12-14 10:59:06 +01:00
onKeyDown = (event) => {
const { undo, redo, deleteSelection, selectAll, d2ChangeTool, moveSelection, selectedPen } = this.props;
const { metaKey, ctrlKey, shiftKey } = event;
const key = keycode(event);
const commandKey = bowser.mac ? metaKey : ctrlKey;
const targetTag = event.target.tagName.toLowerCase();
if (targetTag === 'input' || targetTag === 'textarea') return;
switch (key) {
case 'backspace':
case 'delete':
event.preventDefault();
deleteSelection();
break;
case 'a':
if (commandKey) selectAll();
break;
case 'z':
if (commandKey) {
if (shiftKey) {
redo();
} else {
undo();
}
}
break;
2018-03-19 00:22:16 +01:00
case 's': {
if (!commandKey) d2ChangeTool(d2Tools.TRANSFORM);
break;
}
case 'e': {
if (!commandKey) {
event.preventDefault();
d2ChangeTool(d2Tools.ERASER);
}
break;
}
case 'c': {
if (!commandKey) d2ChangeTool(d2Tools.CIRCLE);
break;
}
case 'l': {
if (!commandKey) d2ChangeTool(d2Tools.POLYGON);
break;
}
2017-12-14 10:59:06 +01:00
case 't': {
if (!commandKey) d2ChangeTool(d2Tools.TEXT);
break;
}
case 'b': {
if (!commandKey) d2ChangeTool(selectedPen);
break;
}
case 'left':
case 'right':
case 'up':
case 'down': {
const delta = shiftKey ? 10 : 1;
const deltas = {
left: { deltaX: -delta, deltaY: 0 },
right: { deltaX: delta, deltaY: 0 },
up: { deltaX: 0, deltaY: -delta },
down: { deltaX: 0, deltaY: delta }
};
const { deltaX, deltaY } = deltas[key];
moveSelection(deltaX, deltaY);
}
default:
break;
}
2017-11-23 15:56:04 +01:00
}
2018-05-09 10:50:18 +02:00
onWheel = (event) => {
const { preventScroll } = this.props;
if (preventScroll) event.preventDefault();
};
dragover = (event) => {
event.preventDefault();
};
2017-11-15 00:46:02 +01:00
render() {
const { classes, undo, redo } = this.props;
2018-02-21 11:54:25 +01:00
const { loaded } = this.state;
2017-11-15 00:46:02 +01:00
return (
2021-05-19 19:14:32 +02:00
<div ref={this.container} className={classes.container}>
<InlineIconsLoader />
2018-02-21 11:54:25 +01:00
{loaded && <div className={classes.appContainer}>
2017-11-15 00:46:02 +01:00
<D2Panel />
<div className={classes.vLine} />
<D3Panel />
2018-02-21 11:54:25 +01:00
</div>}
2017-11-15 00:46:02 +01:00
<Logo />
<div className={classes.undoMenu}>
2017-11-15 15:13:49 +01:00
<Button onSelect={undo} className={classes.undo} />
<Button onSelect={redo} className={classes.redo} />
2017-11-15 00:46:02 +01:00
</div>
2017-11-15 15:13:49 +01:00
<SketcherToolbars />
2017-11-15 00:46:02 +01:00
</div>
);
}
}
2017-12-14 10:59:06 +01:00
export default injectSheet(styles)(connect(state => ({
2018-05-09 10:50:18 +02:00
preventScroll: state.sketcher.present.preventScroll,
2017-12-14 10:59:06 +01:00
selectedPen: state.sketcher.present.menus['pen-tools'].selected
}), {
2017-11-15 00:46:02 +01:00
undo: actions.undo.undo,
2017-11-23 15:56:04 +01:00
redo: actions.undo.redo,
openSketch: actions.openSketch,
2017-12-14 10:59:06 +01:00
addImage: actions.addImage,
deleteSelection: actions.deleteSelection,
selectAll: actions.selectAll,
d2ChangeTool: actions.d2ChangeTool,
moveSelection: actions.moveSelection
2017-11-15 00:46:02 +01:00
})(App));