Radial Tree Layout in React Diagram

21 Aug 202624 minutes to read

A radial tree layout is a specialized diagram that presents hierarchical information with a central node at the core, surrounded by branches extending outward in a circular, tree-like structure. This layout is particularly effective for visualizing organizational charts, family trees, mind maps, and network relationships where understanding the relationship distance from a central concept is important.

Radial Tree Layout

The central node represents the main concept or topic, with child nodes arranged in concentric circles based on their hierarchical level. The layout root property can be used to define the root node of the layout. When no root node is specified, the algorithm automatically identifies the node without any incoming edges (InEdges connector count of 0) as the root node. To create a radial tree, set the type of the layout to RadialTree.

The RadialTree layout provides comprehensive support for controlling node spacing and arrangement. The horizontalSpacing and verticalSpacing properties allow precise control over the space between nodes, measured in pixels. The arrangement creates an expanding concentric pattern where radial proximity to the root node indicates the hierarchical level.

Radial Tree with DataSource

Creating a radial tree layout with a data source provides automatic node generation and connection management. This approach is ideal when working with structured data objects that define hierarchical relationships.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, DataBinding, RadialTree } from "@syncfusion/ej2-react-diagrams";
import { DataManager, Query } from "@syncfusion/ej2-data";

//Initializes data source
let data = [
    {
        Id: 'parent',
        Name: 'Maria Anders',
        Designation: 'Managing Director'
    },
    {
        Id: '1',
        Name: 'Ana Trujillo',
        Designation: 'Project Manager',
        ReportingPerson: 'parent',
    },
    {
        Id: '2',
        Name: 'Lino Rodri',
        Designation: 'Project Manager',
        ReportingPerson: 'parent',
    },
    {
        Id: '3',
        Name: 'Philip Cramer',
        Designation: 'Project Manager',
        ReportingPerson: 'parent',
    },
    {
        Id: '4',
        Name: 'Pedro Afonso',
        Designation: 'Project Manager',
        ReportingPerson: 'parent',
    },
    {
        Id: '15',
        Name: 'Paul Henriot',
        Designation: 'Project Manager',
        ReportingPerson: 'parent',
    },
    {
        Id: '18',
        Name: 'Laura Callahan',
        Designation: 'Project Manager',
        ReportingPerson: 'parent',
    },
    {
        Id: '5',
        Name: 'Anto Moreno',
        Designation: 'Project Lead',
        ReportingPerson: '1',
    },
    {
        Id: '6',
        Name: 'Elizabeth Roel',
        Designation: 'Project Lead',
        ReportingPerson: '1',
    },
    {
        Id: '7',
        Name: 'Aria Cruz',
        Designation: 'Project Lead',
        ReportingPerson: '18',
    },
    {
        Id: '8',
        Name: 'Eduardo Roel',
        Designation: 'Project Lead',
        ReportingPerson: '18',
    },
    {
        Id: '9',
        Name: 'Howard Snyd',
        Designation: 'Project Lead',
        ReportingPerson: '2',
    },
    {
        Id: '10',
        Name: 'Daniel Tonini',
        Designation: 'Project Lead',
        ReportingPerson: '2',
    },
    {
        Id: '11',
        Name: 'Nardo Batista',
        Designation: 'Project Lead',
        ReportingPerson: '3',
    },
    {
        Id: '12',
        Name: 'Michael Holz',
        Designation: 'Project Lead',
        ReportingPerson: '3',
    },
    {
        Id: '13',
        Name: 'Kloss Perrier',
        Designation: 'Project Lead',
        ReportingPerson: '4',
    },
    {
        Id: '14',
        Name: 'Liz Nixon',
        Designation: 'Project Lead',
        ReportingPerson: '4',
    },
    {
        Id: '16',
        Name: 'Paula Parente',
        Designation: 'Project Lead',
        ReportingPerson: '15',
    },
    {
        Id: '17',
        Name: 'Matti Kenna',
        Designation: 'Project Lead',
        ReportingPerson: '15',
    }
];
let items = new DataManager(data, new Query().take(7));

//Uses layout to auto-arrange nodes on the diagram page
let layout = {
    //set layout type
    type: 'RadialTree',
    root: 'parent'
};

//Configures data source for diagram
let dataSourceSettings = {
    id: 'Id',
    parentId: 'ReportingPerson',
    dataSource: items
};

export default function App() {
    return (
        <DiagramComponent
            id="container"
            width={"100%"}
            height={"550px"}
            snapSettings=

            //Uses layout to auto-arrange nodes on the diagram page
            layout={layout}

            //Configures data source for diagram
            dataSourceSettings={dataSourceSettings}

            //Sets the default properties for nodes
            getNodeDefaults={(node) => {
                node.height = 20;
                node.width = 20;
                return node;
            }}

            //Sets the default properties for connectors
            getConnectorDefaults={(connector) => {
                connector.targetDecorator.shape = 'None';
                connector.type = 'Straight';
                return connector;
            }}
        >

            {/* Inject necessary services for the diagram */}
            <Inject services={[DataBinding, RadialTree]} />
        </DiagramComponent>
    );
}

// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram"));
root.render(<App />);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, ConnectorModel, DataBinding, NodeModel, RadialTree, DecoratorModel, LayoutModel, DataSourceModel } from "@syncfusion/ej2-react-diagrams";
import { DataManager, Query } from "@syncfusion/ej2-data";

//Initializes data source
let data: object[] = [
  {
    Id: 'parent',
    Name: 'Maria Anders',
    Designation: 'Managing Director'
  },
  {
    Id: '1',
    Name: 'Ana Trujillo',
    Designation: 'Project Manager',
    ReportingPerson: 'parent',
  },
  {
    Id: '2',
    Name: 'Lino Rodri',
    Designation: 'Project Manager',
    ReportingPerson: 'parent',
  },
  {
    Id: '3',
    Name: 'Philip Cramer',
    Designation: 'Project Manager',
    ReportingPerson: 'parent',
  },
  {
    Id: '4',
    Name: 'Pedro Afonso',
    Designation: 'Project Manager',
    ReportingPerson: 'parent',
  },
  {
    Id: '15',
    Name: 'Paul Henriot',
    Designation: 'Project Manager',
    ReportingPerson: 'parent',
  },
  {
    Id: '18',
    Name: 'Laura Callahan',
    Designation: 'Project Manager',
    ReportingPerson: 'parent',
  },
  {
    Id: '5',
    Name: 'Anto Moreno',
    Designation: 'Project Lead',
    ReportingPerson: '1',
  },
  {
    Id: '6',
    Name: 'Elizabeth Roel',
    Designation: 'Project Lead',
    ReportingPerson: '1',
  },
  {
    Id: '7',
    Name: 'Aria Cruz',
    Designation: 'Project Lead',
    ReportingPerson: '18',
  },
  {
    Id: '8',
    Name: 'Eduardo Roel',
    Designation: 'Project Lead',
    ReportingPerson: '18',
  },
  {
    Id: '9',
    Name: 'Howard Snyd',
    Designation: 'Project Lead',
    ReportingPerson: '2',
  },
  {
    Id: '10',
    Name: 'Daniel Tonini',
    Designation: 'Project Lead',
    ReportingPerson: '2',
  },
  {
    Id: '11',
    Name: 'Nardo Batista',
    Designation: 'Project Lead',
    ReportingPerson: '3',
  },
  {
    Id: '12',
    Name: 'Michael Holz',
    Designation: 'Project Lead',
    ReportingPerson: '3',
  },
  {
    Id: '13',
    Name: 'Kloss Perrier',
    Designation: 'Project Lead',
    ReportingPerson: '4',
  },
  {
    Id: '14',
    Name: 'Liz Nixon',
    Designation: 'Project Lead',
    ReportingPerson: '4',
  },
  {
    Id: '16',
    Name: 'Paula Parente',
    Designation: 'Project Lead',
    ReportingPerson: '15',
  },
  {
    Id: '17',
    Name: 'Matti Kenna',
    Designation: 'Project Lead',
    ReportingPerson: '15',
  }
];
let items: DataManager = new DataManager(data as JSON[], new Query().take(7));

//Uses layout to auto-arrange nodes on the diagram page
const layout: LayoutModel = {
  //set layout type
  type: 'RadialTree',
  root: 'parent'
};

//Configures data source for diagram
const dataSourceSettings: DataSourceModel = {
  id: 'Id',
  parentId: 'ReportingPerson',
  dataSource: items
};

export default function App() {
  return (
    <DiagramComponent
      id="container"
      width={"100%"}
      height={"550px"}
      snapSettings=

      //Uses layout to auto-arrange nodes on the diagram page
      layout={layout}

      //Configures data source for diagram
      dataSourceSettings={dataSourceSettings}

      //Sets the default properties for nodes
      getNodeDefaults={(node: NodeModel) => {
        node.height = 20;
        node.width = 20;
        return node;
      }}

      //Sets the default properties for connectors
      getConnectorDefaults={(connector: ConnectorModel) => {
        (connector.targetDecorator as DecoratorModel).shape = 'None';
        connector.type = 'Straight';
        return connector;
      }}
    >

      {/* Inject necessary services for the diagram */}
      <Inject services={[DataBinding, RadialTree]} />
    </DiagramComponent>
  );
}

// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram") as HTMLElement);
root.render(<App />);

NOTE

When converting a data source into a radial layout, inject both DataBinding and RadialTree modules in the diagram component.

Radial Tree with Nodes and Connectors

For scenarios requiring manual control over node creation and positioning, the radial tree layout can be applied to explicitly defined nodes and connectors. This approach offers greater flexibility for custom node styling and specific layout requirements.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, DataBinding, RadialTree } from "@syncfusion/ej2-react-diagrams";


//Initializes Nodes for diagram
let nodes = [
    { id: 'Maria Anders' },
    { id: 'Ana Trujillo' },
    { id: 'Lino Rodri' },
    { id: 'Philip Cramer' },
    { id: 'Pedro Afonso' },
    { id: 'Paul Henriot' },
    { id: 'Laura Callahan' },
    { id: 'Anto Moreno' },
    { id: 'Elizabeth Roel' },
    { id: 'Aria Cruz' },
    { id: 'Eduardo Roel' },
    { id: 'Howard Snyd' },
    { id: 'Daniel Tonini' },
    { id: 'Nardo Batista' },
    { id: 'Michael Holz' },
    { id: 'Kloss Perrier' },
    { id: 'Liz Nixon' },
    { id: 'Paula Parente' },
    { id: 'Matti Kenna' },
];

//Initializes Connectors for diagram
let connectors = [
    {
        id: 'Maria Anders-Ana Trujillo',
        sourceID: 'Maria Anders',
        targetID: 'Ana Trujillo',
    }, 
    {
        id: 'Maria Anders-Lino Rodri',
        sourceID: 'Maria Anders',
        targetID: 'Lino Rodri',
    },
    {
        id: 'Maria Anders-Philip Cramer',
        sourceID: 'Maria Anders',
        targetID: 'Philip Cramer',
    },
    {
        id: 'Maria Anders-Pedro Afonso',
        sourceID: 'Maria Anders',
        targetID: 'Pedro Afonso',
    },
    {
        id: 'Maria Anders-Paul Henriot',
        sourceID: 'Maria Anders',
        targetID: 'Paul Henriot',
    },
    {
        id: 'Maria Anders-Laura Callahan',
        sourceID: 'Maria Anders',
        targetID: 'Laura Callahan',
    },
    {
        id: 'Ana Trujillo-Anto Moreno',
        sourceID: 'Ana Trujillo',
        targetID: 'Anto Moreno',
    },
    {
        id: 'Ana Trujillo-Elizabeth Roel',
        sourceID: 'Ana Trujillo',
        targetID: 'Elizabeth Roel',
    },
    {
        id: 'Laura Callahan-Aria Cruz',
        sourceID: 'Laura Callahan',
        targetID: 'Aria Cruz',
    },
    {
        id: 'Laura Callahan-Eduardo Roel',
        sourceID: 'Laura Callahan',
        targetID: 'Eduardo Roel',
    },
    {
        id: 'Lino Rodri-Howard Snyd',
        sourceID: 'Lino Rodri',
        targetID: 'Howard Snyd',
    },
    {
        id: 'Lino Rodri-Daniel Tonini',
        sourceID: 'Lino Rodri',
        targetID: 'Daniel Tonini',
    },
    {
        id: 'Philip Cramer-Nardo Batista',
        sourceID: 'Philip Cramer',
        targetID: 'Nardo Batista',
    },
    {
        id: 'Philip Cramer-Michael Holz',
        sourceID: 'Philip Cramer',
        targetID: 'Michael Holz',
    },
    {
        id: 'Pedro Afonso-Kloss Perrier',
        sourceID: 'Pedro Afonso',
        targetID: 'Kloss Perrier',
    },
    {
        id: 'Pedro Afonso-Liz Nixon',
        sourceID: 'Pedro Afonso',
        targetID: 'Liz Nixon',
    },
    {
        id: 'Paul Henriot-Paula Parente',
        sourceID: 'Paul Henriot',
        targetID: 'Paula Parente',
    },
    {
        id: 'Paul Henriot-Matti Kenna',
        sourceID: 'Paul Henriot',
        targetID: 'Matti Kenna',
    }
];

//Uses layout to auto-arrange nodes on the diagram page
let layout = {
    //set layout type
    type: 'RadialTree',
    root: 'parent'
};

export default function App() {
    return (
        <DiagramComponent
            id="container"
            width={"100%"}
            height={"550px"}
            nodes={nodes}
            connectors={connectors}
            snapSettings=

            //Uses layout to auto-arrange nodes on the diagram page
            layout={layout}

            //Sets the default properties for nodes
            getNodeDefaults={(node) => {
                node.height = 20;
                node.width = 20;
                return node;
            }}

            //Sets the default properties for connectors
            getConnectorDefaults={(connector) => {
                connector.targetDecorator.shape = 'None';
                connector.type = 'Straight';
                return connector;
            }}
        >

            {/* Inject necessary services for the diagram */}
            <Inject services={[DataBinding, RadialTree]} />
        </DiagramComponent>
    );
}

// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram"));
root.render(<App />);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, ConnectorModel, DataBinding, NodeModel, RadialTree, DecoratorModel, LayoutModel } from "@syncfusion/ej2-react-diagrams";


//Initializes Nodes for diagram
let nodes: NodeModel[] = [
  { id: 'Maria Anders' },
  { id: 'Ana Trujillo' },
  { id: 'Lino Rodri' },
  { id: 'Philip Cramer' },
  { id: 'Pedro Afonso' },
  { id: 'Paul Henriot' },
  { id: 'Laura Callahan' },
  { id: 'Anto Moreno' },
  { id: 'Elizabeth Roel' },
  { id: 'Aria Cruz' },
  { id: 'Eduardo Roel' },
  { id: 'Howard Snyd' },
  { id: 'Daniel Tonini' },
  { id: 'Nardo Batista' },
  { id: 'Michael Holz' },
  { id: 'Kloss Perrier' },
  { id: 'Liz Nixon' },
  { id: 'Paula Parente' },
  { id: 'Matti Kenna' },
];

//Initializes Connectors for diagram
let connectors: ConnectorModel[] = [
  {
    id: 'Maria Anders-Ana Trujillo',
    sourceID: 'Maria Anders',
    targetID: 'Ana Trujillo',
  },
  {
    id: 'Maria Anders-Lino Rodri',
    sourceID: 'Maria Anders',
    targetID: 'Lino Rodri',
  },
  {
    id: 'Maria Anders-Philip Cramer',
    sourceID: 'Maria Anders',
    targetID: 'Philip Cramer',
  },
  {
    id: 'Maria Anders-Pedro Afonso',
    sourceID: 'Maria Anders',
    targetID: 'Pedro Afonso',
  },
  {
    id: 'Maria Anders-Paul Henriot',
    sourceID: 'Maria Anders',
    targetID: 'Paul Henriot',
  },
  {
    id: 'Maria Anders-Laura Callahan',
    sourceID: 'Maria Anders',
    targetID: 'Laura Callahan',
  },
  {
    id: 'Ana Trujillo-Anto Moreno',
    sourceID: 'Ana Trujillo',
    targetID: 'Anto Moreno',
  },
  {
    id: 'Ana Trujillo-Elizabeth Roel',
    sourceID: 'Ana Trujillo',
    targetID: 'Elizabeth Roel',
  },
  {
    id: 'Laura Callahan-Aria Cruz',
    sourceID: 'Laura Callahan',
    targetID: 'Aria Cruz',
  },
  {
    id: 'Laura Callahan-Eduardo Roel',
    sourceID: 'Laura Callahan',
    targetID: 'Eduardo Roel',
  },
  {
    id: 'Lino Rodri-Howard Snyd',
    sourceID: 'Lino Rodri',
    targetID: 'Howard Snyd',
  },
  {
    id: 'Lino Rodri-Daniel Tonini',
    sourceID: 'Lino Rodri',
    targetID: 'Daniel Tonini',
  },
  {
    id: 'Philip Cramer-Nardo Batista',
    sourceID: 'Philip Cramer',
    targetID: 'Nardo Batista',
  },
  {
    id: 'Philip Cramer-Michael Holz',
    sourceID: 'Philip Cramer',
    targetID: 'Michael Holz',
  },
  {
    id: 'Pedro Afonso-Kloss Perrier',
    sourceID: 'Pedro Afonso',
    targetID: 'Kloss Perrier',
  },
  {
    id: 'Pedro Afonso-Liz Nixon',
    sourceID: 'Pedro Afonso',
    targetID: 'Liz Nixon',
  },
  {
    id: 'Paul Henriot-Paula Parente',
    sourceID: 'Paul Henriot',
    targetID: 'Paula Parente',
  },
  {
    id: 'Paul Henriot-Matti Kenna',
    sourceID: 'Paul Henriot',
    targetID: 'Matti Kenna',
  }
];

//Uses layout to auto-arrange nodes on the diagram page
const layout: LayoutModel = {
  //set layout type
  type: 'RadialTree',
  root: 'parent'
};

export default function App() {
  return (
    <DiagramComponent
      id="container"
      width={"100%"}
      height={"550px"}
      nodes={nodes}
      connectors={connectors}
      snapSettings=
      
      //Uses layout to auto-arrange nodes on the diagram page
      layout={layout}

      //Sets the default properties for nodes
      getNodeDefaults={(node: NodeModel) => {
        node.height = 20;
        node.width = 20;
        return node;
      }}

      //Sets the default properties for connectors
      getConnectorDefaults={(connector: ConnectorModel) => {
        (connector.targetDecorator as DecoratorModel).shape = 'None';
        connector.type = 'Straight';
        return connector;
      }}
    >

      {/* Inject necessary services for the diagram */}
      <Inject services={[DataBinding, RadialTree]} />
    </DiagramComponent>
  );
}

// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram") as HTMLElement);
root.render(<App />);

NOTE

To use radial tree layout functionality, inject the RadialTree module in the diagram component.