Node Interaction in React Diagram Component

21 Oct 202524 minutes to read

The React Diagram component provides comprehensive support for interactive node operations, enabling users to select, drag, resize, rotate, and flip nodes through both mouse interactions and programmatic methods. These interactions form the foundation of dynamic diagram editing capabilities.

Select

Node selection is fundamental to diagram interaction. Users can select nodes by clicking on them and deselect by clicking on the diagram canvas.

Select/UnSelect Node

Programmatic Node Selection

Nodes can be selected at runtime by using the select method and the selection can be cleared in the diagram by using the clearSelection or unSelect method to remove specific objects from selection.
The following code explains how to select and clear selection in the diagram.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent } from '@syncfusion/ej2-react-diagrams';
let diagramInstance;
let node = [
  {
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Text(label) added to the node
  },
];
// initialize Diagram component
function App() {
  const select = () => {
    diagramInstance.select([diagramInstance.nodes[0]]);
  };
  const unSelect = () => {
    diagramInstance.clearSelection();
  };
  return (
    <div>
      <button onClick={select}>
        Select
      </button>
      <button onClick={unSelect}>
        Un Select
      </button>
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, NodeModel } from '@syncfusion/ej2-react-diagrams';
let diagramInstance: DiagramComponent;
let node: NodeModel[] = [
  {
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Text(label) added to the node
  },
];
// initialize Diagram component
function App() {
  const select = () => {
    diagramInstance.select([diagramInstance.nodes[0]]);
  };
  const unSelect = () => {
    diagramInstance.clearSelection();
  };
  return (
    <div>
      <button onClick={select}>
        Select
      </button>
      <button onClick={unSelect}>
        Un Select
      </button>
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Selection Methods Reference

Method Parameter Description
unSelect NodeModel/ConnectorModel The object to remove from the selection.
clearSelection - Clears all the selection in the diagram.

Drag

Node dragging allows users to reposition nodes within the diagram canvas. Users can click and hold a node, then drag it to any location on the canvas.

Drag node

Programmatic Node Dragging

Nodes can be moved programmatically using the drag method, which accepts the target object and new position coordinates.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent } from '@syncfusion/ej2-react-diagrams';
let diagramInstance;
let node = [
  {
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Text(label) added to the node
  },
];
// initialize Diagram component
function App() {
  const drag = () => {
    diagramInstance.drag(diagramInstance.nodes[0], 20, 20);
  };
  return (
    <div>
      <button onClick={drag}>Drag</button>
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, NodeModel } from '@syncfusion/ej2-react-diagrams';
let diagramInstance: DiagramComponent;
let node: NodeModel[] = [
  {
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Text(label) added to the node
  },
];
// initialize Diagram component
function App() {
  const drag = () => {
    diagramInstance.drag(diagramInstance.nodes[0], 20, 20);
  };
  return (
    <div>
      <button onClick={drag}>
        Drag
      </button>
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Resize

When a node is selected, resize handles appear on all sides, allowing users to modify the node’s dimensions by clicking and dragging these handles.

Resize Node

Programmatic Node Resizing

Node dimensions can be modified at runtime using the scale method, which applies scaling factors to adjust the node size proportionally.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent } from '@syncfusion/ej2-react-diagrams';
let diagramInstance;
let node = [
  {
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Text(label) added to the node
  },
];
// initialize Diagram component
function App() {
  const reSize = () => {
    diagramInstance.scale(diagramInstance.nodes[0], 0.5, 0.5, { x: 0.5, y: 0.5 });
  };
  return (
    <div>
      <button onClick={reSize}>Resize</button>
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, NodeModel } from '@syncfusion/ej2-react-diagrams';
let diagramInstance: DiagramComponent;
let node: NodeModel[] = [
  {
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Text(label) added to the node
  },
];
// initialize Diagram component
function App() {
  const reSize = () => {
    diagramInstance.scale(diagramInstance.nodes[0], 0.5, 0.5, { x: 0.5, y: 0.5 });
  };
  return (
    <div>
      <button onClick={reSize}>Resize</button>
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Rotate

Node rotation is performed interactively by clicking and dragging the rotate handle that appears when a node is selected.

Rotate Node

Programmatic Node Rotation

Nodes can be rotated at runtime using the rotate method, which accepts the target object and rotation angle in degrees.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent } from '@syncfusion/ej2-react-diagrams';
let diagramInstance;
let node = [
  {
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Text(label) added to the node
  },
];
// initialize Diagram component
function App() {
  const rotate = () => {
    diagramInstance.rotate(diagramInstance.nodes[0], diagramInstance.nodes[0].rotateAngle + 15);
  };
  return (
    <div>
      <button onClick={rotate}>Rotate</button>
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, NodeModel } from '@syncfusion/ej2-react-diagrams';
let diagramInstance: DiagramComponent;
let node: NodeModel[] = [
  {
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Text(label) added to the node
  },
];
// initialize Diagram component
function App() {
  const rotate = () => {
    diagramInstance.rotate(diagramInstance.nodes[0], diagramInstance.nodes[0].rotateAngle + 15);
  };
  return (
    <div>
      <button onClick={rotate}>Rotate</button>
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Flip

The diagram component supports node flipping operations to create mirrored images of nodes. The flip property controls the flip direction and behavior.

Flip Directions

give the mirrored image of the original element.
The flip types are as follows:

  • HorizontalFlip
    Horizontal is used to change the element in horizontal direction.

  • VerticalFlip
    Vertical is used to change the element in vertical direction

  • Both
    Both which involves both vertical and horizontal changes of the element.

The following example demonstrates how to apply flip transformations to nodes:

import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, FlipDirection } from "@syncfusion/ej2-react-diagrams";
// A node is created and stored in nodes array.
let node = [{
        // Position of the node
        offsetX: 250,
        offsetY: 250,
        // Size of the node
        width: 100,
        height: 100,
        // Flip the node in Horizontal Direction
        flip: FlipDirection.Horizontal,
        shape: {
            type: 'Basic',
            shape: 'RightTriangle',
        },
        style: {
            fill: '#6BA5D7',
            strokeColor: 'white'
        }
        // Text(label) added to the node
    }];
let diagramInstance;
function App() {
    return (<DiagramComponent id="container" ref={(diagram) => (diagramInstance = diagram)} width={'100%'} height={'600px'} nodes={node} created={() => {
            diagramInstance.select([diagramInstance.nodes[0]]);
        }}/>);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import {
    Diagram,
    DiagramComponent,
    NodeModel,
    BasicShapeModel,
    FlipDirection
} from "@syncfusion/ej2-react-diagrams";
// A node is created and stored in nodes array.
let node: NodeModel[] = [{
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Flip the node in Horizontal Direction
   flip: FlipDirection.Horizontal,
   shape: {
        type: 'Basic',
        shape: 'RightTriangle',
    },
    style: {
        fill: '#6BA5D7',
        strokeColor: 'white'
    }
    // Text(label) added to the node
}];
let diagramInstance: DiagramComponent;
function App() {
  return (
    <DiagramComponent
      id="container"
      ref={(diagram) => (diagramInstance = diagram)}
      width={'100%'}
      height={'600px'}
      nodes={node}
      created={() => {
        diagramInstance.select([diagramInstance.nodes[0]]);
      }}
      // render initialized Diagram
    />
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Note: The flip is also applicable for group and BPMN shapes.

Runtime Flip Updates

Node flip properties can be updated dynamically at runtime using the ^ operator, which allows toggling flip states by applying the same flip direction multiple times.

The following example demonstrates how to update the flip for a node dynamically:

import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, FlipDirection } from "@syncfusion/ej2-react-diagrams";
// A node is created and stored in nodes array.
let node = [{
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Flip the node in Horizontal Direction
    flip: FlipDirection.Horizontal,
    shape: {
        type: 'Basic',
        shape: 'RightTriangle',
    },
    style: {
        fill: '#6BA5D7',
        strokeColor: 'white'
    }
    // Text(label) added to the node
}];
let diagramInstance;
function App() {
    const flipHorizontal = () => {
        diagramInstance.nodes[0].flip ^= FlipDirection.Horizontal;
        diagramInstance.dataBind();
    };
    const flipVertical = () => {
        diagramInstance.nodes[0].flip ^= FlipDirection.Vertical;
        diagramInstance.dataBind();
    };
    const flipBoth = () => {
        diagramInstance.nodes[0].flip ^= FlipDirection.Both;
        diagramInstance.dataBind();
    };
    const flipNone = () => {
        diagramInstance.nodes[0].flip = FlipDirection.None;
        diagramInstance.dataBind();
    };
    return (
        <div>
            <button onClick={flipHorizontal}>flipHorizontal</button>
            <button onClick={flipVertical}>flipVertical</button>
            <button onClick={flipBoth}>flipBoth</button>
            <button onClick={flipNone}>flipNone</button>

            <DiagramComponent id="container" ref={(diagram) => (diagramInstance = diagram)} width={'100%'} height={'600px'} nodes={node} />
        </div>);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import {
    Diagram,
    DiagramComponent,
    NodeModel,
    BasicShapeModel,
    FlipDirection
} from "@syncfusion/ej2-react-diagrams";
// A node is created and stored in nodes array.
let node: NodeModel[] = [{
    // Position of the node
    offsetX: 250,
    offsetY: 250,
    // Size of the node
    width: 100,
    height: 100,
    // Flip the node in Horizontal Direction
   flip:FlipDirection.Horizontal,
   shape: {
        type: 'Basic',
        shape: 'RightTriangle',
    },
    style: {
        fill: '#6BA5D7',
        strokeColor: 'white'
    }
    // Text(label) added to the node
}];
let diagramInstance: DiagramComponent;
function App() {
   const flipHorizontal = () => {
          diagramInstance.nodes[0].flip ^= FlipDirection.Horizontal;
          diagramInstance.dataBind();
      };
      const flipVertical = () => {
          diagramInstance.nodes[0].flip ^= FlipDirection.Vertical;
          diagramInstance.dataBind();
      };
      const flipBoth = () => {
          diagramInstance.nodes[0].flip ^= FlipDirection.Both;
          diagramInstance.dataBind();
      };
      const flipNone = () => {
          diagramInstance.nodes[0].flip = FlipDirection.None;
          diagramInstance.dataBind();
      };
  return (
    <div>
    <button onClick={flipHorizontal}>flipHorizontal</button>
    <button onClick={flipVertical}>flipVertical</button>
    <button onClick={flipBoth}>flipBoth</button>
    <button onClick={flipNone}>flipNone</button>
    <DiagramComponent
      id="container"
      ref={(diagram) => (diagramInstance = diagram)}
      width={'100%'}
      height={'600px'}
      nodes={node}
      // render initialized Diagram
    />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Flip Modes

The flipMode property controls which elements are affected during flip operations, determining whether ports, labels, and label text are flipped along with the node.

FlipMode Description
Label It flips the label along with the object while keeping the text readable.
Port It flips the port along with the object.
All It flips the port, label, and label text along with the object.
None It flips only the object.
LabelText It flips the object and inverts the label without changing its position.
PortAndLabel It flips the port and label along with the object while keeping the text readable.
PortAndLabelText It flips the port and label text along with the object.
LabelAndLabelText It flips the label and label text along with the Object.

Flip Mode Visual Examples

The following table demonstrates how different flip modes affect node appearance across various flip directions:

Flip Direction Flip Mode Default Node Flipped Node
Horizontal All Horizontal All HorizontalFlip All
Horizontal Label Horizontal Label HorizontalFlip Label
Horizontal LabelText Horizontal LabelText HorizontalFlip LabelText
Horizontal Port Horizontal Port HorizontalFlip Port
Horizontal None Horizontal None HorizontalFlip None
Horizontal PortAndLabel Horizontal PortAndLabel HorizontalFlip PortAndLabel
Horizontal PortAndLabelText Horizontal PortAndLabelText HorizontalFlip PortAndLabelText
Horizontal LabelAndLabelText Horizontal LabelAndLabelText HorizontalFlip LabelAndLabelText
Vertical All Vertical All VerticalFlip All
Vertical Label Vertical Label VerticalFlip Label
Vertical LabelText Vertical LabelText VerticalFlip LabelText
Vertical Port Vertical Port VerticalFlip Port
Vertical None Vertical None VerticalFlip None
Vertical PortAndLabel Vertical PortAndLabel VerticalFlip PortAndLabel
Vertical PortAndLabelText Vertical PortAndLabelText VerticalFlip PortAndLabelText
Vertical LabelAndLabelText Vertical LabelAndLabelText VerticalFlip LabelAndLabelText
Both All Both All BothFlip All
Both Label Both Label BothFlip Label
Both LabelText Both LabelText BothFlip LabelText
Both Port Both Port BothFlip Port
Both None Both None BothFlip None
Both PortAndLabel Both PortAndLabel BothFlip PortAndLabel
Both PortAndLabelText Both PortAndLabelText BothFlip PortAndLabelText
Both LabelAndLabelText Both LabelAndLabelText BothFlip LabelAndLabelText
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import {
  DiagramComponent,
  PortVisibility,
  FlipDirection,
} from '@syncfusion/ej2-react-diagrams';
// A node is created and stored in nodes array.
var nodes = [
  {
    id: 'node1',
    // Position of the node
    offsetX: 100,
    offsetY: 100,
    // Size of the node
    width: 100,
    height: 100,
    ports: [
      {
        id: 'left',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
    ],
    annotations: [{ content: 'FlipMode as Label', offset: { x: 0, y: 0.8 } }],
    // Flip the node in Horizontal Direction
    flip: FlipDirection.Horizontal,
    //FlipMode as Label
    flipMode: 'Label',
    shape: {
      type: 'Basic',
      shape: 'RightTriangle',
    },
    style: {
      fill: '#6BA5D7',
    },
  },
  {
    id: 'node2',
    // Position of the node
    offsetX: 400,
    offsetY: 100,
    // Size of the node
    width: 100,
    height: 100,
    annotations: [{ content: 'FlipMode as Port', offset: { x: 0, y: 0.8 } }],
    // Flip the node in Horizontal Direction
    flip: FlipDirection.Horizontal,
    ports: [
      {
        id: 'left',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
    ],
    //FlipMode as Port
    flipMode: 'Port',
    shape: {
      type: 'Basic',
      shape: 'RightTriangle',
    },
    style: {
      fill: '#6BA5D7',
    },
  },
  {
    id: 'node3',
    // Position of the node
    offsetX: 100,
    offsetY: 300,
    // Size of the node
    width: 100,
    height: 100,
    annotations: [{ content: 'FlipMode as All', offset: { x: 0, y: 0.8 } }],
    // Flip the node in Horizontal Direction
    flip: FlipDirection.Horizontal,
    ports: [
      {
        id: 'left',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
    ],
    //FlipMode as All
    flipMode: 'All',
    shape: {
      type: 'Basic',
      shape: 'RightTriangle',
    },
    style: {
      fill: '#6BA5D7',
    },
  },
  {
    id: 'node4',
    // Position of the node
    offsetX: 400,
    offsetY: 300,
    // Size of the node
    width: 100,
    height: 100,
    annotations: [{ content: 'FlipMode as None', offset: { x: 0, y: 0.8 } }],
    // Flip the node in Horizontal Direction
    flip: FlipDirection.Horizontal,
    ports: [
      {
        id: 'left',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
    ],
    //FlipMode as None
    flipMode: 'None',
    shape: {
      type: 'Basic',
      shape: 'RightTriangle',
    },
    style: {
      fill: '#6BA5D7',
    },
  },
];
let diagramInstance;
function App() {
  return (
    <DiagramComponent
      id="container"
      ref={(diagram) => (diagramInstance = diagram)}
      width={'100%'}
      height={'600px'}
      nodes={nodes}
      created={() => {
        diagramInstance.select([diagramInstance.nodes[0]]);
      }}
    />
  );
}
export default App;
const root = createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import {
  DiagramComponent,
  PortVisibility,
  FlipDirection,
  NodeModel
} from '@syncfusion/ej2-react-diagrams';
// A node is created and stored in nodes array.
var nodes : NodeModel[] = [
  {
    id: 'node1',
    // Position of the node
    offsetX: 100,
    offsetY: 100,
    // Size of the node
    width: 100,
    height: 100,
    ports: [
      {
        id: 'left',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
    ],
    annotations: [{ content: 'FlipMode as Label', offset: { x: 0, y: 0.8 }  }],
    // Flip the node in Horizontal Direction
    flip: FlipDirection.Horizontal,
    //FlipMode as Label
    flipMode: 'Label',
    shape: {
      type: 'Basic',
      shape: 'RightTriangle',
    },
    style: {
      fill: '#6BA5D7',
    },
  },
  {
    id: 'node2',
    // Position of the node
    offsetX: 400,
    offsetY: 100,
    // Size of the node
    width: 100,
    height: 100,
    annotations: [{ content: 'FlipMode as Port', offset: { x: 0, y: 0.8 }  }],
    // Flip the node in Horizontal Direction
    flip: FlipDirection.Horizontal,
    ports: [
      {
        id: 'left',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
    ],
    //FlipMode as Port
    flipMode: 'Port',
    shape: {
      type: 'Basic',
      shape: 'RightTriangle',
    },
    style: {
      fill: '#6BA5D7',
    },
  },
  {
    id: 'node3',
    // Position of the node
    offsetX: 100,
    offsetY: 300,
    // Size of the node
    width: 100,
    height: 100,
    annotations: [{ content: 'FlipMode as All', offset: { x: 0, y: 0.8 }  }],
    // Flip the node in Horizontal Direction
    flip: FlipDirection.Horizontal,
    ports: [
      {
        id: 'left',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
    ],
    //FlipMode as All
    flipMode: 'All',
    shape: {
      type: 'Basic',
      shape: 'RightTriangle',
    },
    style: {
      fill: '#6BA5D7',
    },
  },
  {
    id: 'node4',
    // Position of the node
    offsetX: 400,
    offsetY: 300,
    // Size of the node
    width: 100,
    height: 100,
    annotations: [{ content: 'FlipMode as None', offset: { x: 0, y: 0.8 }  }],
    // Flip the node in Horizontal Direction
    flip: FlipDirection.Horizontal,
    ports: [
      {
        id: 'left',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
    ],
    //FlipMode as None
    flipMode: 'None',
    shape: {
      type: 'Basic',
      shape: 'RightTriangle',
    },
    style: {
      fill: '#6BA5D7',
    },
  },
];
let diagramInstance: DiagramComponent;
function App() {
  return (
    <DiagramComponent
      id="container"
      ref={(diagram) => (diagramInstance = diagram)}
      width={'100%'}
      height={'600px'}
      nodes={nodes}
      created={() => {
        diagramInstance.select([diagramInstance.nodes[0]]);
      }}
    />
  );
}
export default App;
const root = createRoot(document.getElementById('diagram'));
root.render(<App />);