187 lines
5.9 KiB
React
187 lines
5.9 KiB
React
const bindAll = require('lodash.bindall');
|
|
const React = require('react');
|
|
const Renderer = require('scratch-render');
|
|
const AudioEngine = require('scratch-audio');
|
|
const VM = require('scratch-vm');
|
|
|
|
const StageComponent = require('../components/stage/stage.jsx');
|
|
|
|
class Stage extends React.Component {
|
|
constructor (props) {
|
|
super(props);
|
|
bindAll(this, [
|
|
'attachMouseEvents',
|
|
'cancelMouseDownTimeout',
|
|
'detachMouseEvents',
|
|
'onMouseUp',
|
|
'onMouseMove',
|
|
'onMouseDown',
|
|
'onStartDrag',
|
|
'onStopDrag',
|
|
'updateRect',
|
|
'setCanvas'
|
|
]);
|
|
this.state = {
|
|
mouseDownTimeoutId: null,
|
|
mouseDownPosition: null,
|
|
isDragging: false,
|
|
dragOffset: null,
|
|
dragId: null
|
|
};
|
|
}
|
|
componentDidMount () {
|
|
this.attachRectEvents();
|
|
this.attachMouseEvents(this.canvas);
|
|
this.updateRect();
|
|
this.renderer = new Renderer(this.canvas);
|
|
this.props.vm.attachRenderer(this.renderer);
|
|
this.audioEngine = new AudioEngine();
|
|
this.props.vm.attachAudioEngine(this.audioEngine);
|
|
}
|
|
shouldComponentUpdate () {
|
|
return false;
|
|
}
|
|
componentWillUnmount () {
|
|
this.detachMouseEvents(this.canvas);
|
|
this.detachRectEvents();
|
|
}
|
|
attachMouseEvents (canvas) {
|
|
document.addEventListener('mousemove', this.onMouseMove);
|
|
document.addEventListener('mouseup', this.onMouseUp);
|
|
canvas.addEventListener('mousedown', this.onMouseDown);
|
|
}
|
|
detachMouseEvents (canvas) {
|
|
document.removeEventListener('mousemove', this.onMouseMove);
|
|
document.removeEventListener('mouseup', this.onMouseUp);
|
|
canvas.removeEventListener('mousedown', this.onMouseDown);
|
|
}
|
|
attachRectEvents () {
|
|
window.addEventListener('resize', this.updateRect);
|
|
window.addEventListener('scroll', this.updateRect);
|
|
}
|
|
detachRectEvents () {
|
|
window.removeEventListener('resize', this.updateRect);
|
|
window.removeEventListener('scroll', this.updateRect);
|
|
}
|
|
updateRect () {
|
|
this.rect = this.canvas.getBoundingClientRect();
|
|
}
|
|
getScratchCoords (x, y) {
|
|
return [
|
|
x - (this.rect.width / 2),
|
|
y - (this.rect.height / 2)
|
|
];
|
|
}
|
|
onMouseMove (e) {
|
|
const mousePosition = [e.clientX - this.rect.left, e.clientY - this.rect.top];
|
|
if (this.state.mouseDownTimeoutId !== null) {
|
|
this.cancelMouseDownTimeout();
|
|
if (this.state.mouseDown && !this.state.isDragging) {
|
|
this.onStartDrag(...this.state.mouseDownPosition);
|
|
}
|
|
}
|
|
if (this.state.mouseDown && this.state.isDragging) {
|
|
const spritePosition = this.getScratchCoords(mousePosition[0], mousePosition[1]);
|
|
this.props.vm.postSpriteInfo({
|
|
x: spritePosition[0] + this.state.dragOffset[0],
|
|
y: -(spritePosition[1] + this.state.dragOffset[1]),
|
|
force: true
|
|
});
|
|
}
|
|
const coordinates = {
|
|
x: mousePosition[0],
|
|
y: mousePosition[1],
|
|
canvasWidth: this.rect.width,
|
|
canvasHeight: this.rect.height
|
|
};
|
|
this.props.vm.postIOData('mouse', coordinates);
|
|
}
|
|
onMouseUp (e) {
|
|
this.cancelMouseDownTimeout();
|
|
this.setState({
|
|
mouseDown: false,
|
|
mouseDownPosition: null,
|
|
});
|
|
if (this.state.isDragging) {
|
|
this.onStopDrag();
|
|
} else {
|
|
const data = {
|
|
isDown: false,
|
|
x: e.clientX - this.rect.left,
|
|
y: e.clientY - this.rect.top,
|
|
canvasWidth: this.rect.width,
|
|
canvasHeight: this.rect.height
|
|
};
|
|
this.props.vm.postIOData('mouse', data);
|
|
}
|
|
}
|
|
onMouseDown (e) {
|
|
const mousePosition = [e.clientX - this.rect.left, e.clientY - this.rect.top];
|
|
this.setState({
|
|
mouseDown: true,
|
|
mouseDownPosition: mousePosition,
|
|
mouseDownTimeoutId: setTimeout(
|
|
this.onStartDrag.bind(this, mousePosition[0], mousePosition[1]),
|
|
500
|
|
)
|
|
});
|
|
const data = {
|
|
isDown: true,
|
|
x: mousePosition[0],
|
|
y: mousePosition[1],
|
|
canvasWidth: this.rect.width,
|
|
canvasHeight: this.rect.height
|
|
};
|
|
this.props.vm.postIOData('mouse', data);
|
|
e.preventDefault();
|
|
}
|
|
cancelMouseDownTimeout () {
|
|
if (this.state.mouseDownTimeoutId !== null) {
|
|
clearTimeout(this.state.mouseDownTimeoutId);
|
|
}
|
|
this.setState({mouseDownTimeoutId: null});
|
|
}
|
|
onStartDrag (x, y) {
|
|
const drawableId = this.renderer.pick(x, y);
|
|
if (drawableId === null) return;
|
|
const drawableData = this.renderer.extractDrawable(drawableId, x, y);
|
|
const targetId = this.props.vm.getTargetIdForDrawableId(drawableId);
|
|
if (targetId === null) return;
|
|
this.props.vm.startDrag(targetId);
|
|
this.setState({
|
|
isDragging: true,
|
|
dragId: targetId,
|
|
dragOffset: drawableData.scratchOffset
|
|
});
|
|
}
|
|
onStopDrag () {
|
|
this.props.vm.stopDrag(this.state.dragId);
|
|
this.setState({
|
|
isDragging: false,
|
|
dragOffset: null,
|
|
dragId: null
|
|
});
|
|
}
|
|
setCanvas (canvas) {
|
|
this.canvas = canvas;
|
|
}
|
|
render () {
|
|
const {
|
|
vm, // eslint-disable-line no-unused-vars
|
|
...props
|
|
} = this.props;
|
|
return (
|
|
<StageComponent
|
|
canvasRef={this.setCanvas}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
}
|
|
|
|
Stage.propTypes = {
|
|
vm: React.PropTypes.instanceOf(VM).isRequired
|
|
};
|
|
|
|
module.exports = Stage;
|