Skip to content

Node Swapping

If you want users to reorganize your chart visually, node swapping with drag and drop is a clean approach.

This example enables drag and drop, then handles three important drop scenarios:

  1. Swap nodes on the same level.
  2. Swap parent-child nodes.
  3. Swap nodes from different levels and rewire children safely.

Core Setup

javascript
let chart = new OrgChart(document.getElementById("tree"), {
  mode: 'dark',
  enableDragDrop: true,
  nodeBinding: {
    field_0: "id",
    field_1: "pid",
  },
  orderBy: 'order'
});

The key options are:

  • enableDragDrop: true to allow dragging.
  • orderBy: 'order' so rendering follows your custom sequence.

Drop Logic

javascript
chart.onDrop((args) => {
  let dragData = chart.get(args.dragId);
  let dropData = chart.get(args.dropId);
  if (dropData != undefined) {
    let dragNode = chart.getNode(args.dragId);
    let dropNode = chart.getNode(args.dropId);
    if (dragNode.level == dropNode.level) {
      let temp = dropData.order;
      dropData.order = dragData.order;
      dragData.order = temp;

      temp = dropData.pid;
      dropData.pid = dragData.pid;
      dragData.pid = temp;
      chart.update(dropData).update(dragData).draw();
    }
    else if (dragData.pid == dropData.id || dragData.id == dropData.pid) {

      for (let i = 0; i < chart.config.nodes.length; i++) {
        let data = chart.config.nodes[i];
        if (data.pid == args.dropId) {
          data.pid = args.dragId;
        }
        else if (data.pid == args.dragId) {
          data.pid = args.dropId;
        }
      }

      if (dragData.pid == dropData.id) {
        dragData.pid = dropData.pid;
        dropData.pid = dragData.id;
      }
      else if (dragData.id == dropData.pid) {
        dropData.pid = dragData.pid;
        dragData.pid = dropData.id;
      }

      let temp = dropData.order;
      dropData.order = dragData.order;
      dragData.order = temp;

      chart.update(dropData).update(dragData).draw();
    }
    else {
      for (let i = 0; i < chart.config.nodes.length; i++) {
        let data = chart.config.nodes[i];
        if (dragNode.level > dropNode.level && data.pid == args.dropId) {
          data.pid = args.dragId;
        }
        else if (dragNode.level < dropNode.level && data.pid == args.dragId) {
          data.pid = args.dropId;
        }
        chart.update(data)
      }

      let temp = dragData.pid;
      dragData.pid = dropData.pid;
      dropData.pid = temp;
      temp = dropData.order;
      dropData.order = dragData.order;
      dragData.order = temp;
      chart.update(dropData).update(dragData).draw();
    }
  }

  return false;
})

Returning false cancels the default drop behavior, so your custom swapping logic is always used.

Sample Data

javascript
chart.load([
  { id: 1, order: 1 },
  { id: 2, pid: 1, order: 2 },
  { id: 3, pid: 1, order: 3 },
  { id: 4, pid: 2, order: 4 },
  { id: 5, pid: 2, order: 5 },
  { id: 6, pid: 3, order: 6 },
  { id: 7, pid: 3, order: 7 }
]);

Important Notes

  • Always update both pid and order when swapping nodes.
  • Redraw after updates to keep the UI in sync.
  • Handle parent-child swaps separately to avoid broken hierarchy.