kieler / elkjs

ELK's layout algorithms for JavaScript
Other
1.76k stars 97 forks source link

Specify Position for Specific Node in ELKJS #267

Closed MuttakinHasib closed 7 months ago

MuttakinHasib commented 7 months ago

I'm currently utilizing the ELKJS library along with ReactFlow, and I'm encountering an issue where I need to customize the position of a specific node. Specifically, I have a Suggestions Node which contains a child node called Search Node. Additionally, the Search Node is connected to the parent node of Suggestions Node, referred to as the Follow Up Node.

However, in my current implementation, the Search Node is positioned in the middle between the Follow Up Node and the Suggestions Node. The desired behavior is for the Search Node to always be positioned to the right side of the Suggestions Node and make sure that nodes are not overlapping with other nodes.

I believe this behavior requires tweaking the ELKJS library's layout algorithm or possibly introducing custom positioning logic. I'm seeking guidance or suggestions on how to achieve this desired positioning for the Search Node within the ELKJS library.

Any assistance or insights on how to customize node positioning within ELKJS would be greatly appreciated. Thank you!

Code:


// elk layouting options can be found here:
// https://www.eclipse.org/elk/reference/algorithms/org-eclipse-elk-layered.html
const layoutOptions = {
  'elk.algorithm': 'layered',
  'elk.direction': 'LEFT',
  'elk.layered.spacing.edgeNodeBetweenLayers': '50',
  'elk.spacing.nodeNode': '10',
  'elk.layered.nodePlacement.strategy': 'SIMPLE',
  'org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers':
    '100',
}

const elk = new ELK()

// uses elkjs to give each node a layouted position
export const getLayoutedNodes = async (
  nodes: Node[],
  edges: Edge[],
) => {
  const graph = {
    id: 'root',
    layoutOptions,
    children: nodes.map((n) => {
      return {
        id: n.id,
        width: (n.width ?? 150) + 50,
        height: (n.height ?? 50) + 50,
      }
    }),
    edges: edges.map((e) => ({
      id: e.id,
      sources: [e.sourceHandle || e.source],
      targets: [e.targetHandle || e.target],
    })),
  }

  const layoutedGraph = await elk.layout(graph)

  const layoutedNodes = nodes.map((node) => {
    const layoutedNode = layoutedGraph.children?.find(
      (lgNode) => lgNode.id === node.id,
    )

    return {
      ...node,
      position: {
        x: layoutedNode?.x ?? 0,
        y: layoutedNode?.y ?? 0,
      },
    }
  })

  return layoutedNodes
}

Here is the issue:

image

Expected Behaviour:

image

soerendomroes commented 7 months ago

Have you tried uing partition. You can find an example here.

MuttakinHasib commented 7 months ago

Thanks @soerendomroes