refactor: simplifies renderer component

This commit is contained in:
Mark Mankarious
2023-08-17 10:42:43 +01:00
parent f7532c2b85
commit 0cb2446b9e
18 changed files with 133 additions and 96 deletions

View File

@@ -16,7 +16,7 @@ import { sceneToSceneInput } from 'src/utils';
import { useSceneStore, SceneProvider } from 'src/stores/sceneStore';
import { GlobalStyles } from 'src/styles/GlobalStyles';
import { Renderer } from 'src/components/Renderer/Renderer';
import { LabelContainer } from 'src/components/Node/LabelContainer';
import { LabelContainer } from 'src/components/Nodes/Node/LabelContainer';
import { useWindowUtils } from 'src/hooks/useWindowUtils';
import { sceneInput as sceneValidationSchema } from 'src/validation/scene';
import { EMPTY_SCENE } from 'src/config';

View File

@@ -0,0 +1,28 @@
import React from 'react';
import { useSceneStore } from 'src/stores/sceneStore';
import { useUiStateStore } from 'src/stores/uiStateStore';
import { Connector } from './Connector/Connector';
export const Connectors = () => {
const connectors = useSceneStore((state) => {
return state.connectors;
});
const mode = useUiStateStore((state) => {
return state.mode;
});
return (
<>
{connectors.map((connector) => {
return (
<>
<Connector key={connector.id} connector={connector} />
{mode.type === 'CONNECTOR' && mode.connector && (
<Connector connector={mode.connector} />
)}
</>
);
})}
</>
);
};

View File

@@ -1,14 +1,12 @@
import React from 'react';
import { useTheme } from '@mui/material';
import { Coords } from 'src/types';
import { IsoTileArea } from 'src/components/IsoTileArea/IsoTileArea';
import { useUiStateStore } from 'src/stores/uiStateStore';
interface Props {
tile: Coords;
}
export const Cursor = ({ tile }: Props) => {
export const Cursor = () => {
const tile = useUiStateStore((state) => {
return state.mouse.position.tile;
});
const zoom = useUiStateStore((state) => {
return state.zoom;
});

View File

@@ -1,6 +1,7 @@
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';
@@ -11,6 +12,9 @@ export const DebugUtils = () => {
const uiState = useUiStateStore(({ scroll, mouse, zoom, rendererSize }) => {
return { scroll, mouse, zoom, rendererSize };
});
const scene = useSceneStore((state) => {
return state;
});
const mode = useUiStateStore((state) => {
return state.mode;
});
@@ -73,6 +77,7 @@ export const DebugUtils = () => {
title="Size"
value={`${rendererSize.width}, ${rendererSize.height}`}
/>
<LineItem title="Scene info" value={`${scene.nodes.length} nodes`} />
<LineItem title="Mode" value={mode.type} />
<LineItem title="Mode data" value={JSON.stringify(mode)} />
</Box>

View File

@@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
import { Box } from '@mui/material';
import { Coords, TileOriginEnum, IconInput } from 'src/types';
import { useGetTilePosition } from 'src/hooks/useGetTilePosition';
import { NodeIcon } from 'src/components/Node/NodeIcon';
import { NodeIcon } from 'src/components/Nodes/Node/NodeIcon';
interface Props {
icon: IconInput;

View File

@@ -1,15 +1,16 @@
import React, { useMemo } from 'react';
import { Box } from '@mui/material';
import gridTileSvg from 'src/assets/grid-tile-bg.svg';
import { Scroll } from 'src/types';
import { useUiStateStore } from 'src/stores/uiStateStore';
import { getProjectedTileSize } from 'src/utils';
interface Props {
scroll: Scroll;
zoom: number;
}
export const Grid = ({ zoom, scroll }: Props) => {
export const Grid = () => {
const scroll = useUiStateStore((state) => {
return state.scroll;
});
const zoom = useUiStateStore((state) => {
return state.zoom;
});
const projectedTileSize = useMemo(() => {
return getProjectedTileSize({ zoom });
}, [zoom]);

View File

@@ -0,0 +1,33 @@
import React from 'react';
import { useSceneStore } from 'src/stores/sceneStore';
import { useUiStateStore } from 'src/stores/uiStateStore';
import { DEFAULT_COLOR } from 'src/config';
import { Group } from './Group/Group';
export const Groups = () => {
const groups = useSceneStore((state) => {
return state.groups;
});
const mode = useUiStateStore((state) => {
return state.mode;
});
return (
<>
{groups.map((group) => {
return (
<>
<Group key={group.id} {...group} />
{mode.type === 'AREA_TOOL' && mode.area && (
<Group
from={mode.area.from}
to={mode.area.to}
color={DEFAULT_COLOR}
/>
)}
</>
);
})}
</>
);
};

View File

@@ -0,0 +1,29 @@
import React from 'react';
import { useSceneStore } from 'src/stores/sceneStore';
import { Node } from './Node/Node';
export const Nodes = () => {
const nodes = useSceneStore((state) => {
return state.nodes;
});
const icons = useSceneStore((state) => {
return state.icons;
});
return (
<>
{nodes.map((node) => {
return (
<Node
key={node.id}
order={-node.position.x - node.position.y}
node={node}
icon={icons.find((icon) => {
return icon.id === node.iconId;
})}
/>
);
})}
</>
);
};

View File

@@ -1,54 +1,28 @@
import React, { useEffect, useRef } from 'react';
import { Box } from '@mui/material';
import { useUiStateStore } from 'src/stores/uiStateStore';
import { useSceneStore } from 'src/stores/sceneStore';
import { useInteractionManager } from 'src/interaction/useInteractionManager';
import { Grid } from 'src/components/Grid/Grid';
import { Cursor } from 'src/components/Cursor/Cursor';
import { Node } from 'src/components/Node/Node';
import { Group } from 'src/components/Group/Group';
import { Connector } from 'src/components/Connector/Connector';
import { Nodes } from 'src/components/Nodes/Nodes';
import { Groups } from 'src/components/Groups/Groups';
import { Connectors } from 'src/components/Connectors/Connectors';
import { DebugUtils } from 'src/components/DebugUtils/DebugUtils';
import { useResizeObserver } from 'src/hooks/useResizeObserver';
import { SceneLayer } from 'src/components/SceneLayer/SceneLayer';
import { DEFAULT_COLOR } from 'src/config';
export const Renderer = () => {
const containerRef = useRef<HTMLDivElement>();
const debugMode = useUiStateStore((state) => {
return state.debugMode;
});
const nodes = useSceneStore((state) => {
return state.nodes;
});
const scene = useSceneStore(({ connectors, groups }) => {
return { connectors, groups };
});
const interactionsEnabled = useUiStateStore((state) => {
return state.interactionsEnabled;
});
const icons = useSceneStore((state) => {
return state.icons;
});
const mode = useUiStateStore((state) => {
return state.mode;
});
const zoom = useUiStateStore((state) => {
return state.zoom;
});
const mouse = useUiStateStore((state) => {
return state.mouse;
});
const scroll = useUiStateStore((state) => {
return state.scroll;
});
const { setRendererSize } = useUiStateStore((state) => {
return state.actions;
});
const {
setElement: setInteractionsElement,
setIsEnabled: setInteractionsEnabled
} = useInteractionManager();
const { setElement: setInteractionsElement } = useInteractionManager();
const { observe, disconnect, size: rendererSize } = useResizeObserver();
useEffect(() => {
@@ -62,10 +36,6 @@ export const Renderer = () => {
};
}, [setInteractionsElement, observe, disconnect]);
useEffect(() => {
setInteractionsEnabled(interactionsEnabled);
}, [interactionsEnabled, setInteractionsEnabled]);
useEffect(() => {
setRendererSize(rendererSize);
}, [rendererSize, setRendererSize]);
@@ -77,47 +47,22 @@ export const Renderer = () => {
height: '100%'
}}
>
<Grid scroll={scroll} zoom={zoom} />
<SceneLayer>
{scene.groups.map((group) => {
return <Group key={group.id} {...group} />;
})}
<Grid />
</SceneLayer>
{mode.showCursor && (
<SceneLayer>
<Cursor />
</SceneLayer>
)}
<SceneLayer>
<Groups />
</SceneLayer>
<SceneLayer>
{mode.showCursor && <Cursor tile={mouse.position.tile} />}
<Connectors />
</SceneLayer>
<SceneLayer>
{mode.type === 'AREA_TOOL' && mode.area && (
<Group
from={mode.area.from}
to={mode.area.to}
color={DEFAULT_COLOR}
/>
)}
</SceneLayer>
<SceneLayer>
{scene.connectors.map((connector) => {
return <Connector key={connector.id} connector={connector} />;
})}
</SceneLayer>
<SceneLayer>
{nodes.map((node) => {
return (
<Node
key={node.id}
order={-node.position.x - node.position.y}
node={node}
icon={icons.find((icon) => {
return icon.id === node.iconId;
})}
/>
);
})}
</SceneLayer>
<SceneLayer>
{mode.type === 'CONNECTOR' && mode.connector && (
<Connector connector={mode.connector} />
)}
<Nodes />
</SceneLayer>
{debugMode && (
<SceneLayer>

View File

@@ -4,8 +4,8 @@ import { Callbacks } from './Callbacks/Callbacks';
import { DebugTools } from './DebugTools/DebugTools';
const examples = [
{ name: 'Callbacks', component: Callbacks },
{ name: 'Debug tools', component: DebugTools }
{ name: 'Debug tools', component: DebugTools },
{ name: 'Callbacks', component: Callbacks }
];
export const Examples = () => {

View File

@@ -15,9 +15,6 @@ export const useScroll = () => {
const rendererSize = useUiStateStore((state) => {
return state.rendererSize;
});
const zoom = useUiStateStore((state) => {
return state.zoom;
});
const scrollToTile = useCallback(
(tile: Coords, origin?: TileOriginEnum) => {
@@ -36,6 +33,7 @@ export const useScroll = () => {
);
return {
scroll,
scrollToTile
};
};

View File

@@ -23,9 +23,10 @@ const reducers: { [k in string]: InteractionReducer } = {
export const useInteractionManager = () => {
const rendererRef = useRef<HTMLElement>();
const reducerTypeRef = useRef<string>();
const [isEnabled, setIsEnabled] = useState(true);
const destroyListeners = useRef<() => void>();
const interactionsEnabled = useUiStateStore((state) => {
return state.interactionsEnabled;
});
const mode = useUiStateStore((state) => {
return state.mode;
});
@@ -151,7 +152,7 @@ export const useInteractionManager = () => {
// TODO: Needs optimisation, listeners are added / removed every time the mouse position changes. Very intensive.
useEffect(() => {
if (!rendererRef.current || !isEnabled) {
if (!rendererRef.current || !interactionsEnabled) {
destroyListeners.current?.();
return;
}
@@ -169,14 +170,13 @@ export const useInteractionManager = () => {
};
return destroyListeners.current;
}, [onMouseEvent, isEnabled]);
}, [onMouseEvent, interactionsEnabled]);
const setElement = useCallback((element: HTMLElement) => {
rendererRef.current = element;
}, []);
return {
setElement,
setIsEnabled
setElement
};
};