Update getInternalNodesBounds and examples
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { MouseEvent, CSSProperties, useCallback } from 'react';
|
import { MouseEvent, CSSProperties, useCallback, useState } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ReactFlow,
|
ReactFlow,
|
||||||
@@ -14,19 +14,13 @@ import {
|
|||||||
ReactFlowInstance,
|
ReactFlowInstance,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
|
Panel,
|
||||||
} from '@xyflow/react';
|
} from '@xyflow/react';
|
||||||
|
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
|
const onInit = (reactFlowInstance: ReactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
|
||||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||||
|
|
||||||
const buttonStyle: CSSProperties = {
|
|
||||||
position: 'absolute',
|
|
||||||
left: 10,
|
|
||||||
top: 10,
|
|
||||||
zIndex: 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
const CustomMiniMapNode = ({ x, y, width, height }: MiniMapNodeProps) => {
|
const CustomMiniMapNode = ({ x, y, width, height }: MiniMapNodeProps) => {
|
||||||
return <circle cx={x} cy={y} r={Math.max(width, height) / 2} fill="#ffcc00" />;
|
return <circle cx={x} cy={y} r={Math.max(width, height) / 2} fill="#ffcc00" />;
|
||||||
};
|
};
|
||||||
@@ -34,6 +28,7 @@ const CustomMiniMapNode = ({ x, y, width, height }: MiniMapNodeProps) => {
|
|||||||
const CustomMiniMapNodeFlow = () => {
|
const CustomMiniMapNodeFlow = () => {
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState<Node>([]);
|
const [nodes, setNodes, onNodesChange] = useNodesState<Node>([]);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>([]);
|
const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>([]);
|
||||||
|
const [hideAllNodes, setHideAllNodes] = useState(false);
|
||||||
|
|
||||||
const onConnect = useCallback((params: Connection | Edge) => setEdges((els) => addEdge(params, els)), [setEdges]);
|
const onConnect = useCallback((params: Connection | Edge) => setEdges((els) => addEdge(params, els)), [setEdges]);
|
||||||
const addRandomNode = () => {
|
const addRandomNode = () => {
|
||||||
@@ -45,10 +40,17 @@ const CustomMiniMapNodeFlow = () => {
|
|||||||
x: Math.random() * window.innerWidth,
|
x: Math.random() * window.innerWidth,
|
||||||
y: Math.random() * window.innerHeight,
|
y: Math.random() * window.innerHeight,
|
||||||
},
|
},
|
||||||
|
hidden: hideAllNodes,
|
||||||
};
|
};
|
||||||
setNodes((nds) => nds.concat(newNode));
|
setNodes((nds) => nds.concat(newNode));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleHideAllNodes = () => {
|
||||||
|
setHideAllNodes(!hideAllNodes);
|
||||||
|
setNodes((nds) => nds.map((n) => ({ ...n, hidden: hideAllNodes })));
|
||||||
|
setEdges((eds) => eds.map((e) => ({ ...e, hidden: hideAllNodes })));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
@@ -65,9 +67,14 @@ const CustomMiniMapNodeFlow = () => {
|
|||||||
<Background variant={BackgroundVariant.Lines} />
|
<Background variant={BackgroundVariant.Lines} />
|
||||||
<MiniMap nodeComponent={CustomMiniMapNode} />
|
<MiniMap nodeComponent={CustomMiniMapNode} />
|
||||||
|
|
||||||
<button type="button" onClick={addRandomNode} style={buttonStyle}>
|
<Panel position="top-left">
|
||||||
add node
|
<button type="button" onClick={addRandomNode}>
|
||||||
</button>
|
add node
|
||||||
|
</button>
|
||||||
|
<button type="button" onClick={toggleHideAllNodes}>
|
||||||
|
{hideAllNodes ? 'show all nodes' : 'hide all nodes'}
|
||||||
|
</button>
|
||||||
|
</Panel>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
'handle-connect',
|
'handle-connect',
|
||||||
'interaction',
|
'interaction',
|
||||||
'intersections',
|
'intersections',
|
||||||
|
'minimap-bug',
|
||||||
'node-toolbar',
|
'node-toolbar',
|
||||||
'node-resizer',
|
'node-resizer',
|
||||||
'overview',
|
'overview',
|
||||||
|
|||||||
@@ -4,15 +4,17 @@
|
|||||||
Background,
|
Background,
|
||||||
Controls,
|
Controls,
|
||||||
MiniMap,
|
MiniMap,
|
||||||
|
Panel,
|
||||||
type Node,
|
type Node,
|
||||||
type Edge,
|
type Edge
|
||||||
} from '@xyflow/svelte';
|
} from '@xyflow/svelte';
|
||||||
|
|
||||||
import '@xyflow/svelte/dist/style.css';
|
import '@xyflow/svelte/dist/style.css';
|
||||||
import CustomMiniMapNode from './CustomMiniMapNode.svelte';
|
import CustomMiniMapNode from './CustomMiniMapNode.svelte';
|
||||||
|
|
||||||
let nodes = $state.raw<Node[]>([]);
|
let nodes = $state.raw<Node[]>([]);
|
||||||
let edges = $state.raw<Edge[]>([]);
|
let edges = $state.raw<Edge[]>([]);
|
||||||
|
let hideAllNodes = $state(false);
|
||||||
|
|
||||||
function addRandomNode() {
|
function addRandomNode() {
|
||||||
const nodeId = (nodes.length + 1).toString();
|
const nodeId = (nodes.length + 1).toString();
|
||||||
@@ -21,28 +23,33 @@
|
|||||||
data: { label: `Node: ${nodeId}` },
|
data: { label: `Node: ${nodeId}` },
|
||||||
position: {
|
position: {
|
||||||
x: Math.random() * (typeof window !== 'undefined' ? window.innerWidth : 800),
|
x: Math.random() * (typeof window !== 'undefined' ? window.innerWidth : 800),
|
||||||
y: Math.random() * (typeof window !== 'undefined' ? window.innerHeight : 600),
|
y: Math.random() * (typeof window !== 'undefined' ? window.innerHeight : 600)
|
||||||
},
|
},
|
||||||
type: 'default'
|
type: 'default',
|
||||||
|
hidden: hideAllNodes
|
||||||
};
|
};
|
||||||
nodes = [...nodes, newNode];
|
nodes = [...nodes, newNode];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleHideAllNodes() {
|
||||||
|
hideAllNodes = !hideAllNodes;
|
||||||
|
nodes = nodes.map((node) => ({
|
||||||
|
...node,
|
||||||
|
hidden: hideAllNodes
|
||||||
|
}));
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SvelteFlow
|
<SvelteFlow bind:nodes bind:edges onlyRenderVisibleElements={true}>
|
||||||
bind:nodes
|
|
||||||
bind:edges
|
|
||||||
onlyRenderVisibleElements={true}
|
|
||||||
>
|
|
||||||
<Controls />
|
<Controls />
|
||||||
<Background />
|
<Background />
|
||||||
<MiniMap nodeComponent={CustomMiniMapNode} />
|
<MiniMap nodeComponent={CustomMiniMapNode} />
|
||||||
|
|
||||||
<button
|
<Panel position="top-left">
|
||||||
type="button"
|
<button type="button" onclick={addRandomNode}> add node </button>
|
||||||
onclick={addRandomNode}
|
|
||||||
style="position: absolute; left: 10px; top: 10px; z-index: 4;"
|
<button type="button" onclick={toggleHideAllNodes}>
|
||||||
>
|
{hideAllNodes ? 'show all nodes' : 'hide all nodes'}
|
||||||
add node
|
</button>
|
||||||
</button>
|
</Panel>
|
||||||
</SvelteFlow>
|
</SvelteFlow>
|
||||||
|
|||||||
@@ -61,16 +61,19 @@
|
|||||||
height: store.height / store.viewport.zoom
|
height: store.height / store.viewport.zoom
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasVisibleNodes = $derived(store.nodeLookup.size > 0 && store.nodes.some((n) => !n.hidden));
|
// let boundingRect = $derived(
|
||||||
|
// store.nodeLookup.size > 0 && store.nodes.some((n) => !n.hidden)
|
||||||
|
// ? getBoundsOfRects(
|
||||||
|
// getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }),
|
||||||
|
// viewBB
|
||||||
|
// )
|
||||||
|
// : viewBB
|
||||||
|
// );
|
||||||
|
|
||||||
let boundingRect = $derived(
|
let boundingRect = $derived(
|
||||||
hasVisibleNodes
|
getBoundsOfRects(getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }), viewBB)
|
||||||
? getBoundsOfRects(
|
|
||||||
getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }),
|
|
||||||
viewBB
|
|
||||||
)
|
|
||||||
: viewBB
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let scaledWidth = $derived(boundingRect.width / width);
|
let scaledWidth = $derived(boundingRect.width / width);
|
||||||
let scaledHeight = $derived(boundingRect.height / height);
|
let scaledHeight = $derived(boundingRect.height / height);
|
||||||
let viewScale = $derived(Math.max(scaledWidth, scaledHeight));
|
let viewScale = $derived(Math.max(scaledWidth, scaledHeight));
|
||||||
@@ -124,7 +127,7 @@
|
|||||||
|
|
||||||
{#each store.nodes as userNode (userNode.id)}
|
{#each store.nodes as userNode (userNode.id)}
|
||||||
{@const node = store.nodeLookup.get(userNode.id)}
|
{@const node = store.nodeLookup.get(userNode.id)}
|
||||||
{#if node && nodeHasDimensions(node)}
|
{#if node && nodeHasDimensions(node) && !node.hidden}
|
||||||
{@const nodeDimesions = getNodeDimensions(node)}
|
{@const nodeDimesions = getNodeDimensions(node)}
|
||||||
<MinimapNode
|
<MinimapNode
|
||||||
x={node.internals.positionAbsolute.x}
|
x={node.internals.positionAbsolute.x}
|
||||||
|
|||||||
@@ -241,20 +241,25 @@ export const getInternalNodesBounds = <NodeType extends InternalNodeBase | NodeD
|
|||||||
nodeLookup: Map<string, NodeType>,
|
nodeLookup: Map<string, NodeType>,
|
||||||
params: GetInternalNodesBoundsParams<NodeType> = {}
|
params: GetInternalNodesBoundsParams<NodeType> = {}
|
||||||
): Rect => {
|
): Rect => {
|
||||||
|
const emptyRect = { x: 0, y: 0, width: 0, height: 0 };
|
||||||
|
|
||||||
if (nodeLookup.size === 0) {
|
if (nodeLookup.size === 0) {
|
||||||
return { x: 0, y: 0, width: 0, height: 0 };
|
return emptyRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity };
|
let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity };
|
||||||
|
|
||||||
|
let hasVisibleNodes = false;
|
||||||
|
|
||||||
nodeLookup.forEach((node) => {
|
nodeLookup.forEach((node) => {
|
||||||
if (params.filter === undefined || params.filter(node)) {
|
if (params.filter === undefined || params.filter(node)) {
|
||||||
|
hasVisibleNodes = true;
|
||||||
const nodeBox = nodeToBox(node as InternalNodeBase);
|
const nodeBox = nodeToBox(node as InternalNodeBase);
|
||||||
box = getBoundsOfBoxes(box, nodeBox);
|
box = getBoundsOfBoxes(box, nodeBox);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return boxToRect(box);
|
return hasVisibleNodes ? boxToRect(box) : emptyRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getNodesInside = <NodeType extends NodeBase = NodeBase>(
|
export const getNodesInside = <NodeType extends NodeBase = NodeBase>(
|
||||||
|
|||||||
Reference in New Issue
Block a user