React-diagrams: Link target port points towards 0,0

Created on 8 Apr 2018  路  8Comments  路  Source: projectstorm/react-diagrams

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.

react_diagrams_bad_link

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());
    }

Most helpful comment

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);

All 8 comments

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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Nesterov-Konstantin picture Nesterov-Konstantin  路  4Comments

gugaevkirill picture gugaevkirill  路  3Comments

duvet86 picture duvet86  路  3Comments

jardg picture jardg  路  3Comments

Naveenraj006 picture Naveenraj006  路  3Comments