feat(svelte): add subflows
This commit is contained in:
@@ -89,14 +89,16 @@ export function calcNextPosition(
|
||||
if (node.parentNode && node.width && node.height) {
|
||||
const parent = nodeInternals.get(node.parentNode);
|
||||
const parentOrigin = parent?.origin || nodeOrigin;
|
||||
const currNodeOrigin = node.origin || nodeOrigin;
|
||||
|
||||
const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, parentOrigin).positionAbsolute;
|
||||
currentExtent =
|
||||
parent && isNumeric(parentX) && isNumeric(parentY) && isNumeric(parent.width) && isNumeric(parent.height)
|
||||
? [
|
||||
[parentX + node.width * parentOrigin[0], parentY + node.height * parentOrigin[1]],
|
||||
[parentX + node.width * currNodeOrigin[0], parentY + node.height * currNodeOrigin[1]],
|
||||
[
|
||||
parentX + parent.width - node.width + node.width * parentOrigin[0],
|
||||
parentY + parent.height - node.height + node.height * parentOrigin[1],
|
||||
parentX + parent.width - node.width + node.width * currNodeOrigin[0],
|
||||
parentY + parent.height - node.height + node.height * currNodeOrigin[1],
|
||||
],
|
||||
]
|
||||
: currentExtent;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
'drag-n-drop',
|
||||
'overview',
|
||||
'stress',
|
||||
'subflows',
|
||||
'usesvelteflow',
|
||||
'validation'
|
||||
];
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { get, type Writable } from 'svelte/store';
|
||||
import { get } from 'svelte/store';
|
||||
import { drag as d3Drag, type D3DragEvent, type SubjectPosition } from 'd3-drag';
|
||||
import { select } from 'd3-selection';
|
||||
import type { XYPosition, CoordinateExtent, Transform } from '@reactflow/system';
|
||||
import type { XYPosition, CoordinateExtent } from '@reactflow/system';
|
||||
|
||||
import { getDragItems, hasSelector, calcNextPosition } from './utils';
|
||||
import type { Node } from '$lib/types';
|
||||
import type { SvelteFlowStore } from '$lib/store/types';
|
||||
|
||||
export type UseDragData = { dx: number; dy: number };
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import type { CoordinateExtent, NodeDragItem, NodeOrigin, XYPosition } from '@reactflow/system';
|
||||
import { clampPosition, isNumeric } from '@reactflow/utils';
|
||||
import {
|
||||
errorMessages,
|
||||
type CoordinateExtent,
|
||||
type NodeDragItem,
|
||||
type NodeOrigin,
|
||||
type XYPosition
|
||||
} from '@reactflow/system';
|
||||
import { clampPosition, devWarn, getNodePositionWithOrigin, isNumeric } from '@reactflow/utils';
|
||||
|
||||
import type { Node } from '$lib/types';
|
||||
|
||||
@@ -65,16 +71,28 @@ export function calcNextPosition(
|
||||
node: NodeDragItem | Node,
|
||||
nextPosition: XYPosition,
|
||||
nodes: Node[],
|
||||
nodeExtent?: CoordinateExtent,
|
||||
nodeOrigin: NodeOrigin = [0, 0]
|
||||
nodeExtent?: CoordinateExtent
|
||||
): { position: XYPosition; positionAbsolute: XYPosition } {
|
||||
let currentExtent = node.extent || nodeExtent;
|
||||
|
||||
if (node.extent === 'parent') {
|
||||
if (node.parentNode && node.width && node.height) {
|
||||
const parent = nodes.find((n) => n.id === node.parentNode)!;
|
||||
const parentOrigin = parent.origin || nodeOrigin;
|
||||
const { x: parentX, y: parentY } = parent.positionAbsolute!;
|
||||
const parent = nodes.find((n) => n.id === node.parentNode);
|
||||
const parentOrigin = parent?.origin || [0, 0];
|
||||
const nodeOrigin = node.origin || [0, 0];
|
||||
const { x: parentX, y: parentY } = getNodePositionWithOrigin(
|
||||
parent,
|
||||
parentOrigin
|
||||
).positionAbsolute;
|
||||
console.log({
|
||||
parentX,
|
||||
parentY,
|
||||
parentW: parent?.width,
|
||||
parentH: parent?.height,
|
||||
nodeW: node.width,
|
||||
nodeH: node.height,
|
||||
parentOrigin: parentOrigin[0]
|
||||
});
|
||||
currentExtent =
|
||||
parent &&
|
||||
isNumeric(parentX) &&
|
||||
@@ -82,19 +100,23 @@ export function calcNextPosition(
|
||||
isNumeric(parent.width) &&
|
||||
isNumeric(parent.height)
|
||||
? [
|
||||
[parentX + node.width * parentOrigin[0], parentY + node.height * parentOrigin[1]],
|
||||
[parentX + node.width * nodeOrigin[0], parentY + node.height * nodeOrigin[1]],
|
||||
[
|
||||
parentX + parent.width! - node.width + node.width * parentOrigin[0],
|
||||
parentY + parent.height! - node.height + node.height * parentOrigin[1]
|
||||
parentX + parent.width - node.width + node.width * nodeOrigin[0],
|
||||
parentY + parent.height - node.height + node.height * nodeOrigin[1]
|
||||
]
|
||||
]
|
||||
: currentExtent;
|
||||
} else {
|
||||
devWarn('005', errorMessages['005']());
|
||||
currentExtent = nodeExtent;
|
||||
}
|
||||
} else if (node.extent && node.parentNode) {
|
||||
const parent = nodes.find((n) => n.id === node.parentNode)!;
|
||||
const { x: parentX, y: parentY } = parent.positionAbsolute!;
|
||||
const parent = nodes.find((n) => n.id === node.parentNode);
|
||||
const { x: parentX, y: parentY } = getNodePositionWithOrigin(
|
||||
parent,
|
||||
parent?.origin || [0, 0]
|
||||
).positionAbsolute;
|
||||
currentExtent = [
|
||||
[node.extent[0][0] + parentX, node.extent[0][1] + parentY],
|
||||
[node.extent[1][0] + parentX, node.extent[1][1] + parentY]
|
||||
@@ -104,8 +126,8 @@ export function calcNextPosition(
|
||||
let parentPosition = { x: 0, y: 0 };
|
||||
|
||||
if (node.parentNode) {
|
||||
const parent = nodes.find((n) => n.id === node.parentNode)!;
|
||||
parentPosition = parent.positionAbsolute!;
|
||||
const parent = nodes.find((n) => n.id === node.parentNode);
|
||||
parentPosition = getNodePositionWithOrigin(parent, parent?.origin || [0, 0]).positionAbsolute;
|
||||
}
|
||||
|
||||
const positionAbsolute = currentExtent
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
export let width: NodeWrapperProps['width'] = undefined;
|
||||
export let height: NodeWrapperProps['height'] = undefined;
|
||||
export let type: NodeWrapperProps['type'] = 'default';
|
||||
export let isParent: NodeWrapperProps['isParent'] = false;
|
||||
export let positionAbsolute: NodeWrapperProps['positionAbsolute'] = undefined;
|
||||
export let positionOrigin: NodeWrapperProps['positionOrigin'] = undefined;
|
||||
export let sourcePosition: NodeWrapperProps['sourcePosition'] = undefined;
|
||||
export let targetPosition: NodeWrapperProps['targetPosition'] = undefined;
|
||||
|
||||
let className: string = '';
|
||||
export { className as class };
|
||||
|
||||
@@ -77,12 +77,13 @@
|
||||
use:drag={{ nodeId: id, nodes, snapGrid, transform, updateNodePositions }}
|
||||
bind:this={nodeRef}
|
||||
data-id={id}
|
||||
class={cc(['svelte-flow__node', `svelte-flow__node-${type}`, className])}
|
||||
class={cc(['svelte-flow__node', `svelte-flow__node-${type || 'default'}`, className])}
|
||||
class:initializing={!width && !height}
|
||||
class:dragging
|
||||
class:selected
|
||||
class:draggable
|
||||
class:connectable
|
||||
class:parent={isParent}
|
||||
style:transform={`translate(${positionOrigin?.x ?? 0}px, ${positionOrigin?.y ?? 0}px)`}
|
||||
{style}
|
||||
on:click={onSelectNodeHandler}
|
||||
|
||||
@@ -21,4 +21,5 @@ export type NodeWrapperProps = Pick<
|
||||
positionOrigin?: XYPosition;
|
||||
'on:nodeclick'?: (event: MouseEvent) => void;
|
||||
resizeObserver?: ResizeObserver | null;
|
||||
isParent?: boolean;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy } from 'svelte';
|
||||
import { internalsSymbol } from '@reactflow/system';
|
||||
import { getPositionWithOrigin } from '@reactflow/utils';
|
||||
|
||||
import { NodeWrapper } from '$lib/components/NodeWrapper';
|
||||
@@ -41,6 +42,7 @@
|
||||
connectable={node.connectable || node.connectable === undefined}
|
||||
positionAbsolute={node.positionAbsolute}
|
||||
positionOrigin={posOrigin}
|
||||
isParent={!!node[internalsSymbol]?.isParent}
|
||||
width={node.width}
|
||||
height={node.height}
|
||||
style={node.style}
|
||||
|
||||
@@ -8,55 +8,55 @@ import type { SvelteFlowStoreState } from './types';
|
||||
|
||||
export function getEdgesLayouted(store: SvelteFlowStoreState) {
|
||||
return derived([store.edges, store.nodes], ([edges, nodes]) => {
|
||||
return edges
|
||||
.map((edge) => {
|
||||
const sourceNode = nodes.find((node) => node.id === edge.source);
|
||||
const targetNode = nodes.find((node) => node.id === edge.target);
|
||||
const [sourceNodeRect, sourceHandleBounds, sourceIsValid] = getNodeData(sourceNode);
|
||||
const [targetNodeRect, targetHandleBounds, targetIsValid] = getNodeData(targetNode);
|
||||
return edges.reduce<EdgeLayouted[]>((res, edge) => {
|
||||
const sourceNode = nodes.find((node) => node.id === edge.source);
|
||||
const targetNode = nodes.find((node) => node.id === edge.target);
|
||||
const [sourceNodeRect, sourceHandleBounds, sourceIsValid] = getNodeData(sourceNode);
|
||||
const [targetNodeRect, targetHandleBounds, targetIsValid] = getNodeData(targetNode);
|
||||
|
||||
if (!sourceIsValid || !targetIsValid) {
|
||||
return null;
|
||||
}
|
||||
if (!sourceIsValid || !targetIsValid) {
|
||||
return res;
|
||||
}
|
||||
|
||||
const edgeType = edge.type || 'default';
|
||||
const edgeType = edge.type || 'default';
|
||||
|
||||
const targetNodeHandles = targetHandleBounds!.target;
|
||||
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 targetNodeHandles = targetHandleBounds!.target;
|
||||
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;
|
||||
|
||||
if (!sourceHandle || !targetHandle) {
|
||||
return null;
|
||||
}
|
||||
if (!sourceHandle || !targetHandle) {
|
||||
return res;
|
||||
}
|
||||
|
||||
const { sourceX, sourceY, targetX, targetY } = getEdgePositions(
|
||||
sourceNodeRect,
|
||||
sourceHandle,
|
||||
sourcePosition,
|
||||
targetNodeRect,
|
||||
targetHandle,
|
||||
targetPosition
|
||||
);
|
||||
const { sourceX, sourceY, targetX, targetY } = getEdgePositions(
|
||||
sourceNodeRect,
|
||||
sourceHandle,
|
||||
sourcePosition,
|
||||
targetNodeRect,
|
||||
targetHandle,
|
||||
targetPosition
|
||||
);
|
||||
|
||||
// we nee to do this to match the types
|
||||
const sourceHandleId = edge.sourceHandle;
|
||||
const targetHandleId = edge.targetHandle;
|
||||
// we nee to do this to match the types
|
||||
const sourceHandleId = edge.sourceHandle;
|
||||
const targetHandleId = edge.targetHandle;
|
||||
|
||||
return {
|
||||
...edge,
|
||||
type: edgeType,
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
targetY,
|
||||
sourcePosition,
|
||||
targetPosition,
|
||||
sourceHandleId,
|
||||
targetHandleId
|
||||
};
|
||||
})
|
||||
.filter((e) => e !== null) as EdgeLayouted[];
|
||||
res.push({
|
||||
...edge,
|
||||
type: edgeType,
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
targetY,
|
||||
sourcePosition,
|
||||
targetPosition,
|
||||
sourceHandleId,
|
||||
targetHandleId
|
||||
} as EdgeLayouted);
|
||||
|
||||
return res;
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
} from '@reactflow/utils';
|
||||
|
||||
import { addEdge as addEdgeUtil } from '$lib/utils';
|
||||
import type { EdgeTypes, NodeTypes, Node, Edge, ConnectionData } from '$lib/types';
|
||||
import type { EdgeTypes, NodeTypes, Node, Edge, ConnectionData, FitViewOptions } from '$lib/types';
|
||||
import { getEdgesLayouted } from './edges-layouted';
|
||||
import { getConnectionPath } from './connection-path';
|
||||
import {
|
||||
@@ -102,15 +102,20 @@ export function createStore(params: CreateStoreParams): SvelteFlowStore {
|
||||
);
|
||||
|
||||
if (doUpdate) {
|
||||
node[internalsSymbol] = {
|
||||
...node[internalsSymbol],
|
||||
handleBounds: {
|
||||
source: getHandleBounds('.source', update.nodeElement, zoom, node.origin),
|
||||
target: getHandleBounds('.target', update.nodeElement, zoom, node.origin)
|
||||
const newNode = {
|
||||
...node,
|
||||
width: dimensions.width,
|
||||
height: dimensions.height,
|
||||
[internalsSymbol]: {
|
||||
...node[internalsSymbol],
|
||||
handleBounds: {
|
||||
source: getHandleBounds('.source', update.nodeElement, zoom, node.origin),
|
||||
target: getHandleBounds('.target', update.nodeElement, zoom, node.origin)
|
||||
}
|
||||
}
|
||||
};
|
||||
node.width = dimensions.width;
|
||||
node.height = dimensions.height;
|
||||
|
||||
return newNode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +126,7 @@ export function createStore(params: CreateStoreParams): SvelteFlowStore {
|
||||
|
||||
const fitViewOnInitDone =
|
||||
get(store.fitViewOnInitDone) ||
|
||||
(get(store.fitViewOnInit) && !!d3Zoom && !!d3Selection && fitView());
|
||||
(get(store.fitViewOnInit) && !!d3Zoom && !!d3Selection && fitView({ nodes: nextNodes }));
|
||||
|
||||
store.fitViewOnInitDone.set(fitViewOnInitDone);
|
||||
store.nodes.set(nextNodes);
|
||||
@@ -162,16 +167,18 @@ export function createStore(params: CreateStoreParams): SvelteFlowStore {
|
||||
}
|
||||
}
|
||||
|
||||
function fitView() {
|
||||
function fitView(options?: FitViewOptions) {
|
||||
const { zoom: d3Zoom, selection: d3Selection } = get(store.d3);
|
||||
|
||||
if (!d3Zoom || !d3Selection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const fitViewNodes = options?.nodes || get(store.nodes);
|
||||
|
||||
return fitViewUtil(
|
||||
{
|
||||
nodes: get(store.nodes),
|
||||
nodes: fitViewNodes as Node[],
|
||||
width: get(store.width),
|
||||
height: get(store.height),
|
||||
minZoom: 0.2,
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
} from '@reactflow/system';
|
||||
|
||||
import type { initialStoreState } from './initial-store';
|
||||
import type { Node, Edge, ConnectionData, NodeTypes, EdgeTypes } from '$lib/types';
|
||||
import type { Node, Edge, ConnectionData, NodeTypes, EdgeTypes, FitViewOptions } from '$lib/types';
|
||||
import type { Writable } from 'svelte/store';
|
||||
|
||||
export type SvelteFlowStoreActions = {
|
||||
@@ -18,7 +18,7 @@ export type SvelteFlowStoreActions = {
|
||||
zoomOut: (options?: ViewportHelperFunctionOptions) => void;
|
||||
setMinZoom: (minZoom: number) => void;
|
||||
setMaxZoom: (maxZoom: number) => void;
|
||||
fitView: (options?: ViewportHelperFunctionOptions) => boolean;
|
||||
fitView: (options?: FitViewOptions) => boolean;
|
||||
updateNodePositions: (
|
||||
nodeDragItems: NodeDragItem[],
|
||||
positionChanged?: boolean,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { writable, type Writable } from 'svelte/store';
|
||||
import {
|
||||
isNodeBase,
|
||||
isEdgeBase,
|
||||
@@ -5,10 +6,12 @@ import {
|
||||
getOutgoersBase,
|
||||
getIncomersBase,
|
||||
updateEdgeBase,
|
||||
getConnectedEdgesBase
|
||||
getConnectedEdgesBase,
|
||||
isNumeric,
|
||||
getNodePositionWithOrigin
|
||||
} from '@reactflow/utils';
|
||||
import { internalsSymbol, type XYZPosition } from '@reactflow/system';
|
||||
import type { DefaultEdgeOptions, DefaultNodeOptions, Edge, Node } from '$lib/types';
|
||||
import { writable, type Writable } from 'svelte/store';
|
||||
|
||||
export const isNode = isNodeBase<Node, Edge>;
|
||||
export const isEdge = isEdgeBase<Node, Edge>;
|
||||
@@ -27,11 +30,53 @@ export const createNodes = (
|
||||
let defaults = defaultOptions || {};
|
||||
|
||||
const _set: typeof set = (nds: Node[]) => {
|
||||
const nextNodes = defaults ? nds.map((node) => ({ ...defaults, ...node })) : nds;
|
||||
// @todo calculate absolute position based on parent / child relation
|
||||
const nextNodesLayouted = nextNodes.map((n) => ({ ...n, positionAbsolute: n.position }));
|
||||
const parentNodes: Record<string, boolean> = {};
|
||||
|
||||
value = nextNodesLayouted;
|
||||
const nextNodes = nds.map((n) => {
|
||||
const node: Node = { ...defaults, ...n, positionAbsolute: n.position };
|
||||
const z = (isNumeric(node.zIndex) ? node.zIndex : 0) + (node.selected ? 1 : 0);
|
||||
|
||||
if (node.parentNode) {
|
||||
parentNodes[node.parentNode] = true;
|
||||
}
|
||||
|
||||
Object.defineProperty(node, internalsSymbol, {
|
||||
value: {
|
||||
handleBounds: node?.[internalsSymbol]?.handleBounds,
|
||||
z
|
||||
}
|
||||
});
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
const nodesWithPositions = nextNodes.map((node) => {
|
||||
if (node.parentNode && !parentNodes[node.parentNode]) {
|
||||
throw new Error(`Parent node ${node.parentNode} not found`);
|
||||
}
|
||||
|
||||
if (node.parentNode || parentNodes?.[node.id]) {
|
||||
const { x, y, z } = calculateXYZPosition(node, nextNodes, {
|
||||
...node.position,
|
||||
z: node[internalsSymbol]?.z ?? 0
|
||||
});
|
||||
|
||||
node.positionAbsolute = {
|
||||
x,
|
||||
y
|
||||
};
|
||||
|
||||
node[internalsSymbol]!.z = z;
|
||||
|
||||
if (parentNodes?.[node.id]) {
|
||||
node[internalsSymbol]!.isParent = true;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
|
||||
value = nodesWithPositions;
|
||||
|
||||
set(value);
|
||||
};
|
||||
@@ -81,3 +126,20 @@ export const createEdges = (
|
||||
setDefaultOptions
|
||||
};
|
||||
};
|
||||
|
||||
function calculateXYZPosition(node: Node, nodes: Node[], result: XYZPosition): XYZPosition {
|
||||
if (!node.parentNode) {
|
||||
return result;
|
||||
}
|
||||
const parentNode = nodes.find((n) => n.id === node.parentNode)!;
|
||||
const parentNodePosition = getNodePositionWithOrigin(parentNode, parentNode?.origin);
|
||||
|
||||
return calculateXYZPosition(parentNode, nodes, {
|
||||
x: (result.x ?? 0) + parentNodePosition.x,
|
||||
y: (result.y ?? 0) + parentNodePosition.y,
|
||||
z:
|
||||
(parentNode[internalsSymbol]?.z ?? 0) > (result.z ?? 0)
|
||||
? parentNode[internalsSymbol]?.z ?? 0
|
||||
: result.z ?? 0
|
||||
});
|
||||
}
|
||||
|
||||
141
packages/svelte/src/routes/subflows/+page.svelte
Normal file
141
packages/svelte/src/routes/subflows/+page.svelte
Normal file
@@ -0,0 +1,141 @@
|
||||
<script lang="ts">
|
||||
import SvelteFlow, {
|
||||
SvelteFlowProvider,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
Minimap,
|
||||
createNodes,
|
||||
createEdges,
|
||||
type NodeTypes,
|
||||
} from '../../lib/index';
|
||||
import { DebugNode } from './DebugNode';
|
||||
|
||||
const nodeTypes: NodeTypes = {
|
||||
default: DebugNode,
|
||||
};
|
||||
|
||||
const nodes = createNodes([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Node 1' },
|
||||
position: { x: 250, y: 5 },
|
||||
origin: [0.5, 0.5],
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
data: { label: 'Node 4' },
|
||||
position: { x: 100, y: 200 },
|
||||
style: "width:500px; height:300px;"
|
||||
},
|
||||
{
|
||||
id: '4a',
|
||||
data: { label: 'Node 4a' },
|
||||
position: { x: 15, y: 15 },
|
||||
parentNode: '4',
|
||||
extent: [
|
||||
[0, 0],
|
||||
[100, 100],
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '4b',
|
||||
data: { label: 'Node 4b' },
|
||||
position: { x: 100, y: 60 },
|
||||
style: "width: 300px; height: 200px;",
|
||||
parentNode: '4',
|
||||
},
|
||||
{
|
||||
id: '4b1',
|
||||
data: { label: 'Node 4b1' },
|
||||
position: { x: 40, y: 20 },
|
||||
parentNode: '4b',
|
||||
},
|
||||
{
|
||||
id: '4b2',
|
||||
data: { label: 'Node 4b2' },
|
||||
position: { x: 20, y: 100 },
|
||||
parentNode: '4b',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
type: 'group',
|
||||
data: { label: 'Node 5' },
|
||||
position: { x: 650, y: 250 },
|
||||
style: "width: 400px; height: 150px",
|
||||
zIndex: 1000,
|
||||
},
|
||||
{
|
||||
id: '5a',
|
||||
data: { label: 'Node 5a' },
|
||||
position: { x: 0, y: 0 },
|
||||
parentNode: '5',
|
||||
extent: 'parent',
|
||||
},
|
||||
{
|
||||
id: '5b',
|
||||
data: { label: 'Node 5b' },
|
||||
position: { x: 225, y: 50 },
|
||||
parentNode: '5',
|
||||
expandParent: true,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: { label: 'Node 2' },
|
||||
position: { x: 100, y: 100 },
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: { label: 'Node 3' },
|
||||
position: { x: 400, y: 100 },
|
||||
}
|
||||
]);
|
||||
|
||||
const edges = createEdges([
|
||||
{
|
||||
id: 'e1-2',
|
||||
source: '1',
|
||||
target: '2',
|
||||
// markerEnd: {
|
||||
// type: MarkerType.Arrow,
|
||||
// strokeWidth: 2,
|
||||
// width: 15,
|
||||
// height: 15,
|
||||
// color: '#f00',
|
||||
// },
|
||||
},
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
{ id: 'e3-4', source: '3', target: '4', zIndex: 100 },
|
||||
{ id: 'e3-4b', source: '3', target: '4b' },
|
||||
{ id: 'e4a-4b1', source: '4a', target: '4b1' },
|
||||
{ id: 'e4a-4b2', source: '4a', target: '4b2', zIndex: 100 },
|
||||
{ id: 'e4b1-4b2', source: '4b1', target: '4b2' },
|
||||
], { animated: true });
|
||||
|
||||
$: {
|
||||
console.log($nodes)
|
||||
}
|
||||
</script>
|
||||
|
||||
<SvelteFlowProvider
|
||||
{nodes}
|
||||
{edges}
|
||||
>
|
||||
<SvelteFlow
|
||||
{nodeTypes}
|
||||
fitView
|
||||
minZoom={0.1}
|
||||
maxZoom={2.5}
|
||||
>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
<Minimap />
|
||||
</SvelteFlow>
|
||||
</SvelteFlowProvider>
|
||||
|
||||
<style>
|
||||
:global(.svelte-flow .svelte-flow__node.parent) {
|
||||
background-color: rgba(220,220,255,0.4)
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { Handle, Position } from '../../../lib/index';
|
||||
|
||||
export let id: string;
|
||||
export let xPos: number = 0;
|
||||
export let yPos: number = 0;
|
||||
export let zIndex: number = 0;
|
||||
</script>
|
||||
|
||||
<Handle type="target" position={Position.Top} />
|
||||
<div>{id}</div>
|
||||
<div>
|
||||
x:{Math.round(xPos || 0)} y:{Math.round(yPos || 0)} z:{zIndex}
|
||||
</div>
|
||||
<Handle type="source" position={Position.Bottom} />
|
||||
|
||||
|
||||
<style>
|
||||
.custom {
|
||||
background: #ffcc00;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
1
packages/svelte/src/routes/subflows/DebugNode/index.ts
Normal file
1
packages/svelte/src/routes/subflows/DebugNode/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as DebugNode } from './DebugNode.svelte';
|
||||
@@ -80,6 +80,7 @@ export type NodeDragItem = {
|
||||
extent?: 'parent' | CoordinateExtent;
|
||||
parentNode?: string;
|
||||
dragging?: boolean;
|
||||
origin?: NodeOrigin;
|
||||
};
|
||||
|
||||
export type NodeOrigin = [number, number];
|
||||
|
||||
Reference in New Issue
Block a user