fix(subflows): use abs positions for internal calculations (#2189)

* refactor(dragging): only use absolute positions
* refactor(drag): handle node extent
* refactor(drag-handler): return latest data
* refactor(use-drag): cleanup

fixes #2181
This commit is contained in:
Moritz Klack
2022-06-01 12:55:36 +02:00
committed by GitHub
parent 17df2ab078
commit 26795be7fb
7 changed files with 29 additions and 40 deletions
+2 -2
View File
@@ -141,7 +141,7 @@ const initialEdges: Edge[] = [
]; ];
const connectionLineStyle: CSSProperties = { stroke: '#ddd' }; const connectionLineStyle: CSSProperties = { stroke: '#ddd' };
const snapGrid: SnapGrid = [16, 16]; const snapGrid: SnapGrid = [25, 25];
const nodeStrokeColor = (n: Node): string => { const nodeStrokeColor = (n: Node): string => {
if (n.style?.background) return n.style.background as string; if (n.style?.background) return n.style.background as string;
@@ -203,7 +203,7 @@ const OverviewFlow = () => {
> >
<MiniMap nodeStrokeColor={nodeStrokeColor} nodeColor={nodeColor} nodeBorderRadius={2} /> <MiniMap nodeStrokeColor={nodeStrokeColor} nodeColor={nodeColor} nodeBorderRadius={2} />
<Controls /> <Controls />
<Background color="#aaa" gap={20} /> <Background color="#aaa" gap={25} />
</ReactFlow> </ReactFlow>
); );
}; };
+2 -7
View File
@@ -4,8 +4,8 @@ import { select } from 'd3-selection';
import { useStoreApi } from '../../store'; import { useStoreApi } from '../../store';
import { pointToRendererPoint } from '../../utils/graph'; import { pointToRendererPoint } from '../../utils/graph';
import { NodeDragItem, NodeDragHandler, XYPosition } from '../../types'; import { NodeDragItem, NodeDragHandler } from '../../types';
import { getDragItems, getEventHandlerParams, getParentNodePosition, hasSelector, updatePosition } from './utils'; import { getDragItems, getEventHandlerParams, hasSelector, updatePosition } from './utils';
import { handleNodeClick } from '../../components/Nodes/utils'; import { handleNodeClick } from '../../components/Nodes/utils';
export type UseDragEvent = D3DragEvent<HTMLDivElement, null, SubjectPosition>; export type UseDragEvent = D3DragEvent<HTMLDivElement, null, SubjectPosition>;
@@ -40,7 +40,6 @@ function useDrag({
const store = useStoreApi(); const store = useStoreApi();
const dragItems = useRef<NodeDragItem[]>(); const dragItems = useRef<NodeDragItem[]>();
const lastPos = useRef<{ x: number | null; y: number | null }>({ x: null, y: null }); const lastPos = useRef<{ x: number | null; y: number | null }>({ x: null, y: null });
const parentPos = useRef<XYPosition>({ x: 0, y: 0 });
// returns the pointer position projected to the RF coordinate system // returns the pointer position projected to the RF coordinate system
const getPointerPosition = useCallback(({ sourceEvent }: UseDragEvent) => { const getPointerPosition = useCallback(({ sourceEvent }: UseDragEvent) => {
@@ -49,9 +48,6 @@ function useDrag({
const y = sourceEvent.touches ? sourceEvent.touches[0].clientY : sourceEvent.clientY; const y = sourceEvent.touches ? sourceEvent.touches[0].clientY : sourceEvent.clientY;
const pointerPos = pointToRendererPoint({ x, y }, transform, snapToGrid, snapGrid); const pointerPos = pointToRendererPoint({ x, y }, transform, snapToGrid, snapGrid);
pointerPos.x -= parentPos.current.x;
pointerPos.y -= parentPos.current.y;
return pointerPos; return pointerPos;
}, []); }, []);
@@ -65,7 +61,6 @@ function useDrag({
const dragHandler = drag() const dragHandler = drag()
.on('start', (event: UseDragEvent) => { .on('start', (event: UseDragEvent) => {
const { nodeInternals, multiSelectionActive, unselectNodesAndEdges } = store.getState(); const { nodeInternals, multiSelectionActive, unselectNodesAndEdges } = store.getState();
parentPos.current = getParentNodePosition(nodeInternals, nodeId);
if (!selectNodesOnDrag && !multiSelectionActive && nodeId) { if (!selectNodesOnDrag && !multiSelectionActive && nodeId) {
if (!nodeInternals.get(nodeId)?.selected) { if (!nodeInternals.get(nodeId)?.selected) {
+11 -29
View File
@@ -21,16 +21,6 @@ export function isParentSelected(node: Node, nodeInternals: NodeInternals): bool
return isParentSelected(parentNode, nodeInternals); return isParentSelected(parentNode, nodeInternals);
} }
export function getParentNodePosition(nodeInternals: NodeInternals, nodeId?: string): XYPosition {
const parentNodeId = nodeId ? nodeInternals.get(nodeId)?.parentNode : null;
const parentNode = parentNodeId ? nodeInternals.get(parentNodeId) : null;
return {
x: parentNode?.positionAbsolute?.x || 0,
y: parentNode?.positionAbsolute?.y || 0,
};
}
export function hasSelector(target: Element, selector: string, nodeRef: RefObject<Element>): boolean { export function hasSelector(target: Element, selector: string, nodeRef: RefObject<Element>): boolean {
let current = target; let current = target;
@@ -49,10 +39,10 @@ export function getDragItems(nodeInternals: NodeInternals, mousePos: XYPosition,
.filter((n) => (n.selected || n.id === nodeId) && (!n.parentNode || !isParentSelected(n, nodeInternals))) .filter((n) => (n.selected || n.id === nodeId) && (!n.parentNode || !isParentSelected(n, nodeInternals)))
.map((n) => ({ .map((n) => ({
id: n.id, id: n.id,
position: n.position, position: n.positionAbsolute || { x: 0, y: 0 },
distance: { distance: {
x: mousePos.x - n.position.x, x: mousePos.x - (n.positionAbsolute?.x ?? 0),
y: mousePos.y - n.position.y, y: mousePos.y - (n.positionAbsolute?.y ?? 0),
}, },
delta: { delta: {
x: 0, x: 0,
@@ -72,16 +62,19 @@ export function updatePosition(
nodeExtent?: CoordinateExtent nodeExtent?: CoordinateExtent
): NodeDragItem { ): NodeDragItem {
let currentExtent = dragItem.extent || nodeExtent; let currentExtent = dragItem.extent || nodeExtent;
let nextPosition = { x: mousePos.x - dragItem.distance.x, y: mousePos.y - dragItem.distance.y }; const nextPosition = { x: mousePos.x - dragItem.distance.x, y: mousePos.y - dragItem.distance.y };
if (dragItem.extent === 'parent') { if (dragItem.extent === 'parent') {
if (dragItem.parentNode && dragItem.width && dragItem.height) { if (dragItem.parentNode && dragItem.width && dragItem.height) {
const parent = nodeInternals.get(dragItem.parentNode); const parent = nodeInternals.get(dragItem.parentNode);
currentExtent = currentExtent =
parent?.width && parent?.height parent?.positionAbsolute && parent?.width && parent?.height
? [ ? [
[0, 0], [parent.positionAbsolute.x, parent.positionAbsolute.y],
[parent.width - dragItem.width, parent.height - dragItem.height], [
parent.positionAbsolute.x + parent.width - dragItem.width,
parent.positionAbsolute.y + parent.height - dragItem.height,
],
] ]
: currentExtent; : currentExtent;
} else { } else {
@@ -93,13 +86,7 @@ export function updatePosition(
} }
} }
nextPosition = currentExtent ? clampPosition(nextPosition, currentExtent as CoordinateExtent) : nextPosition; dragItem.position = currentExtent ? clampPosition(nextPosition, currentExtent as CoordinateExtent) : nextPosition;
dragItem.delta = {
x: nextPosition.x - dragItem.position.x,
y: nextPosition.y - dragItem.position.y,
};
dragItem.position = nextPosition;
return dragItem; return dragItem;
} }
@@ -121,11 +108,6 @@ export function getEventHandlerParams({
return { return {
...node, ...node,
position: n.position,
positionAbsolute: {
x: (node.positionAbsolute?.x || 0) + n.delta.x,
y: (node.positionAbsolute?.y || 0) + n.delta.y,
},
}; };
}); });
+9
View File
@@ -99,7 +99,16 @@ const createStore = () =>
}; };
if (positionChanged) { if (positionChanged) {
change.positionAbsolute = node.position;
change.position = node.position; change.position = node.position;
if (node.parentNode) {
const parentNode = nodeInternals.get(node.parentNode);
change.position = {
x: change.position.x - (parentNode?.positionAbsolute?.x ?? 0),
y: change.position.y - (parentNode?.positionAbsolute?.y ?? 0),
};
}
} }
return change; return change;
+1
View File
@@ -12,6 +12,7 @@ export type NodePositionChange = {
id: string; id: string;
type: 'position'; type: 'position';
position?: XYPosition; position?: XYPosition;
positionAbsolute?: XYPosition;
dragging?: boolean; dragging?: boolean;
}; };
-2
View File
@@ -115,8 +115,6 @@ export type NodeDragItem = {
position: XYPosition; position: XYPosition;
// distance from the mouse cursor to the node when start dragging // distance from the mouse cursor to the node when start dragging
distance: XYPosition; distance: XYPosition;
// delta to previous position
delta: XYPosition;
width?: number | null; width?: number | null;
height?: number | null; height?: number | null;
extent?: 'parent' | CoordinateExtent; extent?: 'parent' | CoordinateExtent;
+4
View File
@@ -67,6 +67,10 @@ function applyChanges(changes: any[], elements: any[]): any[] {
updateItem.position = currentChange.position; updateItem.position = currentChange.position;
} }
if (typeof currentChange.positionAbsolute !== 'undefined') {
updateItem.positionAbsolute = currentChange.positionAbsolute;
}
if (typeof currentChange.dragging !== 'undefined') { if (typeof currentChange.dragging !== 'undefined') {
updateItem.dragging = currentChange.dragging; updateItem.dragging = currentChange.dragging;
} }