I have an issue when trying to automatically link new nodes to the previous node. The link finds its source port (the Create node in image), but the target port is pointing towards 0,0 instead of the new node CreateDatabase. Yet they are linked - moving CreateDatabase also moves the link end vertex.
The node and link are inserted on an onClick event triggerring the following function.
addManipulator(event) {
let { engine } = this.props;
let model = engine.getDiagramModel();
var node = new ManipulatorNodeModel({
name: event.target.value
});
node.setPosition(500+Math.random()*100, 350+Math.random()*100);
model.addNode(node);
var previousNode = model.nodes[this.props.previousNodeId];
if(previousNode) {
var fromPort = previousNode.getOutPorts()[0]; // Assume 1 port only
var toPort = node.getInPorts()[0]; // Assume 1 port only
var link = fromPort.link(toPort);
model.addLink(link);
}
this.props.registerPreviousNode(node.id);
this.props.reDrawDiagram(Date.now());
}
I reproduced this bug in my fork by modifying the drag and drop example from the storybook.
https://github.com/jonathanpipe/react-diagrams
https://github.com/jonathanpipe/react-diagrams/commit/3b6132ec379b7aac5d59d3de864b17ece50d7c02
Simply go to the drag and drop example in the story book and drag an "In Node" onto the graph. It tries to connect to the out node already existing.
Thanks @jonathanpipe! Im digging through the source at a slow pace. Any ideas for a fix?
@ajthinking It seems this is the root cause https://github.com/projectstorm/react-diagrams/blob/master/src/widgets/layers/LinkLayerWidget.tsx#L62
That line throws an exception because the targetPort doesn't exist and therefore our new link's end coord is not correct. The node however does have a location (in the model, as defined by calling setPosition in your case), maybe we could use that somehow to help determine what the port's coordinates would be? I'm sure how to do that yet, its my first time looking into the source.
A work around for me and you might be to break up our operation into 2 parts, add node > render > add edge > render. I haven't tried that yet though.
Breaking up the operation in two parts did the trick! Sweet, thanks @jonathanpipe ! In my case I used a setTimeout. Not really beautiful but it works.
addManipulator(event) {
let { engine } = this.props;
let model = engine.getDiagramModel();
var node = new ManipulatorNodeModel({
name: event.target.value
});
node.setPosition(100+Math.random()*100, 100+Math.random()*100);
model.addNode(node);
var latestNode = model.nodes[this.props.latestNode];
if(latestNode) {
node.setPosition(latestNode.x+200, latestNode.y);
setTimeout(function() {
var fromPort = latestNode.getOutPorts()[0]; // Assume 1 port only
var toPort = node.getInPorts()[0]; // Assume 1 port only
var link = fromPort.link(toPort);
model.addAll(link);
this.props.reDrawDiagram(Date.now());
}.bind(this), 0);
}
this.props.registerLatestNode(node.id);
this.props.reDrawDiagram(Date.now());
}
Note the setTimeout at 0 ms, just re-queueing the add link part at the end of the execution queue seems to be enough.
hey @ajthinking @jonathanpipe , i have a very similar issue mentioned here that i just posted in #234 , i tried adding a timeout to re-queue, but it did not work.
also @ajthinking , you used reDrawDiagram method? it threw me an error saying that there is no such method. I am using forceUpdate instead. if you guys could spare some time and have a look at #234 , that will be great! thanks in advance!
I also have the same issue. We are using React + Redux and ports are added dynamically when there are no free ones. So I've used combo:
setTimeout(() => {
this.diagram.handleLinksChanged([...]);
this.forceUpdate();
this.engine.zoomToFit();
});
Without any of this functions it doesnt rerender all engine parts (nodes, ports, links).
Got this problem as well (v6). Solved it with doing _reportPosition_ for all ports:
Fixing after drawing:
_.forEach(model.getNodes(), node => {
_.forEach(node.getPorts(), port => {
port.reportPosition()
});
})
Or fixing before drawing:
link.setSourcePort(outPort);
link.setTargetPort(inPort);
inPort.reportPosition()
outPort.reportPosition()
this.state.model.addAll(link);
@Letrab thank you!
Your solution works perfectly!
Most helpful comment
Got this problem as well (v6). Solved it with doing _reportPosition_ for all ports:
Fixing after drawing:
Or fixing before drawing: