refactor(react): improve performance by simplify edge renderer
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
import { memo, useState, useMemo, useRef, type ComponentType, type KeyboardEvent } from 'react';
|
import { memo, useState, useMemo, useRef, type ComponentType, type KeyboardEvent, useEffect } from 'react';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
import { getMarkerId, elementSelectionKeys, XYHandle, type Connection } from '@xyflow/system';
|
import { getMarkerId, elementSelectionKeys, XYHandle, type Connection } from '@xyflow/system';
|
||||||
|
|
||||||
import { useStoreApi } from '../../hooks/useStore';
|
import { useStoreApi, useStore } from '../../hooks/useStore';
|
||||||
import { ARIA_EDGE_DESC_KEY } from '../A11yDescriptions';
|
import { ARIA_EDGE_DESC_KEY } from '../A11yDescriptions';
|
||||||
import { EdgeAnchor } from './EdgeAnchor';
|
import { EdgeAnchor } from './EdgeAnchor';
|
||||||
import { getMouseHandler } from './utils';
|
import { getMouseHandler } from './utils';
|
||||||
import type { EdgeProps, WrapEdgeProps } from '../../types';
|
import type { EdgeProps, WrapEdgeProps } from '../../types';
|
||||||
|
import { getEdgePosition } from '../../hooks/useVisibleEdges';
|
||||||
const alwaysValidConnection = () => true;
|
import { shallow } from 'zustand/shallow';
|
||||||
|
|
||||||
export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
||||||
const EdgeWrapper = ({
|
const EdgeWrapper = ({
|
||||||
@@ -29,12 +29,6 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
|||||||
style,
|
style,
|
||||||
source,
|
source,
|
||||||
target,
|
target,
|
||||||
sourceX,
|
|
||||||
sourceY,
|
|
||||||
targetX,
|
|
||||||
targetY,
|
|
||||||
sourcePosition,
|
|
||||||
targetPosition,
|
|
||||||
isSelectable,
|
isSelectable,
|
||||||
hidden,
|
hidden,
|
||||||
sourceHandleId,
|
sourceHandleId,
|
||||||
@@ -60,11 +54,34 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
|||||||
const [updateHover, setUpdateHover] = useState<boolean>(false);
|
const [updateHover, setUpdateHover] = useState<boolean>(false);
|
||||||
const [updating, setUpdating] = useState<boolean>(false);
|
const [updating, setUpdating] = useState<boolean>(false);
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
|
const edgePosition = useStore((state) => {
|
||||||
|
const sourceNode = state.nodeInternals.get(source);
|
||||||
|
const targetNode = state.nodeInternals.get(target);
|
||||||
|
|
||||||
|
if (!sourceNode || !targetNode) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pos = getEdgePosition({
|
||||||
|
sourceNode,
|
||||||
|
targetNode,
|
||||||
|
sourceHandle: sourceHandleId || null,
|
||||||
|
targetHandle: targetHandleId || null,
|
||||||
|
connectionMode: state.connectionMode,
|
||||||
|
onError: state.onError,
|
||||||
|
});
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}, shallow);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// console.log(edgePosition);
|
||||||
|
}, [edgePosition]);
|
||||||
|
|
||||||
const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart, rfId)})`, [markerStart, rfId]);
|
const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart, rfId)})`, [markerStart, rfId]);
|
||||||
const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd, rfId)})`, [markerEnd, rfId]);
|
const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd, rfId)})`, [markerEnd, rfId]);
|
||||||
|
|
||||||
if (hidden) {
|
if (hidden || !edgePosition) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,12 +228,12 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
|||||||
labelBgBorderRadius={labelBgBorderRadius}
|
labelBgBorderRadius={labelBgBorderRadius}
|
||||||
data={data}
|
data={data}
|
||||||
style={style}
|
style={style}
|
||||||
sourceX={sourceX}
|
sourceX={edgePosition.sourceX}
|
||||||
sourceY={sourceY}
|
sourceY={edgePosition.sourceY}
|
||||||
targetX={targetX}
|
targetX={edgePosition.targetX}
|
||||||
targetY={targetY}
|
targetY={edgePosition.targetY}
|
||||||
sourcePosition={sourcePosition}
|
sourcePosition={edgePosition.sourcePosition}
|
||||||
targetPosition={targetPosition}
|
targetPosition={edgePosition.targetPosition}
|
||||||
sourceHandleId={sourceHandleId}
|
sourceHandleId={sourceHandleId}
|
||||||
targetHandleId={targetHandleId}
|
targetHandleId={targetHandleId}
|
||||||
markerStart={markerStartUrl}
|
markerStart={markerStartUrl}
|
||||||
@@ -229,9 +246,9 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
|||||||
<>
|
<>
|
||||||
{(isUpdatable === 'source' || isUpdatable === true) && (
|
{(isUpdatable === 'source' || isUpdatable === true) && (
|
||||||
<EdgeAnchor
|
<EdgeAnchor
|
||||||
position={sourcePosition}
|
position={edgePosition.sourcePosition}
|
||||||
centerX={sourceX}
|
centerX={edgePosition.sourceX}
|
||||||
centerY={sourceY}
|
centerY={edgePosition.sourceY}
|
||||||
radius={edgeUpdaterRadius}
|
radius={edgeUpdaterRadius}
|
||||||
onMouseDown={onEdgeUpdaterSourceMouseDown}
|
onMouseDown={onEdgeUpdaterSourceMouseDown}
|
||||||
onMouseEnter={onEdgeUpdaterMouseEnter}
|
onMouseEnter={onEdgeUpdaterMouseEnter}
|
||||||
@@ -241,9 +258,9 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
|||||||
)}
|
)}
|
||||||
{(isUpdatable === 'target' || isUpdatable === true) && (
|
{(isUpdatable === 'target' || isUpdatable === true) && (
|
||||||
<EdgeAnchor
|
<EdgeAnchor
|
||||||
position={targetPosition}
|
position={edgePosition.targetPosition}
|
||||||
centerX={targetX}
|
centerX={edgePosition.targetX}
|
||||||
centerY={targetY}
|
centerY={edgePosition.targetY}
|
||||||
radius={edgeUpdaterRadius}
|
radius={edgeUpdaterRadius}
|
||||||
onMouseDown={onEdgeUpdaterTargetMouseDown}
|
onMouseDown={onEdgeUpdaterTargetMouseDown}
|
||||||
onMouseEnter={onEdgeUpdaterMouseEnter}
|
onMouseEnter={onEdgeUpdaterMouseEnter}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { memo, ReactNode } from 'react';
|
import { memo, ReactNode } from 'react';
|
||||||
import { shallow } from 'zustand/shallow';
|
import { shallow } from 'zustand/shallow';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
import { errorMessages, ConnectionMode, Position, getHandle } from '@xyflow/system';
|
import { errorMessages } from '@xyflow/system';
|
||||||
|
|
||||||
import { useStore } from '../../hooks/useStore';
|
import { useStore } from '../../hooks/useStore';
|
||||||
import useVisibleEdges from '../../hooks/useVisibleEdges';
|
import useVisibleEdges from '../../hooks/useVisibleEdges';
|
||||||
import MarkerDefinitions from './MarkerDefinitions';
|
import MarkerDefinitions from './MarkerDefinitions';
|
||||||
import { getEdgePositions, getNodeData } from './utils';
|
|
||||||
import { GraphViewProps } from '../GraphView';
|
import { GraphViewProps } from '../GraphView';
|
||||||
import type { Edge, ReactFlowState } from '../../types';
|
import type { ReactFlowState } from '../../types';
|
||||||
|
|
||||||
type EdgeRendererProps = Pick<
|
type EdgeRendererProps = Pick<
|
||||||
GraphViewProps,
|
GraphViewProps,
|
||||||
@@ -35,14 +34,12 @@ type EdgeRendererProps = Pick<
|
|||||||
};
|
};
|
||||||
|
|
||||||
const selector = (s: ReactFlowState) => ({
|
const selector = (s: ReactFlowState) => ({
|
||||||
nodesConnectable: s.nodesConnectable,
|
width: s.width,
|
||||||
|
height: s.height,
|
||||||
edgesFocusable: s.edgesFocusable,
|
edgesFocusable: s.edgesFocusable,
|
||||||
edgesUpdatable: s.edgesUpdatable,
|
edgesUpdatable: s.edgesUpdatable,
|
||||||
elementsSelectable: s.elementsSelectable,
|
elementsSelectable: s.elementsSelectable,
|
||||||
width: s.width,
|
|
||||||
height: s.height,
|
|
||||||
connectionMode: s.connectionMode,
|
connectionMode: s.connectionMode,
|
||||||
nodeInternals: s.nodeInternals,
|
|
||||||
onError: s.onError,
|
onError: s.onError,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -65,9 +62,8 @@ const EdgeRenderer = ({
|
|||||||
onEdgeUpdateEnd,
|
onEdgeUpdateEnd,
|
||||||
children,
|
children,
|
||||||
}: EdgeRendererProps) => {
|
}: EdgeRendererProps) => {
|
||||||
const { edgesFocusable, edgesUpdatable, elementsSelectable, width, height, connectionMode, nodeInternals, onError } =
|
const { width, height, edgesFocusable, edgesUpdatable, elementsSelectable, onError } = useStore(selector, shallow);
|
||||||
useStore(selector, shallow);
|
const edgeTree = useVisibleEdges(onlyRenderVisibleElements, elevateEdgesOnSelect);
|
||||||
const edgeTree = useVisibleEdges(onlyRenderVisibleElements, nodeInternals, elevateEdgesOnSelect);
|
|
||||||
|
|
||||||
if (!width) {
|
if (!width) {
|
||||||
return null;
|
return null;
|
||||||
@@ -85,14 +81,7 @@ const EdgeRenderer = ({
|
|||||||
>
|
>
|
||||||
{isMaxLevel && <MarkerDefinitions defaultColor={defaultMarkerColor} rfId={rfId} />}
|
{isMaxLevel && <MarkerDefinitions defaultColor={defaultMarkerColor} rfId={rfId} />}
|
||||||
<g>
|
<g>
|
||||||
{edges.map((edge: Edge) => {
|
{edges.map((edge) => {
|
||||||
const [sourceNodeRect, sourceHandleBounds, sourceIsValid] = getNodeData(nodeInternals.get(edge.source));
|
|
||||||
const [targetNodeRect, targetHandleBounds, targetIsValid] = getNodeData(nodeInternals.get(edge.target));
|
|
||||||
|
|
||||||
if (!sourceIsValid || !targetIsValid) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let edgeType = edge.type || 'default';
|
let edgeType = edge.type || 'default';
|
||||||
|
|
||||||
if (!edgeTypes[edgeType]) {
|
if (!edgeTypes[edgeType]) {
|
||||||
@@ -100,16 +89,7 @@ const EdgeRenderer = ({
|
|||||||
edgeType = 'default';
|
edgeType = 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
const EdgeComponent = edgeTypes[edgeType] || edgeTypes.default;
|
const EdgeComponent = edgeTypes[edgeType];
|
||||||
// when connection type is loose we can define all handles as sources and connect source -> source
|
|
||||||
const targetNodeHandles =
|
|
||||||
connectionMode === ConnectionMode.Strict
|
|
||||||
? targetHandleBounds!.target
|
|
||||||
: (targetHandleBounds!.target ?? []).concat(targetHandleBounds!.source ?? []);
|
|
||||||
const sourceHandle = getHandle(sourceHandleBounds!.source!, edge.sourceHandle);
|
|
||||||
const targetHandle = getHandle(targetNodeHandles!, edge.targetHandle);
|
|
||||||
const sourcePosition = sourceHandle?.position || Position.Bottom;
|
|
||||||
const targetPosition = targetHandle?.position || Position.Top;
|
|
||||||
const isFocusable = !!(edge.focusable || (edgesFocusable && typeof edge.focusable === 'undefined'));
|
const isFocusable = !!(edge.focusable || (edgesFocusable && typeof edge.focusable === 'undefined'));
|
||||||
const isUpdatable =
|
const isUpdatable =
|
||||||
typeof onEdgeUpdate !== 'undefined' &&
|
typeof onEdgeUpdate !== 'undefined' &&
|
||||||
@@ -119,27 +99,12 @@ const EdgeRenderer = ({
|
|||||||
(elementsSelectable && typeof edge.selectable === 'undefined')
|
(elementsSelectable && typeof edge.selectable === 'undefined')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!sourceHandle || !targetHandle) {
|
|
||||||
onError?.('008', errorMessages['error008'](sourceHandle, edge));
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { sourceX, sourceY, targetX, targetY } = getEdgePositions(
|
|
||||||
sourceNodeRect,
|
|
||||||
sourceHandle,
|
|
||||||
sourcePosition,
|
|
||||||
targetNodeRect,
|
|
||||||
targetHandle,
|
|
||||||
targetPosition
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EdgeComponent
|
<EdgeComponent
|
||||||
key={edge.id}
|
key={edge.id}
|
||||||
id={edge.id}
|
id={edge.id}
|
||||||
className={cc([edge.className, noPanClassName])}
|
className={cc([edge.className, noPanClassName])}
|
||||||
type={edgeType}
|
type={edge.type}
|
||||||
data={edge.data}
|
data={edge.data}
|
||||||
selected={!!edge.selected}
|
selected={!!edge.selected}
|
||||||
animated={!!edge.animated}
|
animated={!!edge.animated}
|
||||||
@@ -157,12 +122,6 @@ const EdgeRenderer = ({
|
|||||||
targetHandleId={edge.targetHandle}
|
targetHandleId={edge.targetHandle}
|
||||||
markerEnd={edge.markerEnd}
|
markerEnd={edge.markerEnd}
|
||||||
markerStart={edge.markerStart}
|
markerStart={edge.markerStart}
|
||||||
sourceX={sourceX}
|
|
||||||
sourceY={sourceY}
|
|
||||||
targetX={targetX}
|
|
||||||
targetY={targetY}
|
|
||||||
sourcePosition={sourcePosition}
|
|
||||||
targetPosition={targetPosition}
|
|
||||||
isSelectable={isSelectable}
|
isSelectable={isSelectable}
|
||||||
onEdgeUpdate={onEdgeUpdate}
|
onEdgeUpdate={onEdgeUpdate}
|
||||||
onContextMenu={onEdgeContextMenu}
|
onContextMenu={onEdgeContextMenu}
|
||||||
|
|||||||
@@ -1,13 +1,29 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { internalsSymbol, isNumeric } from '@xyflow/system';
|
import {
|
||||||
|
BaseNode,
|
||||||
|
internalsSymbol,
|
||||||
|
isNumeric,
|
||||||
|
errorMessages,
|
||||||
|
ConnectionMode,
|
||||||
|
Position,
|
||||||
|
getHandle,
|
||||||
|
OnError,
|
||||||
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import { useStore } from '../hooks/useStore';
|
import { useStore } from '../hooks/useStore';
|
||||||
import { isEdgeVisible } from '../container/EdgeRenderer/utils';
|
import { getEdgePositions, getNodeData, isEdgeVisible } from '../container/EdgeRenderer/utils';
|
||||||
import { type ReactFlowState, type NodeInternals, type Edge } from '../types';
|
import { type ReactFlowState, type NodeInternals, type Edge, EdgePosition } from '../types';
|
||||||
|
import { shallow } from 'zustand/shallow';
|
||||||
|
|
||||||
const defaultEdgeTree = [{ level: 0, isMaxLevel: true, edges: [] }];
|
const defaultEdgeTree = [{ level: 0, isMaxLevel: true, edges: [] }];
|
||||||
|
|
||||||
function groupEdgesByZLevel(edges: Edge[], nodeInternals: NodeInternals, elevateEdgesOnSelect = false) {
|
type GroupedEdges = {
|
||||||
|
edges: Edge[];
|
||||||
|
level: number;
|
||||||
|
isMaxLevel: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
function groupEdgesByZLevel(edges: Edge[], nodeInternals: NodeInternals, elevateEdgesOnSelect = false): GroupedEdges[] {
|
||||||
let maxLevel = -1;
|
let maxLevel = -1;
|
||||||
|
|
||||||
const levelLookup = edges.reduce<Record<string, Edge[]>>((tree, edge) => {
|
const levelLookup = edges.reduce<Record<string, Edge[]>>((tree, edge) => {
|
||||||
@@ -51,42 +67,104 @@ function groupEdgesByZLevel(edges: Edge[], nodeInternals: NodeInternals, elevate
|
|||||||
return edgeTree;
|
return edgeTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useVisibleEdges(onlyRenderVisible: boolean, nodeInternals: NodeInternals, elevateEdgesOnSelect: boolean) {
|
type LayoutEdgeParams = {
|
||||||
|
sourceNode: BaseNode;
|
||||||
|
sourceHandle: string | null;
|
||||||
|
targetNode: BaseNode;
|
||||||
|
targetHandle: string | null;
|
||||||
|
connectionMode: ConnectionMode;
|
||||||
|
onError?: OnError;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getEdgePosition(params: LayoutEdgeParams): EdgePosition | null {
|
||||||
|
const [sourceNodeRect, sourceHandleBounds, sourceIsValid] = getNodeData(params.sourceNode);
|
||||||
|
const [targetNodeRect, targetHandleBounds, targetIsValid] = getNodeData(params.targetNode);
|
||||||
|
|
||||||
|
if (!sourceIsValid || !targetIsValid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// when connection type is loose we can define all handles as sources and connect source -> source
|
||||||
|
const targetNodeHandles =
|
||||||
|
params.connectionMode === ConnectionMode.Strict
|
||||||
|
? targetHandleBounds!.target
|
||||||
|
: (targetHandleBounds!.target ?? []).concat(targetHandleBounds!.source ?? []);
|
||||||
|
const sourceHandle = getHandle(sourceHandleBounds!.source!, params.sourceHandle);
|
||||||
|
const targetHandle = getHandle(targetNodeHandles!, params.targetHandle);
|
||||||
|
const sourcePosition = sourceHandle?.position || Position.Bottom;
|
||||||
|
const targetPosition = targetHandle?.position || Position.Top;
|
||||||
|
|
||||||
|
if (!sourceHandle || !targetHandle) {
|
||||||
|
params.onError?.('008', errorMessages['error008'](sourceHandle, {} as Edge));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { sourceX, sourceY, targetX, targetY } = getEdgePositions(
|
||||||
|
sourceNodeRect,
|
||||||
|
sourceHandle,
|
||||||
|
sourcePosition,
|
||||||
|
targetNodeRect,
|
||||||
|
targetHandle,
|
||||||
|
targetPosition
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
sourcePosition,
|
||||||
|
targetPosition,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function useVisibleEdges(onlyRenderVisible: boolean, elevateEdgesOnSelect: boolean): GroupedEdges[] {
|
||||||
const edges = useStore(
|
const edges = useStore(
|
||||||
useCallback(
|
useCallback(
|
||||||
(s: ReactFlowState) => {
|
(s: ReactFlowState) => {
|
||||||
if (!onlyRenderVisible) {
|
const visibleEdges = onlyRenderVisible
|
||||||
return s.edges;
|
? s.edges.filter((e) => {
|
||||||
}
|
const sourceNode = s.nodeInternals.get(e.source);
|
||||||
|
const targetNode = s.nodeInternals.get(e.target);
|
||||||
|
|
||||||
return s.edges.filter((e) => {
|
return (
|
||||||
const sourceNode = nodeInternals.get(e.source);
|
sourceNode?.width &&
|
||||||
const targetNode = nodeInternals.get(e.target);
|
sourceNode?.height &&
|
||||||
|
targetNode?.width &&
|
||||||
return (
|
targetNode?.height &&
|
||||||
sourceNode?.width &&
|
isEdgeVisible({
|
||||||
sourceNode?.height &&
|
sourcePos: sourceNode.positionAbsolute || { x: 0, y: 0 },
|
||||||
targetNode?.width &&
|
targetPos: targetNode.positionAbsolute || { x: 0, y: 0 },
|
||||||
targetNode?.height &&
|
sourceWidth: sourceNode.width,
|
||||||
isEdgeVisible({
|
sourceHeight: sourceNode.height,
|
||||||
sourcePos: sourceNode.positionAbsolute || { x: 0, y: 0 },
|
targetWidth: targetNode.width,
|
||||||
targetPos: targetNode.positionAbsolute || { x: 0, y: 0 },
|
targetHeight: targetNode.height,
|
||||||
sourceWidth: sourceNode.width,
|
width: s.width,
|
||||||
sourceHeight: sourceNode.height,
|
height: s.height,
|
||||||
targetWidth: targetNode.width,
|
transform: s.transform,
|
||||||
targetHeight: targetNode.height,
|
})
|
||||||
width: s.width,
|
);
|
||||||
height: s.height,
|
|
||||||
transform: s.transform,
|
|
||||||
})
|
})
|
||||||
);
|
: s.edges;
|
||||||
});
|
|
||||||
|
return groupEdgesByZLevel(visibleEdges, s.nodeInternals, elevateEdgesOnSelect);
|
||||||
},
|
},
|
||||||
[onlyRenderVisible, nodeInternals]
|
[onlyRenderVisible, elevateEdgesOnSelect]
|
||||||
)
|
),
|
||||||
|
(groupA, groupB) => {
|
||||||
|
const unEqual = groupA.some(
|
||||||
|
(item, index) =>
|
||||||
|
item.isMaxLevel !== groupB[index].isMaxLevel ||
|
||||||
|
item.level !== groupB[index].level ||
|
||||||
|
!shallow(item.edges, groupB[index].edges)
|
||||||
|
);
|
||||||
|
|
||||||
|
return !unEqual;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return groupEdgesByZLevel(edges, nodeInternals, elevateEdgesOnSelect);
|
return edges;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useVisibleEdges;
|
export default useVisibleEdges;
|
||||||
|
|||||||
@@ -54,12 +54,6 @@ export type WrapEdgeProps<T = any> = Omit<Edge<T>, 'sourceHandle' | 'targetHandl
|
|||||||
onEdgeDoubleClick?: EdgeMouseHandler;
|
onEdgeDoubleClick?: EdgeMouseHandler;
|
||||||
sourceHandleId?: string | null;
|
sourceHandleId?: string | null;
|
||||||
targetHandleId?: string | null;
|
targetHandleId?: string | null;
|
||||||
sourceX: number;
|
|
||||||
sourceY: number;
|
|
||||||
targetX: number;
|
|
||||||
targetY: number;
|
|
||||||
sourcePosition: Position;
|
|
||||||
targetPosition: Position;
|
|
||||||
onEdgeUpdate?: OnEdgeUpdateFunc;
|
onEdgeUpdate?: OnEdgeUpdateFunc;
|
||||||
onContextMenu?: EdgeMouseHandler;
|
onContextMenu?: EdgeMouseHandler;
|
||||||
onMouseEnter?: EdgeMouseHandler;
|
onMouseEnter?: EdgeMouseHandler;
|
||||||
@@ -88,18 +82,8 @@ export type EdgeProps<T = any> = Pick<
|
|||||||
Edge<T>,
|
Edge<T>,
|
||||||
'id' | 'animated' | 'data' | 'style' | 'selected' | 'source' | 'target'
|
'id' | 'animated' | 'data' | 'style' | 'selected' | 'source' | 'target'
|
||||||
> &
|
> &
|
||||||
Pick<
|
Pick<WrapEdgeProps, 'sourceHandleId' | 'targetHandleId' | 'interactionWidth'> &
|
||||||
WrapEdgeProps,
|
EdgePosition &
|
||||||
| 'sourceX'
|
|
||||||
| 'sourceY'
|
|
||||||
| 'targetX'
|
|
||||||
| 'targetY'
|
|
||||||
| 'sourcePosition'
|
|
||||||
| 'targetPosition'
|
|
||||||
| 'sourceHandleId'
|
|
||||||
| 'targetHandleId'
|
|
||||||
| 'interactionWidth'
|
|
||||||
> &
|
|
||||||
EdgeLabelOptions & {
|
EdgeLabelOptions & {
|
||||||
markerStart?: string;
|
markerStart?: string;
|
||||||
markerEnd?: string;
|
markerEnd?: string;
|
||||||
@@ -140,3 +124,12 @@ export type ConnectionLineComponentProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type ConnectionLineComponent = ComponentType<ConnectionLineComponentProps>;
|
export type ConnectionLineComponent = ComponentType<ConnectionLineComponentProps>;
|
||||||
|
|
||||||
|
export type EdgePosition = {
|
||||||
|
sourceX: number;
|
||||||
|
sourceY: number;
|
||||||
|
targetX: number;
|
||||||
|
targetY: number;
|
||||||
|
sourcePosition: Position;
|
||||||
|
targetPosition: Position;
|
||||||
|
};
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ function onPointerDown(
|
|||||||
getTransform,
|
getTransform,
|
||||||
}: OnPointerDownParams
|
}: OnPointerDownParams
|
||||||
) {
|
) {
|
||||||
// when react-flow is used inside a shadow root we can't use document
|
// when xyflow is used inside a shadow root we can't use document
|
||||||
const doc = getHostForElement(event.target as HTMLElement);
|
const doc = getHostForElement(event.target as HTMLElement);
|
||||||
let autoPanId = 0;
|
let autoPanId = 0;
|
||||||
let closestHandle: ConnectionHandle | null;
|
let closestHandle: ConnectionHandle | null;
|
||||||
|
|||||||
Reference in New Issue
Block a user