Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default Layout #15

Merged
merged 2 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions lib/NodeGraphEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ReactFlowProps,
ReactFlowProvider,
useEdgesState,
useNodesInitialized,
useNodesState,
useReactFlow,
useStoreApi,
Expand All @@ -23,6 +24,7 @@ import {
useMemo,
JSX,
CSSProperties,
useEffect,
} from 'react'
import { defaultEdgeTypes } from './edge-types'
import { IGraphConfig } from './config'
Expand All @@ -32,15 +34,15 @@ import { ClipboardItem } from './clipboard'
import { LayoutEngine, useLayoutEngine } from './layout/layout'

type NodeGraphEditorProps = Omit<FlowProps, 'edges' | 'nodes'> & {
onSave?: (data: any) => void
onSave?: (data: any) => void,
}

export const NodeGraphEditor = forwardRef<
NodeGraphHandle,
NodeGraphEditorProps
>(
(
{ defaultNodes, defaultEdges, ...props }: NodeGraphEditorProps,
{ defaultNodes, defaultEdges, layoutEngine, ...props }: NodeGraphEditorProps,
ref,
): JSX.Element => {
const [nodes, , onNodesChange] = useNodesState(defaultNodes ?? [])
Expand Down Expand Up @@ -81,15 +83,19 @@ export const ExampleNodeGraphEditor = forwardRef<
})

type FlowProps = ReactFlowProps & {
backgroundStyles?: CSSProperties
backgroundStyles?: CSSProperties,
/**
* The default layout engine to use when nodes are provided without positions.
*/
layoutEngine?: LayoutEngine
}
export type NodeGraphHandle = {
layout: () => void
}

const Flow = forwardRef<NodeGraphHandle, FlowProps>(
(
{ defaultNodes, defaultEdges, backgroundStyles, ...props }: FlowProps,
{ backgroundStyles, layoutEngine, ...props }: FlowProps,
ref,
) => {
const nodeTypes = useNodeTypes()
Expand All @@ -98,6 +104,7 @@ const Flow = forwardRef<NodeGraphHandle, FlowProps>(
const [config] = useGraphConfig()
const { getState } = useStoreApi()
const { setNodes, setEdges } = useReactFlow()


// Handle clipboard events
useHotkeys(
Expand All @@ -110,7 +117,7 @@ const Flow = forwardRef<NodeGraphHandle, FlowProps>(
)

// Provide methods to parent components
const layout = useLayoutEngine(LayoutEngine.Dagre)
const layout = useLayoutEngine(layoutEngine ?? LayoutEngine.Dagre)
useImperativeHandle(
ref,
() => ({
Expand All @@ -119,6 +126,16 @@ const Flow = forwardRef<NodeGraphHandle, FlowProps>(
[],
)

const initialized = useNodesInitialized()
useEffect(() => {
const shouldLayout = !!getState().nodes.find(
(node) => node.position == undefined,
)
if (initialized && shouldLayout) {
layout()
}
}, [initialized])

return (
<div
style={{
Expand Down
4 changes: 2 additions & 2 deletions lib/NodeGraphEditorInputGroups.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ export const InputGroups: Story = {
{
id: '1',
type: 'bsdf',
position: { x: 350, y: 100 },
// position: { x: 350, y: 100 },
data: {
__inputGroupsExpanded: ['Specular'],
},
Expand All @@ -251,7 +251,7 @@ export const InputGroups: Story = {
position: { x: 100, y: 300 },
data: {},
},
],
] as Node[],
edges: [
{
id: 'e1',
Expand Down
14 changes: 10 additions & 4 deletions lib/layout/layout.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback } from 'react'
import { computeDagreLayout } from './dagre'
import { Instance, Node, useReactFlow } from '@xyflow/react'
import { Edge, Instance, Node, useReactFlow } from '@xyflow/react'

export enum LayoutEngine {
Dagre,
Expand All @@ -20,10 +20,16 @@ function computeLayout(
getNodes: Instance.GetNodes<any>,
getEdges: Instance.GetEdges<any>,
): Node[] {
const layoutFn = getLayoutFunction(engine)
if (!layoutFn) throw new Error(`Unknown layout engine ${engine}`)
return layoutFn(getNodes(), getEdges())
}

export function getLayoutFunction(
engine: LayoutEngine | undefined,
): ((nodes: Node[], edges: Edge[]) => Node[]) | undefined {
switch (engine) {
case LayoutEngine.Dagre:
return computeDagreLayout(getNodes(), getEdges())
default:
throw new Error(`Unknown layout engine ${engine}`)
return computeDagreLayout
}
}
Loading