Add editor drag mode for popping sprites of stage.

Also integrate the "ignore draggability, always drag" behavior of editor
mode.

Right now, editor drag mode is hooked up to the "isFullscreen" flag,
since it is the closest thing we have to player mode now.
This commit is contained in:
Paul Kaplan committed 2018-04-12 11:46:25 -04:00
1 parent 7eb6e32778
commit cb960e5a28
3 files changed
+102 -13

No files matched your search

+12 -4
View File
@@ -8,6 +8,10 @@
*/
display: block;
/* Attach border radius directly to canvas to prevent needing overflow:hidden; */
border-radius: $space;
border: 1px solid $ui-black-transparent;
/* @todo: This is for overriding the value being set somewhere. Where is it being set? */
background-color: transparent;
}
@@ -30,10 +34,6 @@
.stage-wrapper {
position: relative;
border-radius: $space;
border: 1px solid $ui-black-transparent;
/* Keep the canvas inside the border radius */
overflow: hidden;
}
.stage-wrapper-overlay {
@@ -78,3 +78,11 @@
pointer-events: none;
overflow: hidden;
}
.dragging-sprite {
position: absolute;
top: 0;
left: 0;
z-index: 1000; /* Above everything so it is draggable into other panes */
filter: drop-shadow(5px 5px 5px $ui-black-transparent);
}
+10 -1
View File
@@ -12,6 +12,7 @@ import styles from './stage.css';
const StageComponent = props => {
const {
canvasRef,
dragRef,
height,
isColorPicking,
isFullScreen,
@@ -24,7 +25,7 @@ const StageComponent = props => {
} = props;
const stageSize = getStageSize(isFullScreen, height, width);
return (
<div>
<Box
@@ -71,6 +72,12 @@ const StageComponent = props => {
</div>
</div>
)}
<canvas
className={styles.draggingSprite}
height={0}
ref={dragRef}
width={0}
/>
</Box>
{isColorPicking ? (
<Box
@@ -84,6 +91,7 @@ const StageComponent = props => {
StageComponent.propTypes = {
canvasRef: PropTypes.func,
colorInfo: Loupe.propTypes.colorInfo,
dragRef: PropTypes.func,
height: PropTypes.number,
isColorPicking: PropTypes.bool,
isFullScreen: PropTypes.bool.isRequired,
@@ -94,6 +102,7 @@ StageComponent.propTypes = {
};
StageComponent.defaultProps = {
canvasRef: () => {},
dragRef: () => {},
width: 480,
height: 360
};
+80 -8
View File
@@ -34,7 +34,11 @@ class Stage extends React.Component {
'onWheel',
'updateRect',
'questionListener',
'setCanvas'
'setCanvas',
'setDragCanvas',
'clearDragCanvas',
'drawDragCanvas',
'positionDragCanvas'
]);
this.state = {
mouseDownTimeoutId: null,
@@ -170,6 +174,7 @@ class Stage extends React.Component {
y: -(spritePosition[1] + this.state.dragOffset[1]),
force: true
});
this.positionDragCanvas(mousePosition[0], mousePosition[1]);
}
const coordinates = {
x: mousePosition[0],
@@ -248,11 +253,47 @@ class Stage extends React.Component {
}
this.setState({mouseDownTimeoutId: null});
}
drawDragCanvas (drawableData) {
const {
data,
width,
height,
x,
y
} = drawableData;
this.dragCanvas.width = width;
this.dragCanvas.height = height;
// Need to convert uint8array from WebGL readPixels into Uint8ClampedArray
// for ImageData constructor. Shares underlying buffer, so it is fast.
const imageData = new ImageData(
new Uint8ClampedArray(data.buffer), width, height);
this.dragCanvas.getContext('2d').putImageData(imageData, 0, 0);
// Position so that pick location is at (0, 0) so that positionDragCanvas()
// can use translation to move to mouse position smoothly.
this.dragCanvas.style.left = `${-x}px`;
this.dragCanvas.style.top = `${-y}px`;
}
clearDragCanvas () {
this.dragCanvas.width = this.dragCanvas.height = 0;
}
positionDragCanvas (mouseX, mouseY) {
// mouseX/Y are relative to stage top/left, and dragCanvas is already
// positioned so that the pick location is at (0,0).
this.dragCanvas.style.transform = `translate(${mouseX}px, ${mouseY}px)`;
}
onStartDrag (x, y) {
if (this.state.dragId) return;
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);
// Only start drags on non-draggable targets in editor drag mode
if (!this.props.useEditorDragStyle) {
const target = this.props.vm.runtime.getTargetById(targetId);
if (!target.draggable) return;
}
if (targetId === null) return;
this.props.vm.startDrag(targetId);
this.setState({
@@ -260,18 +301,41 @@ class Stage extends React.Component {
dragId: targetId,
dragOffset: drawableData.scratchOffset
});
if (this.props.useEditorDragStyle) {
this.drawDragCanvas(drawableData);
this.positionDragCanvas(x, y);
this.props.vm.postSpriteInfo({visible: false});
}
}
onStopDrag () {
this.props.vm.stopDrag(this.state.dragId);
this.setState({
isDragging: false,
dragOffset: null,
dragId: null
});
const dragId = this.state.dragId;
const commonStopDragActions = () => {
this.props.vm.stopDrag(dragId);
this.setState({
isDragging: false,
dragOffset: null,
dragId: null
});
};
if (this.props.useEditorDragStyle) {
// Need to sequence these actions to prevent flickering.
this.props.vm.postSpriteInfo({visible: true});
setTimeout(() => {
this.clearDragCanvas();
setTimeout(() => {
commonStopDragActions();
}, 30);
}, 30);
} else {
commonStopDragActions();
}
}
setCanvas (canvas) {
this.canvas = canvas;
}
setDragCanvas (canvas) {
this.dragCanvas = canvas;
}
render () {
const {
vm, // eslint-disable-line no-unused-vars
@@ -282,6 +346,7 @@ class Stage extends React.Component {
<StageComponent
canvasRef={this.setCanvas}
colorInfo={this.state.colorInfo}
dragRef={this.setDragCanvas}
question={this.state.question}
onDoubleClick={this.handleDoubleClick}
onQuestionAnswered={this.handleQuestionAnswered}
@@ -297,13 +362,20 @@ Stage.propTypes = {
isFullScreen: PropTypes.bool.isRequired,
onActivateColorPicker: PropTypes.func,
onDeactivateColorPicker: PropTypes.func,
useEditorDragStyle: PropTypes.bool,
vm: PropTypes.instanceOf(VM).isRequired,
width: PropTypes.number
};
Stage.defaultProps = {
useEditorDragStyle: true
};
const mapStateToProps = state => ({
isColorPicking: state.colorPicker.active,
isFullScreen: state.stageSize.isFullScreen
isFullScreen: state.stageSize.isFullScreen,
// Do not use editor drag style in fullscreen mode.
useEditorDragStyle: !state.stageSize.isFullScreen
});
const mapDispatchToProps = dispatch => ({