react-cytoscapejs
react-cytoscapejs copied to clipboard
All nodes are accumulated in one position.
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
Current Result
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()
})
}
/>
Seems like this idea was repeated here: https://github.com/plotly/react-cytoscapejs/issues/43
Admittedly not obvious though
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.
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...
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
~~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
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.
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.
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}
/>
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.
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
.