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:
1 parent
7eb6e32778
commit
cb960e5a28
3 files changed
+102
-13
No files matched your search
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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 => ({
|
||||
|
||||
Reference in new issue
Block a user