fix: removes references to window size, replaces with renderer size

This commit is contained in:
Mark Mankarious
2023-08-07 00:29:59 +01:00
parent 287de5bd0e
commit 50c73235fe
11 changed files with 132 additions and 98 deletions

View File

@@ -1,34 +1,26 @@
import React, { useMemo } from 'react';
import { Box } from '@mui/material';
import { Connector as ConnectorI, Node, Coords, Scroll, Size } from 'src/types';
import { Svg } from 'src/components/Svg/Svg';
import { Connector as ConnectorI, Node, Coords } from 'src/types';
import { UNPROJECTED_TILE_SIZE } from 'src/config';
import {
pathfinder,
getBoundingBox,
getBoundingBoxSize,
getTilePosition
} from 'src/utils';
import { pathfinder, getBoundingBox, getBoundingBoxSize } from 'src/utils';
import { IsoTileArea } from 'src/components/IsoTileArea/IsoTileArea';
import { useGetTilePosition } from 'src/hooks/useGetTilePosition';
import { useUiStateStore } from 'src/stores/useUiStateStore';
interface Props {
connector: ConnectorI;
fromNode: Node;
toNode: Node;
scroll: Scroll;
zoom: number;
}
// How far a connector can be outside the grid area that covers two nodes
const BOUNDS_OFFSET: Coords = { x: 3, y: 3 };
export const Connector = ({
connector,
fromNode,
toNode,
zoom,
scroll
}: Props) => {
export const Connector = ({ fromNode, toNode }: Props) => {
const zoom = useUiStateStore((state) => {
return state.zoom;
});
const { getTilePosition } = useGetTilePosition();
const connectorParams = useMemo(() => {
const searchArea = getBoundingBox(
[fromNode.position, toNode.position],
@@ -46,13 +38,11 @@ export const Connector = ({
}`;
}, '');
const position = getTilePosition({
tile: fromNode.position,
zoom,
scroll
tile: fromNode.position
});
return { path, connectorAreaSize, position };
}, [fromNode.position, toNode.position, zoom, scroll]);
}, [fromNode.position, toNode.position, getTilePosition, zoom]);
return (
<Box

View File

@@ -1,20 +1,23 @@
import React, { useEffect, useRef, useCallback, useState } from 'react';
import { Box, useTheme } from '@mui/material';
import gsap from 'gsap';
import { getTilePosition } from 'src/utils';
import { Coords, TileOriginEnum, Scroll } from 'src/types';
import { Coords, TileOriginEnum } from 'src/types';
import { IsoTileArea } from 'src/components/IsoTileArea/IsoTileArea';
import { useUiStateStore } from 'src/stores/useUiStateStore';
import { useGetTilePosition } from 'src/hooks/useGetTilePosition';
interface Props {
tile: Coords;
scroll: Scroll;
zoom: number;
}
export const Cursor = ({ tile, zoom, scroll }: Props) => {
export const Cursor = ({ tile }: Props) => {
const zoom = useUiStateStore((state) => {
return state.zoom;
});
const theme = useTheme();
const [isReady, setIsReady] = useState(false);
const containerRef = useRef<HTMLDivElement>();
const { getTilePosition } = useGetTilePosition();
const setPosition = useCallback(
({
@@ -28,9 +31,7 @@ export const Cursor = ({ tile, zoom, scroll }: Props) => {
const position = getTilePosition({
tile: _tile,
origin: TileOriginEnum.TOP,
scroll,
zoom
origin: TileOriginEnum.TOP
});
gsap.to(containerRef.current, {
@@ -39,7 +40,7 @@ export const Cursor = ({ tile, zoom, scroll }: Props) => {
top: position.y
});
},
[zoom, scroll]
[getTilePosition]
);
useEffect(() => {

View File

@@ -1,18 +1,22 @@
import React, { useMemo } from 'react';
import chroma from 'chroma-js';
import { Box } from '@mui/material';
import { Node, Scroll, TileOriginEnum, Group as GroupI } from 'src/types';
import { getBoundingBox, getTilePosition, getBoundingBoxSize } from 'src/utils';
import { Node, TileOriginEnum, Group as GroupI } from 'src/types';
import { getBoundingBox, getBoundingBoxSize } from 'src/utils';
import { IsoTileArea } from 'src/components/IsoTileArea/IsoTileArea';
import { useGetTilePosition } from 'src/hooks/useGetTilePosition';
import { useUiStateStore } from 'src/stores/useUiStateStore';
interface Props {
nodes: Node[];
group: GroupI;
zoom: number;
scroll: Scroll;
}
export const Group = ({ nodes, zoom, scroll, group }: Props) => {
export const Group = ({ nodes, group }: Props) => {
const zoom = useUiStateStore((state) => {
return state.zoom;
});
const { getTilePosition } = useGetTilePosition();
const nodePositions = useMemo(() => {
return nodes.map((node) => {
return node.position;
@@ -25,13 +29,11 @@ export const Group = ({ nodes, zoom, scroll, group }: Props) => {
const position = getTilePosition({
tile: corners[2],
zoom,
scroll,
origin: TileOriginEnum.TOP
});
return { size, position };
}, [nodePositions, zoom, scroll]);
}, [nodePositions, getTilePosition]);
if (!groupAttrs) return null;

View File

@@ -1,28 +1,28 @@
import React, { useEffect, useRef, useCallback, useMemo } from 'react';
import { Box } from '@mui/material';
import gsap from 'gsap';
import { Size, Coords, TileOriginEnum, Node as NodeI, Scroll } from 'src/types';
import {
getTilePosition,
getProjectedTileSize,
getColorVariant
} from 'src/utils';
import { Size, Coords, TileOriginEnum, Node as NodeI } from 'src/types';
import { getProjectedTileSize, getColorVariant } from 'src/utils';
import { useResizeObserver } from 'src/hooks/useResizeObserver';
import { IsoTileArea } from 'src/components/IsoTileArea/IsoTileArea';
import { useUiStateStore } from 'src/stores/useUiStateStore';
import { useGetTilePosition } from 'src/hooks/useGetTilePosition';
import { LabelContainer } from './LabelContainer';
import { MarkdownLabel } from './LabelTypes/MarkdownLabel';
interface Props {
node: NodeI;
iconUrl?: string;
zoom: number;
scroll: Scroll;
}
export const Node = ({ node, iconUrl, zoom, scroll }: Props) => {
export const Node = ({ node, iconUrl }: Props) => {
const zoom = useUiStateStore((state) => {
return state.zoom;
});
const nodeRef = useRef<HTMLDivElement>();
const iconRef = useRef<HTMLImageElement>();
const { observe, size: iconSize } = useResizeObserver();
const { getTilePosition } = useGetTilePosition();
useEffect(() => {
if (!iconRef.current) return;
@@ -46,8 +46,6 @@ export const Node = ({ node, iconUrl, zoom, scroll }: Props) => {
const position = getTilePosition({
tile,
zoom,
scroll,
origin: TileOriginEnum.BOTTOM
});
@@ -63,7 +61,7 @@ export const Node = ({ node, iconUrl, zoom, scroll }: Props) => {
y: position.y
});
},
[zoom, scroll]
[getTilePosition]
);
const onImageLoaded = useCallback(() => {

View File

@@ -10,6 +10,7 @@ import { Node } from 'src/components/Node/Node';
import { Group } from 'src/components/Group/Group';
import { Connector } from 'src/components/Connector/Connector';
import { DebugUtils } from 'src/components/DebugUtils/DebugUtils';
import { useResizeObserver } from 'src/hooks/useResizeObserver';
export const Renderer = () => {
const [isDebugModeOn] = useState(false);
@@ -32,7 +33,11 @@ export const Renderer = () => {
const scroll = useUiStateStore((state) => {
return state.scroll;
});
const { setRendererSize } = useUiStateStore((state) => {
return state.actions;
});
const { setElement } = useInteractionManager();
const { observe, size: rendererSize } = useResizeObserver();
const getNodesFromIds = useCallback(
(nodeIds: string[]) => {
@@ -52,8 +57,13 @@ export const Renderer = () => {
useEffect(() => {
if (!containerRef.current) return;
observe(containerRef.current);
setElement(containerRef.current);
}, [setElement]);
}, [setElement, observe]);
useEffect(() => {
setRendererSize(rendererSize);
}, [rendererSize, setRendererSize]);
return (
<Box
@@ -67,19 +77,9 @@ export const Renderer = () => {
{scene.groups.map((group) => {
const nodes = getNodesFromIds(group.nodeIds);
return (
<Group
key={group.id}
group={group}
nodes={nodes}
zoom={zoom}
scroll={scroll}
/>
);
return <Group key={group.id} group={group} nodes={nodes} />;
})}
{mode.showCursor && (
<Cursor tile={mouse.position.tile} zoom={zoom} scroll={scroll} />
)}
{mode.showCursor && <Cursor tile={mouse.position.tile} />}
{/* {scene.connectors.map((connector) => {
const nodes = getNodesFromIds([connector.from, connector.to]);
@@ -103,8 +103,6 @@ export const Renderer = () => {
return icon.id === node.iconId;
})?.url
}
zoom={zoom}
scroll={scroll}
/>
);
})}

View File

@@ -2,12 +2,8 @@ import { useCallback } from 'react';
import { useSceneStore } from 'src/stores/useSceneStore';
import { useUiStateStore } from 'src/stores/useUiStateStore';
import { Size, Coords } from 'src/types';
import {
getBoundingBox,
getBoundingBoxSize,
sortByPosition,
getTilePosition
} from 'src/utils';
import { getBoundingBox, getBoundingBoxSize, sortByPosition } from 'src/utils';
import { useGetTilePosition } from 'src/hooks/useGetTilePosition';
const BOUNDING_BOX_PADDING = 4;
@@ -29,6 +25,7 @@ export const useDiagramUtils = () => {
const uiStateActions = useUiStateStore((state) => {
return state.actions;
});
const { getTilePosition } = useGetTilePosition();
const getDiagramBoundingBox = useCallback((): Size & Coords => {
if (scene.nodes.length === 0) return { width: 0, height: 0, x: 0, y: 0 };
@@ -43,9 +40,7 @@ export const useDiagramUtils = () => {
});
const cornerPositions = corners.map((corner) => {
return getTilePosition({
scroll,
tile: corner,
zoom
tile: corner
});
});
const sortedCorners = sortByPosition(cornerPositions);
@@ -58,7 +53,7 @@ export const useDiagramUtils = () => {
x: topLeft.x,
y: topLeft.y
};
}, [scene, scroll, zoom]);
}, [scene, getTilePosition]);
const fitDiagramToScreen = useCallback(() => {
const boundingBox = getDiagramBoundingBox();

View File

@@ -0,0 +1,29 @@
import { useCallback } from 'react';
import { useUiStateStore } from 'src/stores/useUiStateStore';
import { Coords, TileOriginEnum } from 'src/types';
import { getTilePosition as getTilePositionUtil } from 'src/utils';
export const useGetTilePosition = () => {
const { scroll, zoom, rendererSize } = useUiStateStore((state) => {
return {
scroll: state.scroll,
zoom: state.zoom,
rendererSize: state.rendererSize
};
});
const getTilePosition = useCallback(
({ tile, origin }: { tile: Coords; origin?: TileOriginEnum }) => {
return getTilePositionUtil({
tile,
scroll,
zoom,
origin,
rendererSize
});
},
[scroll, zoom, rendererSize]
);
return { getTilePosition };
};

View File

@@ -17,7 +17,7 @@ const reducers: { [k in string]: InteractionReducer } = {
};
export const useInteractionManager = () => {
const elementRef = useRef<HTMLElement>();
const rendererRef = useRef<HTMLElement>();
const mode = useUiStateStore((state) => {
return state.mode;
});
@@ -42,9 +42,14 @@ export const useInteractionManager = () => {
const scene = useSceneStore(({ nodes, connectors, groups, icons }) => {
return { nodes, connectors, groups, icons };
});
const rendererSize = useUiStateStore((state) => {
return state.rendererSize;
});
const onMouseEvent = useCallback(
(e: MouseEvent) => {
if (!rendererRef.current) return;
const reducer = reducers[mode.type];
if (
@@ -58,7 +63,7 @@ export const useInteractionManager = () => {
return;
const reducerAction = reducer[e.type];
const componentOffset = elementRef.current?.getBoundingClientRect();
const componentOffset = rendererRef.current?.getBoundingClientRect();
const offset: Coords = {
x: componentOffset?.left ?? 0,
y: componentOffset?.top ?? 0
@@ -74,7 +79,8 @@ export const useInteractionManager = () => {
tile: screenToIso({
mouse: mousePosition,
zoom,
scroll
scroll,
rendererSize
})
};
@@ -134,21 +140,23 @@ export const useInteractionManager = () => {
);
useEffect(() => {
if (!elementRef.current) return;
if (!rendererRef.current) return;
window.addEventListener('mousemove', onMouseEvent);
window.addEventListener('mousedown', onMouseEvent);
window.addEventListener('mouseup', onMouseEvent);
const el = rendererRef.current;
el.addEventListener('mousemove', onMouseEvent);
el.addEventListener('mousedown', onMouseEvent);
el.addEventListener('mouseup', onMouseEvent);
return () => {
window.removeEventListener('mousemove', onMouseEvent);
window.removeEventListener('mousedown', onMouseEvent);
window.removeEventListener('mouseup', onMouseEvent);
el.removeEventListener('mousemove', onMouseEvent);
el.removeEventListener('mousedown', onMouseEvent);
el.removeEventListener('mouseup', onMouseEvent);
};
}, [onMouseEvent]);
const setElement = useCallback((element: HTMLElement) => {
elementRef.current = element;
rendererRef.current = element;
}, []);
return {

View File

@@ -31,6 +31,7 @@ export const useUiStateStore = create<UseUiStateStore>((set, get) => {
offset: { x: 0, y: 0 }
},
zoom: 1,
rendererSize: { width: 0, height: 0 },
actions: {
setMode: (mode) => {
set({ mode });
@@ -62,6 +63,9 @@ export const useUiStateStore = create<UseUiStateStore>((set, get) => {
},
setMouse: (mouse) => {
set({ mouse });
},
setRendererSize: (rendererSize) => {
set({ rendererSize });
}
}
};

View File

@@ -1,4 +1,4 @@
import { Coords } from './common';
import { Coords, Size } from './common';
import { SceneItem } from './scene';
export enum SidebarTypeEnum {
@@ -87,6 +87,7 @@ export interface UiState {
zoom: number;
scroll: Scroll;
mouse: Mouse;
rendererSize: Size;
}
export interface UiStateActions {
@@ -99,4 +100,5 @@ export interface UiStateActions {
setSidebar: (itemControls: ItemControls) => void;
setContextMenu: (contextMenu: ContextMenu) => void;
setMouse: (mouse: Mouse) => void;
setRendererSize: (rendererSize: Size) => void;
}

View File

@@ -18,20 +18,24 @@ interface ScreenToIso {
mouse: Coords;
zoom: number;
scroll: Scroll;
rendererSize: Size;
}
// converts a mouse position to a tile position
export const screenToIso = ({ mouse, zoom, scroll }: ScreenToIso) => {
const editorWidth = window.innerWidth;
const editorHeight = window.innerHeight;
export const screenToIso = ({
mouse,
zoom,
scroll,
rendererSize
}: ScreenToIso) => {
const projectedTileSize = getProjectedTileSize({ zoom });
const halfW = projectedTileSize.width / 2;
const halfH = projectedTileSize.height / 2;
// The origin is the center of the project.
const projectPosition = {
x: mouse.x - scroll.position.x - editorWidth * 0.5,
y: mouse.y - scroll.position.y - editorHeight * 0.5
x: mouse.x - scroll.position.x - rendererSize.width * 0.5,
y: mouse.y - scroll.position.y - rendererSize.height * 0.5
};
const tile = {
@@ -53,26 +57,29 @@ interface GetTilePosition {
scroll: Scroll;
zoom: number;
origin?: TileOriginEnum;
rendererSize: Size;
}
export const getTilePosition = ({
tile,
scroll,
zoom,
origin = TileOriginEnum.CENTER
origin = TileOriginEnum.CENTER,
rendererSize
}: GetTilePosition) => {
// TODO: Refactor editorWidth to not use window width
const editorWidth = window.innerWidth;
const editorHeight = window.innerHeight;
const projectedTileSize = getProjectedTileSize({ zoom });
const halfW = projectedTileSize.width / 2;
const halfH = projectedTileSize.height / 2;
const position: Coords = {
x:
editorWidth * 0.5 + (halfW * tile.x - halfW * tile.y) + scroll.position.x,
rendererSize.width * 0.5 +
(halfW * tile.x - halfW * tile.y) +
scroll.position.x,
y:
editorHeight * 0.5 - (halfH * tile.x + halfH * tile.y) + scroll.position.y
rendererSize.height * 0.5 -
(halfH * tile.x + halfH * tile.y) +
scroll.position.y
};
switch (origin) {