refactor(edges): optimize edge zIndex calculation
This commit is contained in:
@@ -8,13 +8,14 @@ import {
|
||||
type Connection,
|
||||
getEdgePosition,
|
||||
errorMessages,
|
||||
getEdgeZIndex,
|
||||
} from '@xyflow/system';
|
||||
|
||||
import { useStoreApi, useStore } from '../../hooks/useStore';
|
||||
import { ARIA_EDGE_DESC_KEY } from '../A11yDescriptions';
|
||||
import { EdgeAnchor } from '../Edges/EdgeAnchor';
|
||||
import { getMouseHandler } from '../Edges/utils';
|
||||
import type { EdgeWrapperProps } from '../../types';
|
||||
import type { EdgeWrapperProps, Node } from '../../types';
|
||||
import { builtinEdgeTypes } from './utils';
|
||||
|
||||
function EdgeWrapper({
|
||||
@@ -56,7 +57,8 @@ function EdgeWrapper({
|
||||
pathOptions,
|
||||
interactionWidth,
|
||||
edgeTypes,
|
||||
zIndex,
|
||||
zIndex: edgeZIndex,
|
||||
elevateEdgesOnSelect,
|
||||
onError,
|
||||
}: EdgeWrapperProps): JSX.Element | null {
|
||||
let edgeType = type || 'default';
|
||||
@@ -72,27 +74,45 @@ function EdgeWrapper({
|
||||
const [updateHover, setUpdateHover] = useState<boolean>(false);
|
||||
const [updating, setUpdating] = useState<boolean>(false);
|
||||
const store = useStoreApi();
|
||||
const edgePosition = useStore(
|
||||
const prevSourceNode = useRef<Node | undefined>();
|
||||
const prevTargetNode = useRef<Node | undefined>();
|
||||
const prevZIndex = useRef<number | undefined>(edgeZIndex);
|
||||
const prevEdgePosition = useRef<ReturnType<typeof getEdgePosition> | null>(null);
|
||||
|
||||
const { edgePosition, zIndex } = useStore(
|
||||
useCallback(
|
||||
(state) => {
|
||||
const sourceNode = state.nodeLookup.get(source);
|
||||
const targetNode = state.nodeLookup.get(target);
|
||||
|
||||
if (!sourceNode || !targetNode) {
|
||||
return null;
|
||||
return { edgePosition: null, zIndex: edgeZIndex };
|
||||
}
|
||||
|
||||
return getEdgePosition({
|
||||
id,
|
||||
sourceNode,
|
||||
targetNode,
|
||||
sourceHandle: sourceHandleId || null,
|
||||
targetHandle: targetHandleId || null,
|
||||
connectionMode: state.connectionMode,
|
||||
onError: state.onError,
|
||||
});
|
||||
const nodesChanged = prevSourceNode.current !== sourceNode || prevTargetNode.current !== targetNode;
|
||||
|
||||
prevSourceNode.current = sourceNode;
|
||||
prevTargetNode.current = targetNode;
|
||||
|
||||
prevEdgePosition.current = nodesChanged
|
||||
? getEdgePosition({
|
||||
id,
|
||||
sourceNode,
|
||||
targetNode,
|
||||
sourceHandle: sourceHandleId || null,
|
||||
targetHandle: targetHandleId || null,
|
||||
connectionMode: state.connectionMode,
|
||||
onError: state.onError,
|
||||
})
|
||||
: prevEdgePosition.current;
|
||||
prevZIndex.current = getEdgeZIndex(selected, edgeZIndex, sourceNode, targetNode, elevateEdgesOnSelect);
|
||||
|
||||
return {
|
||||
edgePosition: prevEdgePosition.current,
|
||||
zIndex: prevZIndex.current,
|
||||
};
|
||||
},
|
||||
[source, target]
|
||||
[source, target, selected, edgeZIndex]
|
||||
),
|
||||
shallow
|
||||
);
|
||||
|
||||
@@ -63,7 +63,7 @@ const EdgeRenderer = ({
|
||||
children,
|
||||
}: EdgeRendererProps) => {
|
||||
const { edgesFocusable, edgesUpdatable, elementsSelectable, onError } = useStore(selector, shallow);
|
||||
const edges = useVisibleEdges(onlyRenderVisibleElements, elevateEdgesOnSelect);
|
||||
const edges = useVisibleEdges(onlyRenderVisibleElements);
|
||||
|
||||
return (
|
||||
<div className="react-flow__edges">
|
||||
@@ -121,6 +121,7 @@ const EdgeRenderer = ({
|
||||
interactionWidth={edge.interactionWidth}
|
||||
onError={onError}
|
||||
edgeTypes={edgeTypes}
|
||||
elevateEdgesOnSelect={elevateEdgesOnSelect}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useCallback } from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { adjustEdgeZIndex, isEdgeVisible } from '@xyflow/system';
|
||||
import { isEdgeVisible } from '@xyflow/system';
|
||||
|
||||
import { useStore } from '../hooks/useStore';
|
||||
import { type Edge, type ReactFlowState } from '../types';
|
||||
|
||||
function useVisibleEdges(onlyRenderVisible: boolean, elevateEdgesOnSelect: boolean): Edge[] {
|
||||
function useVisibleEdges(onlyRenderVisible: boolean): Edge[] {
|
||||
const edges = useStore(
|
||||
useCallback(
|
||||
(s: ReactFlowState) => {
|
||||
@@ -29,9 +29,9 @@ function useVisibleEdges(onlyRenderVisible: boolean, elevateEdgesOnSelect: boole
|
||||
})
|
||||
: s.edges;
|
||||
|
||||
return visibleEdges.map((edge) => adjustEdgeZIndex(edge, s.nodeLookup, elevateEdgesOnSelect));
|
||||
return visibleEdges;
|
||||
},
|
||||
[onlyRenderVisible, elevateEdgesOnSelect]
|
||||
[onlyRenderVisible]
|
||||
),
|
||||
shallow
|
||||
);
|
||||
|
||||
@@ -78,6 +78,7 @@ export type EdgeWrapperProps<T = any> = Omit<Edge<T>, 'sourceHandle' | 'targetHa
|
||||
pathOptions?: BezierPathOptions | SmoothStepPathOptions;
|
||||
edgeTypes?: EdgeTypes;
|
||||
onError?: OnError;
|
||||
elevateEdgesOnSelect?: boolean;
|
||||
};
|
||||
|
||||
export type DefaultEdgeOptions = DefaultEdgeOptionsBase<Edge>;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { derived } from 'svelte/store';
|
||||
import { isEdgeVisible, getEdgePosition, adjustEdgeZIndex } from '@xyflow/system';
|
||||
import { isEdgeVisible, getEdgePosition, getEdgeZIndex } from '@xyflow/system';
|
||||
|
||||
import type { EdgeLayouted } from '$lib/types';
|
||||
import type { SvelteFlowStoreState } from './types';
|
||||
@@ -41,15 +41,8 @@ export function getVisibleEdges(store: SvelteFlowStoreState) {
|
||||
);
|
||||
|
||||
return derived(
|
||||
[
|
||||
visibleEdges,
|
||||
store.nodes,
|
||||
store.nodeLookup,
|
||||
store.connectionMode,
|
||||
store.onlyRenderVisibleElements,
|
||||
store.onerror
|
||||
],
|
||||
([visibleEdges, , nodeLookup, connectionMode, onlyRenderVisibleElements, onerror]) => {
|
||||
[visibleEdges, store.nodes, store.nodeLookup, store.connectionMode, store.onerror],
|
||||
([visibleEdges, , nodeLookup, connectionMode, onerror]) => {
|
||||
const layoutedEdges = visibleEdges.reduce<EdgeLayouted[]>((res, edge) => {
|
||||
const sourceNode = nodeLookup.get(edge.source);
|
||||
const targetNode = nodeLookup.get(edge.target);
|
||||
@@ -70,7 +63,8 @@ export function getVisibleEdges(store: SvelteFlowStoreState) {
|
||||
|
||||
if (edgePosition) {
|
||||
res.push({
|
||||
...adjustEdgeZIndex(edge, nodeLookup, onlyRenderVisibleElements),
|
||||
...edge,
|
||||
zIndex: getEdgeZIndex(edge.selected, edge.zIndex, sourceNode, targetNode, false),
|
||||
...edgePosition
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,26 +23,23 @@ export function getEdgeCenter({
|
||||
return [centerX, centerY, xOffset, yOffset];
|
||||
}
|
||||
|
||||
export function adjustEdgeZIndex(edge: EdgeBase, nodeLookup: Map<string, NodeBase>, elevateEdgesOnSelect: boolean) {
|
||||
const hasZIndex = isNumeric(edge.zIndex);
|
||||
let z = hasZIndex ? edge.zIndex! : 0;
|
||||
export function getEdgeZIndex(
|
||||
selected: boolean | undefined,
|
||||
zIndex: number | undefined,
|
||||
sourceNode: NodeBase,
|
||||
targetNode: NodeBase,
|
||||
elevateEdgesOnSelect?: boolean
|
||||
) {
|
||||
const hasZIndex = isNumeric(zIndex);
|
||||
let nextZIndex = hasZIndex ? zIndex! : 0;
|
||||
|
||||
if (elevateEdgesOnSelect) {
|
||||
const targetNode = nodeLookup.get(edge.target)!;
|
||||
const sourceNode = nodeLookup.get(edge.source)!;
|
||||
const edgeOrConnectedNodeSelected = edge.selected || targetNode?.selected || sourceNode?.selected;
|
||||
const edgeOrConnectedNodeSelected = selected || targetNode?.selected || sourceNode?.selected;
|
||||
const selectedZIndex = Math.max(sourceNode?.[internalsSymbol]?.z || 0, targetNode?.[internalsSymbol]?.z || 0, 1000);
|
||||
z = (hasZIndex ? edge.zIndex! : 0) + (edgeOrConnectedNodeSelected ? selectedZIndex : 0);
|
||||
|
||||
if (edge.zIndex !== z) {
|
||||
return {
|
||||
...edge,
|
||||
zIndex: z,
|
||||
};
|
||||
}
|
||||
nextZIndex = (hasZIndex ? zIndex! : 0) + (edgeOrConnectedNodeSelected ? selectedZIndex : 0);
|
||||
}
|
||||
|
||||
return edge;
|
||||
return nextZIndex;
|
||||
}
|
||||
|
||||
type IsEdgeVisibleParams = {
|
||||
|
||||
Reference in New Issue
Block a user