give movement controls transition animations

This commit is contained in:
HF 2024-01-24 02:51:43 +01:00
parent ad200cfcad
commit 2457382052
5 changed files with 101 additions and 88 deletions

View File

@ -39,7 +39,7 @@ persistStore(store, {}, () => {
window.imMobile = function checkMobile() { window.imMobile = function checkMobile() {
delete window.imMobile; delete window.imMobile;
store.dispatch(setMobile(true)); store.dispatch(setMobile(true));
} };
document.addEventListener('touchstart', window.imMobile, { once: true }); document.addEventListener('touchstart', window.imMobile, { once: true });
// listen for resize // listen for resize

View File

@ -20,22 +20,16 @@ const UI = () => {
isHistoricalView, isHistoricalView,
is3D, is3D,
isOnMobile, isOnMobile,
showMvmCtrls,
holdPaint,
] = useSelector((state) => [ ] = useSelector((state) => [
state.canvas.isHistoricalView, state.canvas.isHistoricalView,
state.canvas.is3D, state.canvas.is3D,
state.user.isOnMobile, state.user.isOnMobile,
state.gui.showMvmCtrls,
state.gui.holdPaint,
], shallowEqual); ], shallowEqual);
return ( return (
<> <>
<Alert /> <Alert />
{(showMvmCtrls <MovementControls />
|| (isOnMobile && (is3D || (holdPaint > 0) && !isHistoricalView))
) && <MovementControls />}
{(isHistoricalView) ? ( {(isHistoricalView) ? (
<HistorySelect /> <HistorySelect />
) : ( ) : (

View File

@ -3,13 +3,8 @@
* Menu for WASD keys for mobile users * Menu for WASD keys for mobile users
*/ */
import React, { import React, { useState, useCallback, useEffect } from 'react';
useCallback, import { useSelector, useDispatch, shallowEqual } from 'react-redux';
} from 'react';
import {
useSelector,
useDispatch,
} from 'react-redux';
import { import {
PiMagnifyingGlassMinus, PiMagnifyingGlassMinus,
PiMagnifyingGlassPlus, PiMagnifyingGlassPlus,
@ -22,96 +17,103 @@ import {
} from 'react-icons/pi'; } from 'react-icons/pi';
import { import {
setMoveU, setMoveU, setMoveV, setMoveW, cancelMove,
setMoveV,
setMoveW,
cancelMove,
} from '../../store/actions'; } from '../../store/actions';
import { selectMovementControlProps } from '../../store/selectors/gui';
const btnStyle = {
// fontSize: 34,
};
const MovementControls = () => { const MovementControls = () => {
const is3D = useSelector((state) => state.canvas.is3D); const [render, setRender] = useState(false);
const [is3D, open] = useSelector(
selectMovementControlProps,
shallowEqual,
);
const dispatch = useDispatch(); const dispatch = useDispatch();
const onPressStart = useCallback((event) => { useEffect(() => {
event.preventDefault(); if (open) window.setTimeout(() => setRender(true), 10);
switch (event.currentTarget.id) { }, [open]);
case 'forwardbtn':
dispatch(setMoveV(-1));
break;
case 'backwardbtn':
dispatch(setMoveV(1));
break;
case 'leftbtn':
dispatch(setMoveU(-1));
break;
case 'rightbtn':
dispatch(setMoveU(1));
break;
case 'upbtn':
dispatch(setMoveW(-1));
break;
case 'downbtn':
dispatch(setMoveW(1));
break;
default:
}
}, [dispatch]);
const onPressStop = useCallback((event) => {
event.preventDefault();
switch (event.currentTarget.id) {
case 'forwardbtn':
dispatch(setMoveV(0));
break;
case 'backwardbtn':
dispatch(setMoveV(0));
break;
case 'leftbtn':
dispatch(setMoveU(0));
break;
case 'rightbtn':
dispatch(setMoveU(0));
break;
case 'upbtn':
dispatch(setMoveW(0));
break;
case 'downbtn':
dispatch(setMoveW(0));
break;
default:
}
}, [dispatch]);
const onCancel = useCallback((event) => {
event.preventDefault();
dispatch(cancelMove());
}, [dispatch]);
const refCallBack = useCallback((node) => { const refCallBack = useCallback((node) => {
if (!node) { if (!node) {
return; return;
} }
const onPressStart = (event) => {
event.preventDefault();
switch (event.currentTarget.id) {
case 'forwardbtn':
dispatch(setMoveV(-1));
break;
case 'backwardbtn':
dispatch(setMoveV(1));
break;
case 'leftbtn':
dispatch(setMoveU(-1));
break;
case 'rightbtn':
dispatch(setMoveU(1));
break;
case 'upbtn':
dispatch(setMoveW(-1));
break;
case 'downbtn':
dispatch(setMoveW(1));
break;
default:
}
};
const onPressStop = (event) => {
event.preventDefault();
switch (event.currentTarget.id) {
case 'forwardbtn':
dispatch(setMoveV(0));
break;
case 'backwardbtn':
dispatch(setMoveV(0));
break;
case 'leftbtn':
dispatch(setMoveU(0));
break;
case 'rightbtn':
dispatch(setMoveU(0));
break;
case 'upbtn':
dispatch(setMoveW(0));
break;
case 'downbtn':
dispatch(setMoveW(0));
break;
default:
}
};
const onCancel = (event) => {
event.preventDefault();
dispatch(cancelMove());
};
node.addEventListener('touchstart', onPressStart, { passive: false }); node.addEventListener('touchstart', onPressStart, { passive: false });
node.addEventListener('mousedown', onPressStart, { passive: false }); node.addEventListener('mousedown', onPressStart, { passive: false });
node.addEventListener('touchend', onPressStop, { passive: false }); node.addEventListener('touchend', onPressStop, { passive: false });
node.addEventListener('mouseup', onPressStop, { passive: false }); node.addEventListener('mouseup', onPressStop, { passive: false });
node.addEventListener('mouseleave', onCancel, { passive: false }); node.addEventListener('mouseleave', onCancel, { passive: false });
node.addEventListener('touchcancel', onCancel, { passive: false }); node.addEventListener('touchcancel', onCancel, { passive: false });
}, [onPressStart, onPressStop, onCancel]); }, [dispatch]);
return ( return ((render || open) && (
<> <div
id="mvmctrls"
className={render && open ? 'show' : ''}
onTransitionEnd={() => !open && setRender(false)}
>
<div <div
className="actionbuttons" className="actionbuttons"
id="forwardbtn" id="forwardbtn"
role="button" role="button"
key="forward"
tabIndex={0} tabIndex={0}
style={{ style={{
...btnStyle,
left: 57, left: 57,
bottom: 139, bottom: 139,
}} }}
@ -123,9 +125,9 @@ const MovementControls = () => {
className="actionbuttons" className="actionbuttons"
id="backwardbtn" id="backwardbtn"
role="button" role="button"
key="backward"
tabIndex={0} tabIndex={0}
style={{ style={{
...btnStyle,
left: 57, left: 57,
bottom: 98, bottom: 98,
}} }}
@ -137,9 +139,9 @@ const MovementControls = () => {
className="actionbuttons" className="actionbuttons"
id="leftbtn" id="leftbtn"
role="button" role="button"
key="left"
tabIndex={0} tabIndex={0}
style={{ style={{
...btnStyle,
left: 16, left: 16,
bottom: 98, bottom: 98,
}} }}
@ -151,9 +153,9 @@ const MovementControls = () => {
className="actionbuttons" className="actionbuttons"
id="rightbtn" id="rightbtn"
role="button" role="button"
key="right"
tabIndex={0} tabIndex={0}
style={{ style={{
...btnStyle,
left: 98, left: 98,
bottom: 98, bottom: 98,
}} }}
@ -165,6 +167,7 @@ const MovementControls = () => {
className="actionbuttons" className="actionbuttons"
id="upbtn" id="upbtn"
role="button" role="button"
key="up"
tabIndex={0} tabIndex={0}
style={{ style={{
left: 16, left: 16,
@ -178,6 +181,7 @@ const MovementControls = () => {
className="actionbuttons" className="actionbuttons"
id="downbtn" id="downbtn"
role="button" role="button"
key="down"
tabIndex={0} tabIndex={0}
style={{ style={{
left: 98, left: 98,
@ -187,8 +191,8 @@ const MovementControls = () => {
> >
{(is3D) ? <PiCaretDoubleDown /> : <PiMagnifyingGlassPlus />} {(is3D) ? <PiCaretDoubleDown /> : <PiMagnifyingGlassPlus />}
</div> </div>
</> </div>
); ));
}; };
export default MovementControls; export default MovementControls;

View File

@ -7,3 +7,10 @@
export const selectIsDarkMode = (state) => ( export const selectIsDarkMode = (state) => (
state.gui.style.indexOf('dark') !== -1 state.gui.style.indexOf('dark') !== -1
); );
export const selectMovementControlProps = (state) => [
state.canvas.is3D,
state.gui.showMvmCtrls || (state.user.isOnMobile
&& (state.canvas.is3D || (state.gui.holdPaint > 0)
&& !state.canvas.isHistoricalView)),
];

View File

@ -994,6 +994,14 @@ table td span {
background-color: #d2d2d2cc; background-color: #d2d2d2cc;
} }
#mvmctrls {
transition: opacity 0.25s ease;
opacity: 0;
}
#mvmctrls.show {
opacity: 1;
}
#palettebox { #palettebox {
z-index: 1; z-index: 1;
bottom: 59px; bottom: 59px;
@ -1024,7 +1032,7 @@ table td span {
} }
.modal.show, .Alert.show, .overlay.show, .window.show { .modal.show, .Alert.show, .overlay.show, .window.show {
opacity: 1; opacity: 1;
} }
.vemb { .vemb {