mirror of
https://github.com/stan-smith/FossFLOW.git
synced 2025-12-24 15:09:03 -05:00
feat: allows better drag and drop interaction for connector anchors
This commit is contained in:
@@ -3,7 +3,7 @@ import { useTheme, Box } from '@mui/material';
|
||||
import { Connector as ConnectorI } from 'src/types';
|
||||
import { UNPROJECTED_TILE_SIZE } from 'src/config';
|
||||
import {
|
||||
getAnchorPosition,
|
||||
getAnchorTile,
|
||||
CoordsUtils,
|
||||
getColorVariant,
|
||||
getAllAnchors
|
||||
@@ -53,11 +53,7 @@ export const Connector = ({ connector }: Props) => {
|
||||
|
||||
const anchorPositions = useMemo(() => {
|
||||
return connector.anchors.map((anchor) => {
|
||||
const position = getAnchorPosition({
|
||||
anchor,
|
||||
nodes,
|
||||
allAnchors: getAllAnchors(connectors)
|
||||
});
|
||||
const position = getAnchorTile(anchor, nodes, getAllAnchors(connectors));
|
||||
|
||||
return {
|
||||
x: (connector.path.rectangle.from.x - position.x) * unprojectedTileSize,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
getBoundingBoxSize,
|
||||
sortByPosition,
|
||||
clamp,
|
||||
getAnchorPosition,
|
||||
getAnchorTile,
|
||||
getAllAnchors
|
||||
} from 'src/utils';
|
||||
import { useGetTilePosition } from 'src/hooks/useGetTilePosition';
|
||||
@@ -44,11 +44,11 @@ export const useDiagramUtils = () => {
|
||||
return [
|
||||
...acc,
|
||||
...item.anchors.map((anchor) => {
|
||||
return getAnchorPosition({
|
||||
return getAnchorTile(
|
||||
anchor,
|
||||
nodes: scene.nodes,
|
||||
allAnchors: getAllAnchors(scene.connectors)
|
||||
});
|
||||
scene.nodes,
|
||||
getAllAnchors(scene.connectors)
|
||||
);
|
||||
})
|
||||
];
|
||||
case 'RECTANGLE':
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { produce } from 'immer';
|
||||
import {
|
||||
ConnectorAnchor,
|
||||
Connector,
|
||||
ModeActions,
|
||||
ModeActionsAction,
|
||||
SceneItemTypeEnum,
|
||||
SceneStore,
|
||||
Coords
|
||||
Coords,
|
||||
Node
|
||||
} from 'src/types';
|
||||
import {
|
||||
getItemAtTile,
|
||||
@@ -13,9 +15,36 @@ import {
|
||||
getAnchorAtTile,
|
||||
getItemById,
|
||||
generateId,
|
||||
CoordsUtils
|
||||
CoordsUtils,
|
||||
getAnchorTile,
|
||||
getAllAnchors,
|
||||
connectorPathTileToGlobal
|
||||
} from 'src/utils';
|
||||
|
||||
const getAnchorOrdering = (
|
||||
anchor: ConnectorAnchor,
|
||||
connector: Connector,
|
||||
nodes: Node[],
|
||||
allAnchors: ConnectorAnchor[]
|
||||
) => {
|
||||
const anchorTile = getAnchorTile(anchor, nodes, allAnchors);
|
||||
const index = connector.path.tiles.findIndex((pathTile) => {
|
||||
const globalTile = connectorPathTileToGlobal(
|
||||
pathTile,
|
||||
connector.path.rectangle.from
|
||||
);
|
||||
return CoordsUtils.isEqual(globalTile, anchorTile);
|
||||
});
|
||||
|
||||
if (index === -1) {
|
||||
throw new Error(
|
||||
`Could not calculate ordering index of anchor [anchorId: ${anchor.id}]`
|
||||
);
|
||||
}
|
||||
|
||||
return index;
|
||||
};
|
||||
|
||||
const getAnchor = (connectorId: string, tile: Coords, scene: SceneStore) => {
|
||||
const connector = getItemById(scene.connectors, connectorId).item;
|
||||
const anchor = getAnchorAtTile(tile, connector.anchors);
|
||||
@@ -27,11 +56,19 @@ const getAnchor = (connectorId: string, tile: Coords, scene: SceneStore) => {
|
||||
ref: { type: 'TILE', coords: tile }
|
||||
};
|
||||
|
||||
const newConnector = produce(connector, (draft) => {
|
||||
draft.anchors.push(newAnchor);
|
||||
});
|
||||
const allAnchors = getAllAnchors(scene.connectors);
|
||||
const orderedAnchors = [...connector.anchors, newAnchor]
|
||||
.map((anch) => {
|
||||
return {
|
||||
...anch,
|
||||
ordering: getAnchorOrdering(anch, connector, scene.nodes, allAnchors)
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a.ordering - b.ordering;
|
||||
});
|
||||
|
||||
scene.actions.updateConnector(connector.id, newConnector);
|
||||
scene.actions.updateConnector(connector.id, { anchors: orderedAnchors });
|
||||
return newAnchor;
|
||||
}
|
||||
|
||||
@@ -84,14 +121,8 @@ export const Cursor: ModeActions = {
|
||||
|
||||
let item = uiState.mode.mousedownItem;
|
||||
|
||||
if (item?.type === 'CONNECTOR') {
|
||||
const prevTile = uiState.mouse.delta
|
||||
? CoordsUtils.subtract(
|
||||
uiState.mouse.position.tile,
|
||||
uiState.mouse.delta.tile
|
||||
)
|
||||
: CoordsUtils.zero();
|
||||
const anchor = getAnchor(item.id, prevTile, scene);
|
||||
if (item?.type === 'CONNECTOR' && uiState.mouse.mousedown) {
|
||||
const anchor = getAnchor(item.id, uiState.mouse.mousedown.tile, scene);
|
||||
item = anchor;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,13 +88,11 @@ const initialState = () => {
|
||||
|
||||
draft.nodes.splice(index, 1);
|
||||
|
||||
draft.connectors = draft.connectors.filter(
|
||||
(connector) => {
|
||||
return !connector.anchors.find((anchor) => {
|
||||
return anchor.ref.type === 'NODE' && anchor.ref.id === id;
|
||||
});
|
||||
}
|
||||
);
|
||||
draft.connectors = draft.connectors.filter((connector) => {
|
||||
return !connector.anchors.find((anchor) => {
|
||||
return anchor.ref.type === 'NODE' && anchor.ref.id === id;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
set({ nodes: newScene.nodes, connectors: newScene.connectors });
|
||||
@@ -134,7 +132,6 @@ const initialState = () => {
|
||||
});
|
||||
|
||||
set({ connectors: newScene.connectors });
|
||||
console.log(newScene.connectors)
|
||||
},
|
||||
|
||||
deleteConnector: (id: string) => {
|
||||
@@ -165,10 +162,7 @@ const initialState = () => {
|
||||
|
||||
updateTextBox: (id, updates) => {
|
||||
const newScene = produce(get(), (draft) => {
|
||||
const { item: textBox, index } = getItemById(
|
||||
draft.textBoxes,
|
||||
id
|
||||
);
|
||||
const { item: textBox, index } = getItemById(draft.textBoxes, id);
|
||||
|
||||
if (updates.text !== undefined || updates.fontSize !== undefined) {
|
||||
draft.textBoxes[index].size = {
|
||||
|
||||
@@ -86,7 +86,12 @@ export interface Rectangle {
|
||||
to: Coords;
|
||||
}
|
||||
|
||||
export type SceneItem = Node | Connector | TextBox | Rectangle | ConnectorAnchor;
|
||||
export type SceneItem =
|
||||
| Node
|
||||
| Connector
|
||||
| TextBox
|
||||
| Rectangle
|
||||
| ConnectorAnchor;
|
||||
export type SceneItemReference = {
|
||||
type: SceneItemTypeEnum;
|
||||
id: string;
|
||||
|
||||
@@ -334,17 +334,11 @@ export const getAllAnchors = (connectors: Connector[]) => {
|
||||
}, [] as ConnectorAnchor[]);
|
||||
};
|
||||
|
||||
interface GetAnchorPositions {
|
||||
anchor: ConnectorAnchor;
|
||||
nodes: Node[];
|
||||
allAnchors: ConnectorAnchor[];
|
||||
}
|
||||
|
||||
export const getAnchorPosition = ({
|
||||
anchor,
|
||||
nodes,
|
||||
allAnchors
|
||||
}: GetAnchorPositions): Coords => {
|
||||
export const getAnchorTile = (
|
||||
anchor: ConnectorAnchor,
|
||||
nodes: Node[],
|
||||
allAnchors: ConnectorAnchor[]
|
||||
): Coords => {
|
||||
if (anchor.ref.type === 'NODE') {
|
||||
const { item: node } = getItemById(nodes, anchor.ref.id);
|
||||
return node.tile;
|
||||
@@ -357,7 +351,7 @@ export const getAnchorPosition = ({
|
||||
|
||||
const nextAnchor = getItemById(anchorsWithIds, anchor.ref.id);
|
||||
|
||||
return getAnchorPosition({ anchor: nextAnchor.item, nodes, allAnchors });
|
||||
return getAnchorTile(nextAnchor.item, nodes, allAnchors);
|
||||
}
|
||||
|
||||
return anchor.ref.coords;
|
||||
@@ -395,7 +389,7 @@ export const getConnectorPath = ({
|
||||
);
|
||||
|
||||
const anchorPositions = anchors.map((anchor) => {
|
||||
return getAnchorPosition({ anchor, nodes, allAnchors });
|
||||
return getAnchorTile(anchor, nodes, allAnchors);
|
||||
});
|
||||
|
||||
const searchArea = getBoundingBox(
|
||||
@@ -411,7 +405,10 @@ export const getConnectorPath = ({
|
||||
};
|
||||
|
||||
const positionsNormalisedFromSearchArea = anchorPositions.map((position) => {
|
||||
return normalisePositionFromOrigin({ position, origin: rectangle.from });
|
||||
return normalisePositionFromOrigin({
|
||||
position,
|
||||
origin: rectangle.from
|
||||
});
|
||||
});
|
||||
|
||||
const tiles = positionsNormalisedFromSearchArea.reduce<Coords[]>(
|
||||
|
||||
Reference in New Issue
Block a user