react-cytoscapejs icon indicating copy to clipboard operation
react-cytoscapejs copied to clipboard

All nodes are accumulated in one position.

Open scnetrix opened this issue 4 years ago • 12 comments

When creating a path using dagre, the whole nodes accumulate in one position. How can we set default positions for nodes ( Cytoscape js without react works fine) instead of setting position separately using position attribute for nodes.

const layout = { name: "dagre", rankDir: "LR" } pageData = < CytoscapeComponent elements = { CytoscapeComponent.normalizeElements({ nodes: nodess, edges: edgess, layout: layout, }) } pan = { { x: 200, y: 200 } } autounselectify = { true } userZoomingEnabled = { false } boxSelectionEnabled = { false } style = { { width: "1200px", height: "1000px" } } /> return ( < div

{ pageData } < /div> );

/------------------------------/ Expected Result Expected Result

Current Result Current-Result

scnetrix avatar Feb 27 '20 09:02 scnetrix

I encountered something similar. I found a workaround but I don't know if it's a bandaid because I'm doing it wrong or not.

Effectively, I used the graph event hooks to call the layout function as nodes were added. Try this and see what works for you. Maybe it will uncover or yield insight into how it's meant to be done:

<CytoscapeComponent
  cy={cy =>
    cy.on('add', 'node', _evt => {
      cy.layout(layoutOptions).run()
      cy.fit()
    })
  } 
/>

TheDahv avatar Mar 11 '20 03:03 TheDahv

Seems like this idea was repeated here: https://github.com/plotly/react-cytoscapejs/issues/43

Admittedly not obvious though

TheDahv avatar Mar 11 '20 03:03 TheDahv

Seems like this code is needed when i tried to re-render a different graph on the same canvas. All my nodes are on the same position previously.

SaiMun92 avatar May 19 '20 12:05 SaiMun92

Adding the cy.on calls didn't solve the problem for me. I've tried putting a run on ready as well, and no good. Not really sure what else there is to try...

willowv avatar Jul 03 '20 03:07 willowv

const layout = {
name: "dagre",
rankDir: "LR"
}
pageData = < CytoscapeComponent
elements = {
CytoscapeComponent.normalizeElements({
nodes: nodess,
edges: edgess,
layout: layout,
})
}

I'm confused why the layout is part of the CytoscapeComponent.normalizeElements call, it should be set next the elements as another property

sgratzl avatar Jul 06 '20 12:07 sgratzl

~~I'm having the same problem, and just like eps-tvaughan, cy.on did not solve the problem for either.~~

Edit: it did work, I misspelled the cy prop

EdwinSmulders avatar Jul 31 '20 13:07 EdwinSmulders

What worked really well for me is this:

                    cy.on('resize', _evt => {
                        cy.layout(layoutOptions).run()
                        cy.fit()
                    })

This will run the layout the first time it configures the size, which is apparently after the nodes have been added. This is way more performance friendly than running it on every node add.

EdwinSmulders avatar Jul 31 '20 15:07 EdwinSmulders

I ended up using a different lightweight graph vis library and writing my own basic layout calculation. My graphs are pretty light (strictly less than 20 nodes) and I think ultimately cytoscape is probably overkill for what I'm doing.

willowv avatar Jul 31 '20 22:07 willowv

from a plotly component. works for me but its really not obvious to get here... thanks those pathfinders!

                <CytoscapeComponent
                    cy={cy =>
                        cy.on('add', 'node', _evt => {
                            cy.layout(layout).run()
                            cy.fit()
                        })
                    }
                    className='cyto-box'
                    elements={graphData}
                    layout={layout}
                    stylesheet={stylesheet}
                />

dcsan avatar Jun 08 '21 07:06 dcsan

What worked really well for me is this:

                    cy.on('resize', _evt => {
                        cy.layout(layoutOptions).run()
                        cy.fit()
                    })

This will run the layout the first time it configures the size, which is apparently after the nodes have been added. This is way more performance friendly than running it on every node add.

Unfortunately I didn't have similar luck, however your comment inspired a simple workaround which was to only call layout and fit after all the changed elements had been added (i.e. run a counter in the add event handler and when it matches elements.length, then do the layout and fit).

edit: by similar luck, I mean I tried using resize and for my use case (changing elements from React set state), I didn't get the layout/fit calls expected.

fiatexodus avatar Jul 21 '21 03:07 fiatexodus

Because my elements are fed into the parent component by a variable created with useState, what I'm doing is just running the .layout and .fit methods in a React.useEffect hook. The plus side is that this works. The downside is that the window spazzes a little bit when I change the data.

    React.useEffect(() => {
        if (cyRef.current !== null) {
            cyRef.current.layout(graphLayout).run()
            cyRef.current.fit()
        }
    })

    return <CytoscapeComponent elements={allElements}
                style={graphComponentStyle}
                stylesheet={graphStyleSheet}
                layout={graphLayout}
                cy={cy => {
                    cyRef.current = cy
                }}/>

To be clear, allElements is not the useState variable; the actual state variable is higher up, which is comprised of random JSON that from a server. I run some processing on the stateful variable to get allElements.

sahansk2 avatar Aug 04 '21 05:08 sahansk2