syncfusion / ej2-vue-ui-components

Syncfusion Vue UI component library offer more than 50+ cross-browser, responsive, and lightweight vue UI controls for building modern web applications.

Home Page:https://www.syncfusion.com/vue-ui-components

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Adding a node by dragging over a connector

nautilebleu opened this issue · comments

Hi,

We are trying to setup a bot builder using Vue and Syncfusion Diagram.

We encounter some strange behaviours when developping the drag and drop
functionnality.

Currently, we are able to add nodes by dragging them from the palettes on
another node. It successfully adds the node to the diagram and triggers a
relayout of the diagram using the following code (which is called on the drop
event:

  insertNewNode (src: NodeModel, target: NodeModel) {
    const diagram = this.diagram;
    (src as any).inEdges = [target.id]
    this.$nextTick(() => {
      const connector = {
        id: 'connector' + Math.floor(Math.random() * 1000 + 100),
        sourceID: (target as any).id,
        targetID: src.id,
        Id: Math.floor(Math.random() * 1000 + 100)
      }
      const diag: any = diagram
      diag.add(connector)
      diag.doLayout()
      this.$store.dispatch('botBuilder/buildNodesFromDiagram', diagram)
    })
  }

Everything is ok, the whole diagram is reorganised as needed.

We also allows to move a subtree to another node with the following code (once
again, called from the drop event):

  moveToNewParent (src: NodeModel, target: NodeModel) {
    const diagram = this.diagram;
    (src as any).parentUuid = (target.data as any).customData.uuid

    let conn
    (src as any).inEdges.forEach((connectorId: any) => {
      diagram.connectors.forEach((connector: { id: any }) => {
        if (connector.id === connectorId) {
          conn = connector
        }
      })
    })
    diagram.remove(conn)

    this.$nextTick(() => {
      const connector = {
        id: 'connector' + Math.floor(Math.random() * 1000 + 100),
        sourceID: target.id,
        targetID: src.id,
        Id: Math.floor(Math.random() * 1000 + 100)
      }
      diagram.add(connector)
      diagram.doLayout()
      this.$store.dispatch('botBuilder/buildNodesFromDiagram', diagram)
    })
  }

This code also leads to the desired behavior, and the whole tree is reorganised
as expected on the diagram.

When we try to do the same when dropping a node over a connector with the
following code:

  insertOnConnector (src: NodeModel, target: ConnectorModel) {
    const diagram = this.diagram
    const connectorId = (target.properties.wrapper as any).id
    let parentNode: Node | null = null
    let childNode: Node | null = null
    diagram.nodes.forEach((node: any) => {
      if (node.outEdges.includes(connectorId)) {
        parentNode = node
      } else if (node.inEdges.includes(connectorId)) {
        childNode = node
      }
    })
    if (parentNode && childNode) {
      const pNodeOutEgdes: Array<string> = (parentNode as any).outEdges
      const cNodeOutEgdes: Array<string> = (childNode as any).outEdges
      pNodeOutEgdes.splice(pNodeOutEgdes.indexOf(connectorId), 1)
      cNodeOutEgdes.splice(cNodeOutEgdes.indexOf(connectorId), 1)

      diagram.remove(target)

      this.$nextTick(() => {
        const diag: any = diagram
        const connectorParent = {
          id: 'connector' + Math.floor(Math.random() * 1000 + 100),
          sourceID: (parentNode as any).id,
          targetID: src.id,
          Id: Math.floor(Math.random() * 1000 + 100)
        }
        diag.add(connectorParent)
        this.$nextTick(() => {
          diag.doLayout()
        })
        const connectorChild = {
          id: 'connector' + Math.floor(Math.random() * 1000 + 100),
          sourceID: src.id,
          targetID: (childNode as any).id,
          Id: Math.floor(Math.random() * 1000 + 100)
        }
        diag.add(connectorChild)
        this.$nextTick(() => {
          diag.doLayout()
        })
      })
    }
  }

It works only to reorganize the diagram if we add the node on the connector of
a leaf node. If we do this on a connector that is linked to a node with several
children (and grand children), it doesn't trigger the relayout and the new node
is placed over the next one.

We tried to use the refresh method instead of doLayout but:

  • if we call it without a clear before, it adds another tree next to the
    previous version.
  • if we call it with clear before, it adds another tree next to the
    previous version, it rerenders only the old version.

We also try to use refreshDiagram method: it works quite good, except that
it leaves some glitches of the previous nodes' positions (mostly the text zone
within a node we use to display the preview of the node's content.) Also
sometimes the diagram nodes can't be dragged anymore (but new nodes can be
added)

Can you help us finding what we are doing wrong?

Hi Nautilebleu,

On the further analysis of the shared details, we understood that you want to drag and drop a node on a connector in the layout and add the new node in between the source node and target node of the dropped connector. Please refer to the following sample for how to add a new node in between the source node and target node of the dropped connector. We have enabled allowDrop constraints to all the nodes and connectors, so whenever we drag a node from palette and drop on a connector the drop event of diagram will triggers, in the event we have removed the target connector and add the new node and add two connector and then called the doLayout API to arrange the new node and connector based on the automatic layout algorithm.

Code snippet:

     drop: (args) => {
         // canceled the addition of dropped node
         args.cancel = true;
        if(args.element && args.target && args.target.sourceID && args.target.targetID)
        {
          var parentNode = args.target.sourceID;
          var childNode = args.target.targetID;
        // remove the target connector
          diagramInstance.remove(args.target);
        // add the dropped node and connector using add API
         var addedNode = diagramInstance.add({shape:args.element.shape, offsetX:args.element.offsetX,offsetY:args.element.offsetY,
         width:args.element.width,height:args.element.height});

           diagramInstance.add({
          id: 'connector' + Math.floor(Math.random() * 1000 + 100),
          sourceID: parentNode,
          targetID: addedNode.id,
          Id: Math.floor(Math.random() * 1000 + 100)
        });

           diagramInstance.add({
          id: 'connector' + Math.floor(Math.random() * 1000 + 100),
          sourceID: addedNode.id,
          targetID: childNode,
          Id: Math.floor(Math.random() * 1000 + 100)
        });
      // call the doLayout API to arrange the added node and connectors
        diagramInstance.doLayout();
        }
      },

Sample link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/drapAnNodeOnConnectorInLayout1138290881.zip
Video link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/DropNode_toConnector372519908.zip

If we misunderstood your requirement, please share us more details or replicate the issue in the shared sample. This will be helpful for us to proceed further.

Regards,
Kamesh R.

Thanks for your answer.

We found a solution in the meantime but it's always good to have an official answer