refactor(svelte/react): use edge layouting vanilla helpers
This commit is contained in:
@@ -1,4 +1,14 @@
|
||||
import { Position, type HandleElement, type MarkerType, type Rect, type XYPosition } from '../../types';
|
||||
import { Transform, internalsSymbol } from '../..';
|
||||
import {
|
||||
Position,
|
||||
type HandleElement,
|
||||
type MarkerType,
|
||||
type Rect,
|
||||
type XYPosition,
|
||||
BaseEdge,
|
||||
BaseNode,
|
||||
} from '../../types';
|
||||
import { isNumeric, rectToBox } from '../utils';
|
||||
|
||||
// this is used for straight edges and simple smoothstep edges (LTR, RTL, BTT, TTB)
|
||||
export function getEdgeCenter({
|
||||
@@ -72,3 +82,115 @@ export function getHandle(bounds: HandleElement[], handleId?: string | null): Ha
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const defaultEdgeTree = [{ level: 0, isMaxLevel: true, edges: [] }];
|
||||
|
||||
export type GroupedEdges<EdgeType extends BaseEdge> = {
|
||||
edges: EdgeType[];
|
||||
level: number;
|
||||
isMaxLevel: boolean;
|
||||
};
|
||||
|
||||
export function groupEdgesByZLevel<EdgeType extends BaseEdge>(
|
||||
edges: EdgeType[],
|
||||
nodes: Map<string, BaseNode> | BaseNode[],
|
||||
elevateEdgesOnSelect = false
|
||||
): GroupedEdges<EdgeType>[] {
|
||||
let maxLevel = -1;
|
||||
|
||||
const isNodeInternals = 'get' in nodes;
|
||||
|
||||
const levelLookup = edges.reduce<Record<string, EdgeType[]>>((tree, edge) => {
|
||||
const hasZIndex = isNumeric(edge.zIndex);
|
||||
let z = hasZIndex ? edge.zIndex! : 0;
|
||||
|
||||
if (elevateEdgesOnSelect) {
|
||||
z = hasZIndex
|
||||
? edge.zIndex!
|
||||
: Math.max(
|
||||
(isNodeInternals ? nodes.get(edge.source) : nodes.find((n) => n.id === edge.source))?.[internalsSymbol]
|
||||
?.z || 0,
|
||||
(isNodeInternals ? nodes.get(edge.target) : nodes.find((n) => n.id === edge.target))?.[internalsSymbol]
|
||||
?.z || 0
|
||||
);
|
||||
}
|
||||
|
||||
if (tree[z]) {
|
||||
tree[z].push(edge);
|
||||
} else {
|
||||
tree[z] = [edge];
|
||||
}
|
||||
|
||||
maxLevel = z > maxLevel ? z : maxLevel;
|
||||
|
||||
return tree;
|
||||
}, {});
|
||||
|
||||
const edgeTree = Object.entries(levelLookup).map(([key, edges]) => {
|
||||
const level = +key;
|
||||
|
||||
return {
|
||||
edges,
|
||||
level,
|
||||
isMaxLevel: level === maxLevel,
|
||||
};
|
||||
});
|
||||
|
||||
if (edgeTree.length === 0) {
|
||||
return defaultEdgeTree;
|
||||
}
|
||||
|
||||
return edgeTree;
|
||||
}
|
||||
|
||||
type IsEdgeVisibleParams = {
|
||||
sourcePos: XYPosition;
|
||||
targetPos: XYPosition;
|
||||
sourceWidth: number;
|
||||
sourceHeight: number;
|
||||
targetWidth: number;
|
||||
targetHeight: number;
|
||||
width: number;
|
||||
height: number;
|
||||
transform: Transform;
|
||||
};
|
||||
|
||||
export function isEdgeVisible({
|
||||
sourcePos,
|
||||
targetPos,
|
||||
sourceWidth,
|
||||
sourceHeight,
|
||||
targetWidth,
|
||||
targetHeight,
|
||||
width,
|
||||
height,
|
||||
transform,
|
||||
}: IsEdgeVisibleParams): boolean {
|
||||
const edgeBox = {
|
||||
x: Math.min(sourcePos.x, targetPos.x),
|
||||
y: Math.min(sourcePos.y, targetPos.y),
|
||||
x2: Math.max(sourcePos.x + sourceWidth, targetPos.x + targetWidth),
|
||||
y2: Math.max(sourcePos.y + sourceHeight, targetPos.y + targetHeight),
|
||||
};
|
||||
|
||||
if (edgeBox.x === edgeBox.x2) {
|
||||
edgeBox.x2 += 1;
|
||||
}
|
||||
|
||||
if (edgeBox.y === edgeBox.y2) {
|
||||
edgeBox.y2 += 1;
|
||||
}
|
||||
|
||||
const viewBox = rectToBox({
|
||||
x: (0 - transform[0]) / transform[2],
|
||||
y: (0 - transform[1]) / transform[2],
|
||||
width: width / transform[2],
|
||||
height: height / transform[2],
|
||||
});
|
||||
|
||||
const xOverlap = Math.max(0, Math.min(viewBox.x2, edgeBox.x2) - Math.max(viewBox.x, edgeBox.x));
|
||||
const yOverlap = Math.max(0, Math.min(viewBox.y2, edgeBox.y2) - Math.max(viewBox.y, edgeBox.y));
|
||||
const overlappingArea = Math.ceil(xOverlap * yOverlap);
|
||||
|
||||
return overlappingArea > 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user