Merge pull request #4166 from xyflow/refactor/xy-drag-use-map
Refactor/xy drag use map
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
## Patch changes
|
## Patch changes
|
||||||
|
|
||||||
- use correct positions for intersection helpers
|
- use correct positions for intersection helpers
|
||||||
|
- fix minimap interaction for touch devices
|
||||||
|
|
||||||
## 12.0.0-next.14
|
## 12.0.0-next.14
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export function useMoveSelectedNodes() {
|
|||||||
const moveSelectedNodes = useCallback((params: { direction: XYPosition; factor: number }) => {
|
const moveSelectedNodes = useCallback((params: { direction: XYPosition; factor: number }) => {
|
||||||
const { nodeExtent, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin } =
|
const { nodeExtent, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin } =
|
||||||
store.getState();
|
store.getState();
|
||||||
const nodeUpdates = [];
|
const nodeUpdates = new Map();
|
||||||
const isSelected = selectedAndDraggable(nodesDraggable);
|
const isSelected = selectedAndDraggable(nodesDraggable);
|
||||||
|
|
||||||
// by default a node moves 5px on each key press
|
// by default a node moves 5px on each key press
|
||||||
@@ -56,7 +56,7 @@ export function useMoveSelectedNodes() {
|
|||||||
node.position = position;
|
node.position = position;
|
||||||
node.internals.positionAbsolute = positionAbsolute;
|
node.internals.positionAbsolute = positionAbsolute;
|
||||||
|
|
||||||
nodeUpdates.push(node);
|
nodeUpdates.set(node.id, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateNodePositions(nodeUpdates);
|
updateNodePositions(nodeUpdates);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
|
|
||||||
import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
|
import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
|
||||||
import getInitialState from './initialState';
|
import getInitialState from './initialState';
|
||||||
import type { ReactFlowState, Node, Edge, UnselectNodesAndEdgesParams, FitViewOptions, InternalNode } from '../types';
|
import type { ReactFlowState, Node, Edge, UnselectNodesAndEdgesParams, FitViewOptions } from '../types';
|
||||||
|
|
||||||
const createRFStore = ({
|
const createRFStore = ({
|
||||||
nodes,
|
nodes,
|
||||||
@@ -124,27 +124,26 @@ const createRFStore = ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateNodePositions: (nodeDragItems, dragging = false) => {
|
updateNodePositions: (nodeDragItems, dragging = false) => {
|
||||||
const { nodeLookup, parentLookup } = get();
|
|
||||||
const parentExpandChildren: ParentExpandChild[] = [];
|
const parentExpandChildren: ParentExpandChild[] = [];
|
||||||
|
const changes = [];
|
||||||
|
|
||||||
const changes: NodeChange[] = nodeDragItems.map((node) => {
|
for (const [id, dragItem] of nodeDragItems) {
|
||||||
// @todo add expandParent to drag item so that we can get rid of the look up here
|
// @todo add expandParent to drag item so that we can get rid of the look up here
|
||||||
const internalNode = nodeLookup.get(node.id);
|
|
||||||
const change: NodeChange = {
|
const change: NodeChange = {
|
||||||
id: node.id,
|
id,
|
||||||
type: 'position',
|
type: 'position',
|
||||||
position: node.position,
|
position: dragItem.position,
|
||||||
dragging,
|
dragging,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (internalNode?.expandParent && internalNode?.parentId && change.position) {
|
if (dragItem?.expandParent && dragItem?.parentId && change.position) {
|
||||||
parentExpandChildren.push({
|
parentExpandChildren.push({
|
||||||
id: internalNode.id,
|
id,
|
||||||
parentId: internalNode.parentId,
|
parentId: dragItem.parentId,
|
||||||
rect: {
|
rect: {
|
||||||
...node.internals.positionAbsolute,
|
...dragItem.internals.positionAbsolute,
|
||||||
width: internalNode.measured.width!,
|
width: dragItem.measured.width!,
|
||||||
height: internalNode.measured.height!,
|
height: dragItem.measured.height!,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -152,10 +151,11 @@ const createRFStore = ({
|
|||||||
change.position.y = Math.max(0, change.position.y);
|
change.position.y = Math.max(0, change.position.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
return change;
|
changes.push(change);
|
||||||
});
|
}
|
||||||
|
|
||||||
if (parentExpandChildren.length > 0) {
|
if (parentExpandChildren.length > 0) {
|
||||||
|
const { nodeLookup, parentLookup } = get();
|
||||||
const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup);
|
const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup);
|
||||||
changes.push(...parentExpandChanges);
|
changes.push(...parentExpandChanges);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,14 +64,14 @@ export function createStore({
|
|||||||
const updateNodePositions: UpdateNodePositions = (nodeDragItems, dragging = false) => {
|
const updateNodePositions: UpdateNodePositions = (nodeDragItems, dragging = false) => {
|
||||||
const nodeLookup = get(store.nodeLookup);
|
const nodeLookup = get(store.nodeLookup);
|
||||||
|
|
||||||
for (const nodeDragItem of nodeDragItems) {
|
for (const [id, dragItem] of nodeDragItems) {
|
||||||
const node = nodeLookup.get(nodeDragItem.id)?.internals.userNode;
|
const node = nodeLookup.get(id)?.internals.userNode;
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
node.position = nodeDragItem.position;
|
node.position = dragItem.position;
|
||||||
node.dragging = dragging;
|
node.dragging = dragging;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ export type SelectionRect = Rect & {
|
|||||||
|
|
||||||
export type OnError = (id: string, message: string) => void;
|
export type OnError = (id: string, message: string) => void;
|
||||||
|
|
||||||
export type UpdateNodePositions = (dragItems: NodeDragItem[] | InternalNodeBase[], dragging?: boolean) => void;
|
export type UpdateNodePositions = (dragItems: Map<string, NodeDragItem | InternalNodeBase>, dragging?: boolean) => void;
|
||||||
export type PanBy = (delta: XYPosition) => boolean;
|
export type PanBy = (delta: XYPosition) => boolean;
|
||||||
|
|
||||||
export type UpdateConnection = (params: {
|
export type UpdateConnection = (params: {
|
||||||
|
|||||||
@@ -120,8 +120,8 @@ export type NodeDragItem = {
|
|||||||
// 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;
|
||||||
measured: {
|
measured: {
|
||||||
width: number | null;
|
width: number;
|
||||||
height: number | null;
|
height: number;
|
||||||
};
|
};
|
||||||
internals: {
|
internals: {
|
||||||
positionAbsolute: XYPosition;
|
positionAbsolute: XYPosition;
|
||||||
|
|||||||
@@ -205,9 +205,13 @@ export function isCoordinateExtent(extent?: CoordinateExtent | 'parent'): extent
|
|||||||
return extent !== undefined && extent !== 'parent';
|
return extent !== undefined && extent !== 'parent';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNodeDimensions<NodeType extends NodeBase = NodeBase>(
|
export function getNodeDimensions(node: {
|
||||||
node: NodeType
|
measured?: { width?: number; height?: number };
|
||||||
): { width: number; height: number } {
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
initialWidth?: number;
|
||||||
|
initialHeight?: number;
|
||||||
|
}): { width: number; height: number } {
|
||||||
return {
|
return {
|
||||||
width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,
|
width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,
|
||||||
height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0,
|
height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
getViewportForBounds,
|
getViewportForBounds,
|
||||||
isCoordinateExtent,
|
isCoordinateExtent,
|
||||||
getNodeDimensions,
|
getNodeDimensions,
|
||||||
|
getPositionWithOrigin,
|
||||||
} from './general';
|
} from './general';
|
||||||
import {
|
import {
|
||||||
type Transform,
|
type Transform,
|
||||||
@@ -25,6 +26,7 @@ import {
|
|||||||
OnBeforeDeleteBase,
|
OnBeforeDeleteBase,
|
||||||
NodeLookup,
|
NodeLookup,
|
||||||
InternalNodeBase,
|
InternalNodeBase,
|
||||||
|
NodeDragItem,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { errorMessages } from '../constants';
|
import { errorMessages } from '../constants';
|
||||||
|
|
||||||
@@ -186,7 +188,7 @@ export const getNodesBounds = (
|
|||||||
export type GetInternalNodesBoundsParams = {
|
export type GetInternalNodesBoundsParams = {
|
||||||
nodeOrigin?: NodeOrigin;
|
nodeOrigin?: NodeOrigin;
|
||||||
useRelativePosition?: boolean;
|
useRelativePosition?: boolean;
|
||||||
filter?: (node: NodeBase) => boolean;
|
filter?: (node: NodeBase | NodeDragItem) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -194,10 +196,9 @@ export type GetInternalNodesBoundsParams = {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export const getInternalNodesBounds = (
|
export const getInternalNodesBounds = (
|
||||||
nodeLookup: NodeLookup,
|
nodeLookup: NodeLookup | Map<string, NodeDragItem>,
|
||||||
params: GetInternalNodesBoundsParams = {
|
params: GetInternalNodesBoundsParams = {
|
||||||
nodeOrigin: [0, 0],
|
nodeOrigin: [0, 0],
|
||||||
useRelativePosition: false,
|
|
||||||
}
|
}
|
||||||
): Rect => {
|
): Rect => {
|
||||||
if (nodeLookup.size === 0) {
|
if (nodeLookup.size === 0) {
|
||||||
@@ -208,12 +209,22 @@ export const getInternalNodesBounds = (
|
|||||||
|
|
||||||
nodeLookup.forEach((node) => {
|
nodeLookup.forEach((node) => {
|
||||||
if (params.filter == undefined || params.filter(node)) {
|
if (params.filter == undefined || params.filter(node)) {
|
||||||
const nodePos = getNodePositionWithOrigin(node, node.origin || params.nodeOrigin);
|
const { width, height } = getNodeDimensions(node);
|
||||||
|
const { x, y } = getPositionWithOrigin({
|
||||||
|
x: node.internals.positionAbsolute.x,
|
||||||
|
y: node.internals.positionAbsolute.x,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
origin: node.origin || params.nodeOrigin,
|
||||||
|
});
|
||||||
|
|
||||||
box = getBoundsOfBoxes(
|
box = getBoundsOfBoxes(
|
||||||
box,
|
box,
|
||||||
rectToBox({
|
rectToBox({
|
||||||
...nodePos[params.useRelativePosition ? 'position' : 'positionAbsolute'],
|
x,
|
||||||
...getNodeDimensions(node),
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import {
|
|||||||
getPointerPosition,
|
getPointerPosition,
|
||||||
calculateNodePosition,
|
calculateNodePosition,
|
||||||
snapPosition,
|
snapPosition,
|
||||||
getNodesBounds,
|
getInternalNodesBounds,
|
||||||
rectToBox,
|
rectToBox,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
import { getDragItems, getEventHandlerParams, hasSelector, wrapSelectionDragFunc } from './utils';
|
import { getDragItems, getEventHandlerParams, hasSelector } from './utils';
|
||||||
import type {
|
import type {
|
||||||
NodeBase,
|
NodeBase,
|
||||||
NodeDragItem,
|
NodeDragItem,
|
||||||
@@ -29,7 +29,12 @@ import type {
|
|||||||
InternalNodeBase,
|
InternalNodeBase,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
export type OnDrag = (event: MouseEvent, dragItems: NodeDragItem[], node: NodeBase, nodes: NodeBase[]) => void;
|
export type OnDrag = (
|
||||||
|
event: MouseEvent,
|
||||||
|
dragItems: Map<string, NodeDragItem>,
|
||||||
|
node: NodeBase,
|
||||||
|
nodes: NodeBase[]
|
||||||
|
) => void;
|
||||||
|
|
||||||
type StoreItems<OnNodeDrag> = {
|
type StoreItems<OnNodeDrag> = {
|
||||||
nodes: NodeBase[];
|
nodes: NodeBase[];
|
||||||
@@ -89,7 +94,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
}: XYDragParams<OnNodeDrag>): XYDragInstance {
|
}: XYDragParams<OnNodeDrag>): XYDragInstance {
|
||||||
let lastPos: { x: number | null; y: number | null } = { x: null, y: null };
|
let lastPos: { x: number | null; y: number | null } = { x: null, y: null };
|
||||||
let autoPanId = 0;
|
let autoPanId = 0;
|
||||||
let dragItems: NodeDragItem[] = [];
|
let dragItems = new Map<string, NodeDragItem>();
|
||||||
let autoPanStarted = false;
|
let autoPanStarted = false;
|
||||||
let mousePosition: XYPosition = { x: 0, y: 0 };
|
let mousePosition: XYPosition = { x: 0, y: 0 };
|
||||||
let containerBounds: DOMRect | null = null;
|
let containerBounds: DOMRect | null = null;
|
||||||
@@ -117,13 +122,13 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
let hasChange = false;
|
let hasChange = false;
|
||||||
let nodesBox: Box = { x: 0, y: 0, x2: 0, y2: 0 };
|
let nodesBox: Box = { x: 0, y: 0, x2: 0, y2: 0 };
|
||||||
|
|
||||||
if (dragItems.length > 1 && nodeExtent) {
|
if (dragItems.size > 1 && nodeExtent) {
|
||||||
const rect = getNodesBounds(dragItems as unknown as NodeBase[], { nodeOrigin });
|
const rect = getInternalNodesBounds(dragItems, { nodeOrigin });
|
||||||
nodesBox = rectToBox(rect);
|
nodesBox = rectToBox(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
dragItems = dragItems.map((n) => {
|
for (const [id, dragItem] of dragItems) {
|
||||||
let nextPosition = { x: x - n.distance.x, y: y - n.distance.y };
|
let nextPosition = { x: x - dragItem.distance.x, y: y - dragItem.distance.y };
|
||||||
|
|
||||||
if (snapToGrid) {
|
if (snapToGrid) {
|
||||||
nextPosition = snapPosition(nextPosition, snapGrid);
|
nextPosition = snapPosition(nextPosition, snapGrid);
|
||||||
@@ -136,13 +141,13 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
[nodeExtent[1][0], nodeExtent[1][1]],
|
[nodeExtent[1][0], nodeExtent[1][1]],
|
||||||
];
|
];
|
||||||
|
|
||||||
if (dragItems.length > 1 && nodeExtent && !n.extent) {
|
if (dragItems.size > 1 && nodeExtent && !dragItem.extent) {
|
||||||
const { positionAbsolute } = n.internals;
|
const { positionAbsolute } = dragItem.internals;
|
||||||
const x1 = positionAbsolute.x - nodesBox.x + nodeExtent[0][0];
|
const x1 = positionAbsolute.x - nodesBox.x + nodeExtent[0][0];
|
||||||
const x2 = positionAbsolute.x + (n.measured?.width ?? 0) - nodesBox.x2 + nodeExtent[1][0];
|
const x2 = positionAbsolute.x + dragItem.measured.width - nodesBox.x2 + nodeExtent[1][0];
|
||||||
|
|
||||||
const y1 = positionAbsolute.y - nodesBox.y + nodeExtent[0][1];
|
const y1 = positionAbsolute.y - nodesBox.y + nodeExtent[0][1];
|
||||||
const y2 = positionAbsolute.y + (n.measured?.height ?? 0) - nodesBox.y2 + nodeExtent[1][1];
|
const y2 = positionAbsolute.y + dragItem.measured.height - nodesBox.y2 + nodeExtent[1][1];
|
||||||
|
|
||||||
adjustedNodeExtent = [
|
adjustedNodeExtent = [
|
||||||
[x1, y1],
|
[x1, y1],
|
||||||
@@ -151,7 +156,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { position, positionAbsolute } = calculateNodePosition({
|
const { position, positionAbsolute } = calculateNodePosition({
|
||||||
nodeId: n.id,
|
nodeId: id,
|
||||||
nextPosition,
|
nextPosition,
|
||||||
nodeLookup,
|
nodeLookup,
|
||||||
nodeExtent: adjustedNodeExtent,
|
nodeExtent: adjustedNodeExtent,
|
||||||
@@ -160,13 +165,11 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
});
|
});
|
||||||
|
|
||||||
// we want to make sure that we only fire a change event when there is a change
|
// we want to make sure that we only fire a change event when there is a change
|
||||||
hasChange = hasChange || n.position.x !== position.x || n.position.y !== position.y;
|
hasChange = hasChange || dragItem.position.x !== position.x || dragItem.position.y !== position.y;
|
||||||
|
|
||||||
n.position = position;
|
dragItem.position = position;
|
||||||
n.internals.positionAbsolute = positionAbsolute;
|
dragItem.internals.positionAbsolute = positionAbsolute;
|
||||||
|
}
|
||||||
return n;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!hasChange) {
|
if (!hasChange) {
|
||||||
return;
|
return;
|
||||||
@@ -185,8 +188,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
onNodeDrag?.(dragEvent, currentNode, currentNodes);
|
onNodeDrag?.(dragEvent, currentNode, currentNodes);
|
||||||
|
|
||||||
if (!nodeId) {
|
if (!nodeId) {
|
||||||
const _onSelectionDrag = wrapSelectionDragFunc(onSelectionDrag);
|
onSelectionDrag?.(dragEvent, currentNodes);
|
||||||
_onSelectionDrag(dragEvent, currentNode, currentNodes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +244,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
lastPos = pointerPos;
|
lastPos = pointerPos;
|
||||||
dragItems = getDragItems(nodeLookup, nodesDraggable, pointerPos, nodeId);
|
dragItems = getDragItems(nodeLookup, nodesDraggable, pointerPos, nodeId);
|
||||||
|
|
||||||
if (dragItems.length > 0 && (onDragStart || onNodeDragStart || (!nodeId && onSelectionDragStart))) {
|
if (dragItems.size > 0 && (onDragStart || onNodeDragStart || (!nodeId && onSelectionDragStart))) {
|
||||||
const [currentNode, currentNodes] = getEventHandlerParams({
|
const [currentNode, currentNodes] = getEventHandlerParams({
|
||||||
nodeId,
|
nodeId,
|
||||||
dragItems,
|
dragItems,
|
||||||
@@ -253,8 +255,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
onNodeDragStart?.(event.sourceEvent as MouseEvent, currentNode, currentNodes);
|
onNodeDragStart?.(event.sourceEvent as MouseEvent, currentNode, currentNodes);
|
||||||
|
|
||||||
if (!nodeId) {
|
if (!nodeId) {
|
||||||
const _onSelectionDragStart = wrapSelectionDragFunc(onSelectionDragStart);
|
onSelectionDragStart?.(event.sourceEvent as MouseEvent, currentNodes);
|
||||||
_onSelectionDragStart(event.sourceEvent as MouseEvent, currentNode, currentNodes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,7 +309,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
dragStarted = false;
|
dragStarted = false;
|
||||||
cancelAnimationFrame(autoPanId);
|
cancelAnimationFrame(autoPanId);
|
||||||
|
|
||||||
if (dragItems.length > 0) {
|
if (dragItems.size > 0) {
|
||||||
const { nodeLookup, updateNodePositions, onNodeDragStop, onSelectionDragStop } = getStoreItems();
|
const { nodeLookup, updateNodePositions, onNodeDragStop, onSelectionDragStop } = getStoreItems();
|
||||||
|
|
||||||
updateNodePositions(dragItems, false);
|
updateNodePositions(dragItems, false);
|
||||||
@@ -324,8 +325,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
onNodeDragStop?.(event.sourceEvent as MouseEvent, currentNode, currentNodes);
|
onNodeDragStop?.(event.sourceEvent as MouseEvent, currentNode, currentNodes);
|
||||||
|
|
||||||
if (!nodeId) {
|
if (!nodeId) {
|
||||||
const _onSelectionDragStop = wrapSelectionDragFunc(onSelectionDragStop);
|
onSelectionDragStop?.(event.sourceEvent as MouseEvent, currentNodes);
|
||||||
_onSelectionDragStop(event.sourceEvent as MouseEvent, currentNode, currentNodes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { type NodeDragItem, type XYPosition, InternalNodeBase, NodeBase, NodeLookup } from '../types';
|
import { type NodeDragItem, type XYPosition, InternalNodeBase, NodeBase, NodeLookup } from '../types';
|
||||||
|
|
||||||
export function wrapSelectionDragFunc(selectionFunc?: (event: MouseEvent, nodes: NodeBase[]) => void) {
|
|
||||||
return (event: MouseEvent, _: NodeBase, nodes: NodeBase[]) => selectionFunc?.(event, nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isParentSelected<NodeType extends NodeBase>(node: NodeType, nodeLookup: NodeLookup): boolean {
|
export function isParentSelected<NodeType extends NodeBase>(node: NodeType, nodeLookup: NodeLookup): boolean {
|
||||||
if (!node.parentId) {
|
if (!node.parentId) {
|
||||||
return false;
|
return false;
|
||||||
@@ -40,8 +36,8 @@ export function getDragItems<NodeType extends NodeBase>(
|
|||||||
nodesDraggable: boolean,
|
nodesDraggable: boolean,
|
||||||
mousePos: XYPosition,
|
mousePos: XYPosition,
|
||||||
nodeId?: string
|
nodeId?: string
|
||||||
): NodeDragItem[] {
|
): Map<string, NodeDragItem> {
|
||||||
const dragItems: NodeDragItem[] = [];
|
const dragItems = new Map<string, NodeDragItem>();
|
||||||
|
|
||||||
for (const [id, node] of nodeLookup) {
|
for (const [id, node] of nodeLookup) {
|
||||||
if (
|
if (
|
||||||
@@ -49,29 +45,32 @@ export function getDragItems<NodeType extends NodeBase>(
|
|||||||
(!node.parentId || !isParentSelected(node, nodeLookup)) &&
|
(!node.parentId || !isParentSelected(node, nodeLookup)) &&
|
||||||
(node.draggable || (nodesDraggable && typeof node.draggable === 'undefined'))
|
(node.draggable || (nodesDraggable && typeof node.draggable === 'undefined'))
|
||||||
) {
|
) {
|
||||||
const internalNode = nodeLookup.get(id)!;
|
const internalNode = nodeLookup.get(id);
|
||||||
|
|
||||||
dragItems.push({
|
if (internalNode) {
|
||||||
id: internalNode.id,
|
dragItems.set(id, {
|
||||||
position: internalNode.position || { x: 0, y: 0 },
|
id,
|
||||||
distance: {
|
position: internalNode.position || { x: 0, y: 0 },
|
||||||
x: mousePos.x - internalNode.internals.positionAbsolute.x,
|
distance: {
|
||||||
y: mousePos.y - internalNode.internals.positionAbsolute.y,
|
x: mousePos.x - internalNode.internals.positionAbsolute.x,
|
||||||
},
|
y: mousePos.y - internalNode.internals.positionAbsolute.y,
|
||||||
extent: internalNode.extent,
|
},
|
||||||
parentId: internalNode.parentId,
|
extent: internalNode.extent,
|
||||||
origin: internalNode.origin,
|
parentId: internalNode.parentId,
|
||||||
expandParent: internalNode.expandParent,
|
origin: internalNode.origin,
|
||||||
internals: {
|
expandParent: internalNode.expandParent,
|
||||||
positionAbsolute: internalNode.internals.positionAbsolute || { x: 0, y: 0 },
|
internals: {
|
||||||
},
|
positionAbsolute: internalNode.internals.positionAbsolute || { x: 0, y: 0 },
|
||||||
measured: {
|
},
|
||||||
width: internalNode.measured.width || 0,
|
measured: {
|
||||||
height: internalNode.measured.height || 0,
|
width: internalNode.measured.width ?? 0,
|
||||||
},
|
height: internalNode.measured.height ?? 0,
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dragItems;
|
return dragItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,20 +83,32 @@ export function getEventHandlerParams<NodeType extends NodeBase>({
|
|||||||
nodeLookup,
|
nodeLookup,
|
||||||
}: {
|
}: {
|
||||||
nodeId?: string;
|
nodeId?: string;
|
||||||
dragItems: NodeDragItem[];
|
dragItems: Map<string, NodeDragItem>;
|
||||||
nodeLookup: Map<string, NodeType>;
|
nodeLookup: Map<string, NodeType>;
|
||||||
}): [NodeType, NodeType[]] {
|
}): [NodeType, NodeType[]] {
|
||||||
const nodesFromDragItems: NodeType[] = dragItems.map((n) => {
|
const nodesFromDragItems: NodeType[] = [];
|
||||||
const node = nodeLookup.get(n.id)!;
|
|
||||||
|
|
||||||
return {
|
for (const [id, dragItem] of dragItems) {
|
||||||
|
const node = nodeLookup.get(id);
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
nodesFromDragItems.push({
|
||||||
|
...node,
|
||||||
|
position: dragItem.position,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nodeId) {
|
||||||
|
return [nodesFromDragItems[0], nodesFromDragItems];
|
||||||
|
}
|
||||||
|
|
||||||
|
const node = nodeLookup.get(nodeId)!;
|
||||||
|
return [
|
||||||
|
{
|
||||||
...node,
|
...node,
|
||||||
position: n.position,
|
position: dragItems.get(nodeId)?.position || node.position,
|
||||||
measured: {
|
},
|
||||||
...n.measured,
|
nodesFromDragItems,
|
||||||
},
|
];
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return [nodeId ? nodesFromDragItems.find((n) => n.id === nodeId)! : nodesFromDragItems[0], nodesFromDragItems];
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user