mirror of
https://github.com/stan-smith/FossFLOW.git
synced 2025-12-24 06:58:48 -05:00
feat: implements basic support for touch devices
This commit is contained in:
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import { Box, useTheme } from '@mui/material';
|
||||
import { useUiStateStore } from 'src/stores/uiStateStore';
|
||||
import { useSceneStore } from 'src/stores/sceneStore';
|
||||
import { SizeIndicator } from './SizeIndicator';
|
||||
import { LineItem } from './LineItem';
|
||||
|
||||
export const DebugUtils = () => {
|
||||
@@ -21,63 +20,45 @@ export const DebugUtils = () => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
pointerEvents: 'none'
|
||||
bgcolor: 'common.white',
|
||||
px: 2,
|
||||
py: 1
|
||||
}}
|
||||
>
|
||||
<SizeIndicator />
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
left: appPadding.x,
|
||||
bottom: appPadding.y,
|
||||
bgcolor: 'common.white',
|
||||
width: 350,
|
||||
borderRadius: 1,
|
||||
border: (theme) => {
|
||||
return `1px solid ${theme.palette.grey[400]}`;
|
||||
},
|
||||
px: 2,
|
||||
py: 1
|
||||
}}
|
||||
>
|
||||
<LineItem
|
||||
title="Mouse"
|
||||
value={`${uiState.mouse.position.tile.x}, ${uiState.mouse.position.tile.y}`}
|
||||
/>
|
||||
<LineItem
|
||||
title="Mouse down"
|
||||
value={
|
||||
uiState.mouse.mousedown
|
||||
? `${uiState.mouse.mousedown.tile.x}, ${uiState.mouse.mousedown.tile.y}`
|
||||
: 'null'
|
||||
}
|
||||
/>
|
||||
<LineItem
|
||||
title="Mouse delta"
|
||||
value={
|
||||
uiState.mouse.delta
|
||||
? `${uiState.mouse.delta.tile.x}, ${uiState.mouse.delta.tile.y}`
|
||||
: 'null'
|
||||
}
|
||||
/>
|
||||
<LineItem
|
||||
title="Scroll"
|
||||
value={`${uiState.scroll.position.x}, ${uiState.scroll.position.y}`}
|
||||
/>
|
||||
<LineItem title="Zoom" value={uiState.zoom} />
|
||||
<LineItem
|
||||
title="Size"
|
||||
value={`${uiState.rendererSize.width}, ${uiState.rendererSize.height}`}
|
||||
/>
|
||||
<LineItem title="Scene info" value={`${scene.nodes.length} nodes`} />
|
||||
<LineItem title="Mode" value={uiState.mode.type} />
|
||||
<LineItem title="Mode data" value={JSON.stringify(uiState.mode)} />
|
||||
</Box>
|
||||
<LineItem
|
||||
title="Mouse"
|
||||
value={`${uiState.mouse.position.tile.x}, ${uiState.mouse.position.tile.y}`}
|
||||
/>
|
||||
<LineItem
|
||||
title="Mouse down"
|
||||
value={
|
||||
uiState.mouse.mousedown
|
||||
? `${uiState.mouse.mousedown.tile.x}, ${uiState.mouse.mousedown.tile.y}`
|
||||
: 'null'
|
||||
}
|
||||
/>
|
||||
<LineItem
|
||||
title="Mouse delta"
|
||||
value={
|
||||
uiState.mouse.delta
|
||||
? `${uiState.mouse.delta.tile.x}, ${uiState.mouse.delta.tile.y}`
|
||||
: 'null'
|
||||
}
|
||||
/>
|
||||
<LineItem
|
||||
title="Scroll"
|
||||
value={`${uiState.scroll.position.x}, ${uiState.scroll.position.y}`}
|
||||
/>
|
||||
<LineItem title="Zoom" value={uiState.zoom} />
|
||||
<LineItem
|
||||
title="Size"
|
||||
value={`${uiState.rendererSize.width}, ${uiState.rendererSize.height}`}
|
||||
/>
|
||||
<LineItem title="Scene info" value={`${scene.nodes.length} nodes`} />
|
||||
<LineItem title="Mode" value={uiState.mode.type} />
|
||||
<LineItem title="Mode data" value={JSON.stringify(uiState.mode)} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Rectangles } from 'src/components/SceneLayers/Rectangles/Rectangles';
|
||||
import { Connectors } from 'src/components/SceneLayers/Connectors/Connectors';
|
||||
import { ConnectorLabels } from 'src/components/SceneLayers/ConnectorLabels/ConnectorLabels';
|
||||
import { TextBoxes } from 'src/components/SceneLayers/TextBoxes/TextBoxes';
|
||||
import { DebugUtils } from 'src/components/DebugUtils/DebugUtils';
|
||||
import { SizeIndicator } from 'src/components/DebugUtils/SizeIndicator';
|
||||
import { useResizeObserver } from 'src/hooks/useResizeObserver';
|
||||
import { SceneLayer } from 'src/components/SceneLayer/SceneLayer';
|
||||
import { TransformControlsManager } from 'src/components/TransformControlsManager/TransformControlsManager';
|
||||
@@ -82,7 +82,7 @@ export const Renderer = () => {
|
||||
</SceneLayer>
|
||||
{debugMode && (
|
||||
<SceneLayer>
|
||||
<DebugUtils />
|
||||
<SizeIndicator />
|
||||
</SceneLayer>
|
||||
)}
|
||||
<SceneLayer>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useUiStateStore } from 'src/stores/uiStateStore';
|
||||
import { MainMenu } from 'src/components/MainMenu/MainMenu';
|
||||
import { ZoomControls } from 'src/components/ZoomControls/ZoomControls';
|
||||
import { useSceneStore } from 'src/stores/sceneStore';
|
||||
import { DebugUtils } from 'src/components/DebugUtils/DebugUtils';
|
||||
|
||||
export const UiOverlay = () => {
|
||||
const theme = useTheme();
|
||||
@@ -23,6 +24,9 @@ export const UiOverlay = () => {
|
||||
const disableInteractions = useUiStateStore((state) => {
|
||||
return state.disableInteractions;
|
||||
});
|
||||
const debugMode = useUiStateStore((state) => {
|
||||
return state.debugMode;
|
||||
});
|
||||
const mode = useUiStateStore((state) => {
|
||||
return state.mode;
|
||||
});
|
||||
@@ -114,6 +118,21 @@ export const UiOverlay = () => {
|
||||
{sceneTitle}
|
||||
</Typography>
|
||||
</UiElement>
|
||||
|
||||
{debugMode && (
|
||||
<UiElement
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
width: 350,
|
||||
height: 400,
|
||||
maxWidth: '100%',
|
||||
left: appPadding.x,
|
||||
bottom: appPadding.y * 2 + spacing(2)
|
||||
}}
|
||||
>
|
||||
<DebugUtils />
|
||||
</UiElement>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@200;600&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<title>Development | Isoflow</title>
|
||||
</head>
|
||||
<style>
|
||||
body {
|
||||
overscroll-behavior: none;
|
||||
position: fixed;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useSceneStore } from 'src/stores/sceneStore';
|
||||
import { useUiStateStore } from 'src/stores/uiStateStore';
|
||||
import { ModeActions, State } from 'src/types';
|
||||
import { ModeActions, State, SlimMouseEvent } from 'src/types';
|
||||
import { getMouse } from 'src/utils';
|
||||
import { Cursor } from './modes/Cursor';
|
||||
import { DragItems } from './modes/DragItems';
|
||||
@@ -35,20 +35,17 @@ export const useInteractionManager = () => {
|
||||
});
|
||||
|
||||
const onMouseEvent = useCallback(
|
||||
(e: MouseEvent | TouchEvent) => {
|
||||
(e: SlimMouseEvent) => {
|
||||
if (!rendererRef.current || uiState.disableInteractions) return;
|
||||
|
||||
const mode = modes[uiState.mode.type];
|
||||
|
||||
const getModeFunction = () => {
|
||||
switch (e.type) {
|
||||
case 'touchmove':
|
||||
case 'mousemove':
|
||||
return mode.mousemove;
|
||||
case 'touchstart':
|
||||
case 'mousedown':
|
||||
return mode.mousedown;
|
||||
case 'touchend':
|
||||
case 'mouseup':
|
||||
return mode.mouseup;
|
||||
default:
|
||||
@@ -101,16 +98,49 @@ export const useInteractionManager = () => {
|
||||
useEffect(() => {
|
||||
const el = window;
|
||||
|
||||
const onTouchStart = (e: TouchEvent) => {
|
||||
onMouseEvent({
|
||||
...e,
|
||||
clientX: e.touches[0].clientX,
|
||||
clientY: e.touches[0].clientY,
|
||||
type: 'mousedown'
|
||||
});
|
||||
};
|
||||
|
||||
const onTouchMove = (e: TouchEvent) => {
|
||||
onMouseEvent({
|
||||
...e,
|
||||
clientX: e.touches[0].clientX,
|
||||
clientY: e.touches[0].clientY,
|
||||
type: 'mousemove'
|
||||
});
|
||||
};
|
||||
|
||||
const onTouchEnd = (e: TouchEvent) => {
|
||||
onMouseEvent({
|
||||
...e,
|
||||
clientX: uiState.mouse.position.screen.x,
|
||||
clientY: uiState.mouse.position.screen.y,
|
||||
type: 'mouseup'
|
||||
});
|
||||
};
|
||||
|
||||
el.addEventListener('mousemove', onMouseEvent);
|
||||
el.addEventListener('mousedown', onMouseEvent);
|
||||
el.addEventListener('mouseup', onMouseEvent);
|
||||
el.addEventListener('touchstart', onTouchStart);
|
||||
el.addEventListener('touchmove', onTouchMove);
|
||||
el.addEventListener('touchend', onTouchEnd);
|
||||
|
||||
return () => {
|
||||
el.removeEventListener('mousemove', onMouseEvent);
|
||||
el.removeEventListener('mousedown', onMouseEvent);
|
||||
el.removeEventListener('mouseup', onMouseEvent);
|
||||
el.removeEventListener('touchstart', onTouchStart);
|
||||
el.removeEventListener('touchmove', onTouchMove);
|
||||
el.removeEventListener('touchend', onTouchEnd);
|
||||
};
|
||||
}, [onMouseEvent]);
|
||||
}, [onMouseEvent, uiState.mouse.position.screen]);
|
||||
|
||||
const setElement = useCallback((element: HTMLElement) => {
|
||||
rendererRef.current = element;
|
||||
|
||||
@@ -25,3 +25,8 @@ export const ProjectionOrientationEnum = {
|
||||
} as const;
|
||||
|
||||
export type BoundingBox = [Coords, Coords, Coords, Coords];
|
||||
|
||||
export type SlimMouseEvent = Pick<
|
||||
MouseEvent,
|
||||
'clientX' | 'clientY' | 'target' | 'type'
|
||||
>;
|
||||
|
||||
@@ -23,7 +23,8 @@ import {
|
||||
ProjectionOrientationEnum,
|
||||
AnchorPositionsEnum,
|
||||
BoundingBox,
|
||||
TextBox
|
||||
TextBox,
|
||||
SlimMouseEvent
|
||||
} from 'src/types';
|
||||
import {
|
||||
CoordsUtils,
|
||||
@@ -250,7 +251,7 @@ interface GetMouse {
|
||||
zoom: number;
|
||||
scroll: Scroll;
|
||||
lastMouse: Mouse;
|
||||
mouseEvent: MouseEvent | TouchEvent;
|
||||
mouseEvent: SlimMouseEvent;
|
||||
rendererSize: Size;
|
||||
}
|
||||
|
||||
@@ -268,12 +269,7 @@ export const getMouse = ({
|
||||
y: componentOffset?.top ?? 0
|
||||
};
|
||||
|
||||
const clientX =
|
||||
(mouseEvent as MouseEvent).clientX ??
|
||||
(mouseEvent as TouchEvent).touches[0].clientX;
|
||||
const clientY =
|
||||
(mouseEvent as MouseEvent).clientY ??
|
||||
(mouseEvent as TouchEvent).touches[0].clientY;
|
||||
const { clientX, clientY } = mouseEvent;
|
||||
|
||||
const mousePosition = {
|
||||
x: clientX - offset.x,
|
||||
|
||||
Reference in New Issue
Block a user