Copied RSS Feed

Blazor

Seamlessly Create a Mind Map Using the Blazor Diagram Component

Mind mapping is a powerful technique that helps you represent tasks, words, concepts, or items related to and arranged around a central idea. It is the perfect tool for strategy mapping and formulation, problem-solving, brainstorming, and conceptualizing, as it displays various ideas associated with a specific concept. Mind mapping boosts creativity, productivity, and teamwork.

The Syncfusion Blazor Diagram component is a fast and powerful library for visualizing, creating and editing interactive diagrams.

In this article, we’ll see how to create a mind map diagram using the features of the Syncfusion Blazor Diagram component.

Note: Before proceeding, refer to the getting started with the Blazor Diagram component documentation.

Add the Blazor Diagram component to an application

First, add the Syncfusion Blazor Diagram component to a Blazor WebAssembly app:

  1. Create a Blazor WebAssembly app.
  2. Then, install the NuGet package Syncfusion.Blazor.Diagram in the app using the NuGet package manager.
  3. Add the style resources through CDN or from the NuGet package in the head element of the ~/wwwroot/index.html page.
    <head>
        ………
        ………
        <link href="_content/Syncfusion.Blazor.Themes/bootstrap5.css" rel="stylesheet" />
        <script src="https://cdn.syncfusion.com/blazor/20.4.38/syncfusion-blazor.min.js" type="text/javascript"></script>
    </head>
  1. Open the ~/_Imports.Blazor file and import the Blazor.Diagram package in it.
    @using Syncfusion.Blazor.Diagram
  1. In the Program.cs file, add the services required for the Syncfusion Blazor components using the builder.Services.AddSyncfusionBlazor() method.
    using Syncfusion.Blazor;
    
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    . . . . .
    . . . . .
    builder.Services.AddSyncfusionBlazor();
    
    await builder.Build().RunAsync();
  1. Finally, add the Blazor Diagram component to the Pages folder in the Razor file.
    <SfDiagramComponent @ref="@diagram" Width="100%" Height="600px" InteractionController="@DiagramInteractions.ZoomPan" NodeCreating="@NodeCreating" ConnectorCreating="@ConnectorCreating"/>

Thus, we have added the Syncfusion Blazor Diagram component to the Blazor WebAssembly app.

Create a mind map diagram

Next, we are going to create a mind map diagram for business planning in the Blazor WebAssembly app.

Step #1: Define the data source

We need a data source or node collection to populate the mind map on the diagram canvas.

Create a model class to construct the data source. Define the Id, ParentId, and Branch details in the mind map model class. Then, add a fill property to improve the UI’s design. You can specify your custom properties, if necessary.

Refer to the following code.

// Create a model class for the data source.
public class MindMapItem
{
   public string Id { get; set; }
   public string Label { get; set; }
   public string ParentId { get; set; }
   public BranchType Branch { get; set; }
   public string Fill { get; set; }
}

Next, create a data source for the mind map and populate the records as nodes. Each record in the data source will be created as a separate node in the mind map layout.

Specify the parent and child relationship between the nodes.

Refer to the following code.

//Defining the dataSource.
public List<MindMapItem> DataSource = new List<MindMapItem>()
{
   new MindMapItem(){Id="1",Label="Business Planning",ParentId ="",Branch= BranchType.Root, Fill="#034d6d" },
   new MindMapItem(){Id="2",Label= "Expectation",ParentId = "1",Branch= BranchType.Left,Fill= "#1b80c6" },
   new MindMapItem(){Id="3",Label= "Requirements", ParentId="1",Branch= BranchType.Right,Fill= "#1b80c6" },
   new MindMapItem(){Id="4",Label= "Marketing", ParentId="1",Branch= BranchType.Left,Fill= "#1b80c6" },
   new MindMapItem(){Id="5",Label= "Budgets",ParentId= "1",Branch= BranchType.Right,Fill= "#1b80c6" },
   new MindMapItem(){ Id="6", Label="Situation in Market", ParentId= "1", Branch = BranchType.Left, Fill= "#1b80c6" },
   new MindMapItem(){ Id="7", Label="Product Sales", ParentId= "2", Branch = BranchType.SubLeft, Fill= "#3dbfc9" },
   new MindMapItem() { Id = "8", Label= "Strategy", ParentId="2", Branch = BranchType.SubLeft, Fill="#3dbfc9" },
   new MindMapItem() { Id = "9", Label="Contacts", ParentId="2", Branch = BranchType.SubLeft, Fill="#3dbfc9" },
   new MindMapItem() { Id = "10", Label="Customer Groups", ParentId= "4", Branch = BranchType.SubLeft,Fill= "#3dbfc9" },
   new MindMapItem() { Id = "11", Label= "Branding", ParentId= "4", Branch = BranchType.SubLeft, Fill= "#3dbfc9" },
   new MindMapItem() { Id = "12", Label= "Advertising", ParentId= "4", Branch = BranchType.SubLeft, Fill= "#3dbfc9" },
   new MindMapItem() { Id = "13", Label= "Competitors", ParentId= "6", Branch = BranchType.SubLeft, Fill="#3dbfc9" },
   new MindMapItem() { Id = "14", Label="Location", ParentId="6", Branch = BranchType.SubLeft, Fill= "#3dbfc9" },
   new MindMapItem() { Id = "15", Label= "Director", ParentId= "3", Branch = BranchType.SubRight, Fill="#3dbfc9" },
   new MindMapItem() { Id = "16", Label="Accounts Department", ParentId= "3", Branch = BranchType.SubRight, Fill= "#3dbfc9" },
   new MindMapItem() { Id = "17", Label="Administration", ParentId= "3", Branch = BranchType.SubRight, Fill="#3dbfc9" },
   new MindMapItem() { Id = "18", Label= "Development", ParentId="3", Branch = BranchType.SubRight, Fill= "#3dbfc9" },
   new MindMapItem() { Id = "19", Label= "Estimation", ParentId= "5", Branch = BranchType.SubRight, Fill="#3dbfc9" },
   new MindMapItem() { Id = "20", Label= "Profit", ParentId= "5", Branch = BranchType.SubRight, Fill= "#3dbfc9" },
   new MindMapItem(){ Id="21", Label="Funds", ParentId= "5", Branch = BranchType.SubRight, Fill= "#3dbfc9" }
};

Note: For more details, refer to the documentation on how to create Blazor Diagram nodes and connectors with labels.

Step #2: Binding the data source to the Diagram component

Bind the data source with the Blazor Diagram component, as shown in the following code.

<SfDiagramComponent>
    <DataSourceSettings ID="Id" ParentID="ParentId" DataSource="DataSource"></DataSourceSettings>
</SfDiagramComponent>

Once the data source is bound and the parent-child relationships are configured, define the layout type as MindMap to automatically arrange the nodes’ positions.

<Layout Type="LayoutType.MindMap" HorizontalSpacing="80" VerticalSpacing="30">
</Layout>

Finally, the Razor file will look like the following.

@page "/"
@using Syncfusion.Blazor.Diagram
@using Syncfusion.Blazor.Diagram.Internal

<SfDiagramComponent @ref="@diagram" Height="690px" InteractionController="@DiagramInteractions.ZoomPan" NodeCreating="@NodeCreating" ConnectorCreating="@ConnectorCreating">
 <DataSourceSettings ID="Id" ParentID="ParentId" DataSource="DataSource"></DataSourceSettings>
  <Layout Type="LayoutType.MindMap" HorizontalSpacing="80" VerticalSpacing="30">
   <LayoutMargin Top="10" Bottom="10" Right="10" Left="10"></LayoutMargin>
  </Layout>
  <SnapSettings Constraints="SnapConstraints.None" />
</SfDiagramComponent>

@code
{
    SfDiagramComponent diagram;

    // Create a model class for the data source.
    public class MindMapItem
    {
        public string Id { get; set; }
        public string Label { get; set; }
        public string ParentId { get; set; }
        public BranchType Branch { get; set; }
        public string Fill { get; set; }
    }

    //Defining the dataSource.
    public List<MindMapItem> DataSource = new List<MindMapItem>()
    {
        new MindMapItem(){Id="1",Label="Business Planning",ParentId ="",Branch= BranchType.Root, Fill="#034d6d" },
        new MindMapItem(){Id="2",Label= "Expectation",ParentId = "1",Branch= BranchType.Left,Fill= "#1b80c6" },
        new MindMapItem(){Id="3",Label= "Requirements", ParentId="1",Branch= BranchType.Right,Fill= "#1b80c6" },
        new MindMapItem(){Id="4",Label= "Marketing", ParentId="1",Branch= BranchType.Left,Fill= "#1b80c6" },
        new MindMapItem(){Id="5",Label= "Budgets",ParentId= "1",Branch= BranchType.Right,Fill= "#1b80c6" },
        new MindMapItem(){ Id="6", Label="Situation in Market", ParentId= "1", Branch = BranchType.Left, Fill= "#1b80c6" },
        new MindMapItem(){ Id="7", Label="Product Sales", ParentId= "2", Branch = BranchType.SubLeft, Fill= "#3dbfc9" },
        new MindMapItem() { Id = "8", Label= "Strategy", ParentId="2", Branch = BranchType.SubLeft, Fill="#3dbfc9" },
        new MindMapItem() { Id = "9", Label="Contacts", ParentId="2", Branch = BranchType.SubLeft, Fill="#3dbfc9" },
        new MindMapItem() { Id = "10", Label="Customer Groups", ParentId= "4", Branch = BranchType.SubLeft,Fill= "#3dbfc9" },
        new MindMapItem() { Id = "11", Label= "Branding", ParentId= "4", Branch = BranchType.SubLeft, Fill= "#3dbfc9" },
        new MindMapItem() { Id = "12", Label= "Advertising", ParentId= "4", Branch = BranchType.SubLeft, Fill= "#3dbfc9" },
        new MindMapItem() { Id = "13", Label= "Competitors", ParentId= "6", Branch = BranchType.SubLeft, Fill="#3dbfc9" },
        new MindMapItem() { Id = "14", Label="Location", ParentId="6", Branch = BranchType.SubLeft, Fill= "#3dbfc9" },
        new MindMapItem() { Id = "15", Label= "Director", ParentId= "3", Branch = BranchType.SubRight, Fill="#3dbfc9" },
        new MindMapItem() { Id = "16", Label="Accounts Department", ParentId= "3", Branch = BranchType.SubRight, Fill= "#3dbfc9" },
        new MindMapItem() { Id = "17", Label="Administration", ParentId= "3", Branch = BranchType.SubRight, Fill="#3dbfc9" },
        new MindMapItem() { Id = "18", Label= "Development", ParentId="3", Branch = BranchType.SubRight, Fill= "#3dbfc9" },
        new MindMapItem() { Id = "19", Label= "Estimation", ParentId= "5", Branch = BranchType.SubRight, Fill="#3dbfc9" },
        new MindMapItem() { Id = "20", Label= "Profit", ParentId= "5", Branch = BranchType.SubRight, Fill= "#3dbfc9" },
        new MindMapItem(){ Id="21", Label="Funds", ParentId= "5", Branch = BranchType.SubRight, Fill= "#3dbfc9" }
    };

    private void NodeCreating(IDiagramObject obj)
    {
        Node node = obj as Node;
        MindMapItem data = node.Data is MindMapItem ? node.Data as MindMapItem : null;
        node.Height = 50;
        node.Width = 100;
        node.Shape = new BasicShape() { Type = NodeShapes.Basic, Shape = NodeBasicShapes.Ellipse };

        PointPort portLeft = new PointPort()
        {
            ID = "left",
            Offset = new DiagramPoint() { X = 0, Y = 0.5 },
            Height = 10,
            Width = 10,
        };

        PointPort portRight = new PointPort()
        {
            ID = "right",
            Offset = new DiagramPoint() { X = 1, Y = 0.5 },
            Height = 10,
            Width = 10,
        };

        if (data != null)
        {
            node.Style.Fill = data.Fill;
            node.Style.StrokeColor = data.Fill;
            node.Ports = new DiagramObjectCollection<PointPort>()
            {
                portLeft,portRight
            };
        }

        string content = data != null ? data.Label : "New Child";

        node.Annotations = new DiagramObjectCollection<ShapeAnnotation>()
        {
            new ShapeAnnotation()
            {
                Content = content,
                Style=new TextStyle(){Color="White",FontSize = 12,FontFamily="Segoe UI"},
                Offset=new DiagramPoint(){X=0.5,Y=0.5}
            }
        };
        node.Constraints &= ~NodeConstraints.Rotate;
    }

    private void ConnectorCreating(IDiagramObject obj)
    {
        Connector connector = obj as Connector;
        connector.Type = ConnectorSegmentType.Bezier;
        connector.Constraints = ConnectorConstraints.Default & ~ConnectorConstraints.Select;
        connector.Style = new ShapeStyle() { StrokeColor = "#4f4f4f", StrokeWidth = 1 };
        connector.TargetDecorator = new DecoratorSettings() { Shape = DecoratorShape.None };
        connector.SourceDecorator.Shape = DecoratorShape.None;
        Node sourceNode = diagram.GetObject(connector.SourceID) as Node;
        Node targetNode = diagram.GetObject(connector.TargetID) as Node;
        if (targetNode != null && targetNode.Data != null)
        {
            MindMapItem nodeInfo = (targetNode.Data as MindMapItem);
            if (nodeInfo.Branch == BranchType.Right || nodeInfo.Branch == BranchType.SubRight)
            {
                connector.SourcePortID = sourceNode.Ports[0].ID;
                connector.TargetPortID = targetNode.Ports[1].ID;
            }
            else if (nodeInfo.Branch == BranchType.Left || nodeInfo.Branch == BranchType.SubLeft)
            {
                connector.SourcePortID = sourceNode.Ports[1].ID;
                connector.TargetPortID = targetNode.Ports[0].ID;
            }
        }
    }
}

Refer to the following image.

Mind Map Diagram Created Using Blazor Diagram Component

We have created the mind map. Let’s now look at the user-friendly features available in the Blazor Diagram component.

Interactivity using keyboard and mouse

We can interactively build mind map diagrams using mouse, touch, and keyboard interfaces. Let’s see how to do so with code examples.

Quick commands

The Blazor Diagram component allows us to show frequently used commands as buttons near a selector. While creating a mind map, you can define actions like adding or removing a node as a command for a button and perform that action by just clicking the button.

Refer to the following code example.

<SfDiagramComponent ...... GetCustomTool="@GetCustomTool" SelectionSettings="@selectionSettings" SelectionChanging="OnSelectionChanging" Created="OnCreated">
  ........
  ........
</SfDiagramComponent>

@code
{
    SfDiagramComponent diagram;
    DiagramSelectionSettings selectionSettings = new DiagramSelectionSettings();
    DiagramObjectCollection<UserHandle> handles = new DiagramObjectCollection<UserHandle>();
    ........
    ........
    ........

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        if (firstRender)
        {
            UpdateHandle();
        }
    }

    private void UpdateHandle()
    {
        UserHandle deleteLeftHandle = AddHandle("DeleteRight", "delete", Direction.Right);

        UserHandle addRightHandle = AddHandle("AddLeft", "add", Direction.Left);

        UserHandle addLeftHandle = AddHandle("AddRight", "add", Direction.Right);

        UserHandle deleteRightHandle = AddHandle("DeleteLeft", "delete", Direction.Left);

        handles.Add(deleteLeftHandle);
        handles.Add(deleteRightHandle);
        handles.Add(addLeftHandle);
        handles.Add(addRightHandle);

        selectionSettings.UserHandles = handles;
    }

    private UserHandle AddHandle(string name, string path, Direction direction)
    {
        UserHandle handle = new UserHandle()
            {
                Name = name,
                Visible = true,
                Offset = 0.5,
                Side = direction,
                Margin = new DiagramThickness() { Top = 0, Bottom = 0, Left = 0, Right = 0 }
            };
        if (path == "delete")
        {
            handle.PathData = "M1.0000023,3 L7.0000024,3 7.0000024,8.75 C7.0000024,9.4399996 6.4400025,10 5.7500024,10 L2.2500024,10 C1.5600024,10 1.0000023,9.4399996 1.0000023,8.75 z M2.0699998,0 L5.9300004,0 6.3420029,0.99999994 8.0000001,0.99999994 8.0000001,2 0,2 0,0.99999994 1.6580048,0.99999994 z";
        }
        else
        {
            handle.PathData = "M4.0000001,0 L6,0 6,4.0000033 10,4.0000033 10,6.0000033 6,6.0000033 6,10 4.0000001,10 4.0000001,6.0000033 0,6.0000033 0,4.0000033 4.0000001,4.0000033 z";
        }
        return handle;
    }

    private void OnSelectionChanging(SelectionChangingEventArgs args)
    {
        if (args.NewValue.Count > 0)
        {
            if (args.NewValue[0] is Node && (args.NewValue[0] as Node).Data != null)
            {
                BranchType type = ((args.NewValue[0] as Node).Data as MindMapItem).Branch;
                if (type == BranchType.Root)
                {
                    selectionSettings.UserHandles[0].Visible = false;
                    selectionSettings.UserHandles[1].Visible = false;
                    selectionSettings.UserHandles[2].Visible = true;
                    selectionSettings.UserHandles[3].Visible = true;
                }
                else if (type == BranchType.Left || type == BranchType.SubLeft)
                {
                    selectionSettings.UserHandles[0].Visible = false;
                    selectionSettings.UserHandles[1].Visible = true;
                    selectionSettings.UserHandles[2].Visible = true;
                    selectionSettings.UserHandles[3].Visible = false;
                }
                else if (type == BranchType.Right || type == BranchType.SubRight)
                {
                    selectionSettings.UserHandles[0].Visible = true;
                    selectionSettings.UserHandles[1].Visible = false;
                    selectionSettings.UserHandles[2].Visible = false;
                    selectionSettings.UserHandles[3].Visible = true;
                }
            }
        }
    }
    // Method to customize the tool.
    public InteractionControllerBase GetCustomTool(DiagramElementAction action, string id)
    {
        InteractionControllerBase tool = null;
        if (id == "AddLeft")
        {
            tool = new AddRightTool(diagram);
        }
        else if (id == "AddRight")
        {
            tool = new AddLeftTool(diagram);
        }
        else
        {
            tool = new DeleteTool(diagram);
        }
        return tool;
    }

    // Custom tool to add the node.
    public class AddLeftTool : DragController
    {
        SfDiagramComponent diagram;
        public AddLeftTool(SfDiagramComponent Diagram) : base(Diagram)
        {
            diagram = Diagram;
        }
        public override async void OnMouseDown(DiagramMouseEventArgs args)
        {
            int newChildID = diagram.Nodes.Count + 1;
            string newchildColor = "";
            BranchType type = (diagram.SelectionSettings.Nodes[0].Data as MindMapItem).Branch;
            BranchType childType = BranchType.Left;

            switch (type.ToString())
            {
                case "Root":
                    childType = BranchType.Left;
                    break;
                case "Left":
                    childType = BranchType.SubLeft;
                    break;
                case "SubLeft":
                    childType = BranchType.SubLeft;
                    break;
            }

            if (diagram.SelectionSettings.Nodes[0].Style.Fill == "#034d6d")
            {
                newchildColor = "#1b80c6";
            }
            else
            {
                newchildColor = "#3dbfc9";
            }

            MindMapItem childNode = new MindMapItem ()
            {
               Id = newChildID.ToString(),
               ParentId = (diagram.SelectionSettings.Nodes[0].Data as MindMapItem).Id,
               Fill = newchildColor,
               Branch = childType,
               Label = "New Child"
            };
            diagram.BeginUpdate();
            await UpdatePortConnection(childNode, diagram);
            await diagram.EndUpdate();
            MindmapData.Add(childNode);
            diagram.ClearSelection();
            base.OnMouseDown(args);
            diagram.Select(new ObservableCollection<IDiagramObject>() { diagram.Nodes[diagram.Nodes.Count - 1] });
            diagram.StartTextEdit(diagram.Nodes[diagram.Nodes.Count - 1]);
            this.InAction = true;
        }
    }
    private static async Task UpdatePortConnection(MindMapItem childNode, SfDiagramComponent diagram)
    {
        Node node = new Node()
        {
           Data = childNode,
        };
        Connector connector = new Connector()
        {
           TargetID = node.ID,
           SourceID = diagram.SelectionSettings.Nodes[0].ID
        };
        await diagram.AddDiagramElements(new DiagramObjectCollection<NodeBase>() { node, connector });
        Node sourceNode = diagram.GetObject(connector.SourceID) as Node;
        Node targetNode = diagram.GetObject(connector.TargetID) as Node;
        if (targetNode != null && targetNode.Data != null)
        {
            MindMapItem nodeInfo = (targetNode.Data as MindMapItem);
            if (nodeInfo.Branch == BranchType.Right || nodeInfo.Branch == BranchType.SubRight)
            {
                connector.SourcePortID = sourceNode.Ports[0].ID;
                connector.TargetPortID = targetNode.Ports[1].ID;
            }
            else if (nodeInfo.Branch == BranchType.Left || nodeInfo.Branch == BranchType.SubLeft)
            {
                connector.SourcePortID = sourceNode.Ports[1].ID;
                connector.TargetPortID = targetNode.Ports[0].ID;
            }
        }
        await diagram.DoLayout();
    }
    // Custom tool to add the node.
    public class AddRightTool : DragController
    {
        SfDiagramComponent diagram;
        public AddRightTool(SfDiagramComponent Diagram) : base(Diagram)
        {
            diagram = Diagram;
        }
        public override async void OnMouseDown(DiagramMouseEventArgs args)
        {
            int newChildID = diagram.Nodes.Count + 1;
            string newchildColor = "";
            BranchType type = (diagram.SelectionSettings.Nodes[0].Data as MindMapItem).Branch;
            BranchType childType = BranchType.Left;

            switch (type.ToString())
            {
                case "Root":
                    childType = BranchType.Right;
                    break;
                case "Right":
                    childType = BranchType.SubRight;
                    break;
                case "SubRight":
                    childType = BranchType.SubRight;
                    break;
            }

            if (diagram.SelectionSettings.Nodes[0].Style.Fill == "#034d6d")
            {
                newchildColor = "#1b80c6";
            }
            else
            {
                newchildColor = "#3dbfc9";
            }

            MindMapItem childNode = new MindMapItem ()
            {
                Id = newChildID.ToString(),
                ParentId = (diagram.SelectionSettings.Nodes[0].Data as MindMapItem).Id,
                Fill = newchildColor,
                Branch = childType,
                Label = "New Child"
            };
            diagram.BeginUpdate();
            await UpdatePortConnection(childNode, diagram);
            await diagram.EndUpdate();
            MindmapData.Add(childNode);
            diagram.ClearSelection();
            base.OnMouseDown(args);
            diagram.Select(new ObservableCollection<IDiagramObject>() { diagram.Nodes[diagram.Nodes.Count - 1] });
            diagram.StartTextEdit(diagram.Nodes[diagram.Nodes.Count - 1]);
            this.InAction = true;
        }
    }

    public class DeleteTool : DragController
    {
        SfDiagramComponent sfDiagram;
        Node deleteObject = null;
        public DeleteTool(SfDiagramComponent Diagram) : base(Diagram)
        {
            sfDiagram = Diagram;
        }
        public override void OnMouseDown(DiagramMouseEventArgs args)
        {
            deleteObject = (sfDiagram.SelectionSettings.Nodes[0]) as Node;
        }
        public override void OnMouseUp(DiagramMouseEventArgs args)
        {
            if (deleteObject != null)
            {
                sfDiagram.BeginUpdate();
                RemoveData(deleteObject, sfDiagram);
                sfDiagram.Nodes.Remove(deleteObject);
                _ = sfDiagram.EndUpdate();
                _ = sfDiagram.RefreshDataSource();
            }
            base.OnMouseUp(args);
            this.InAction = true;
        }
    }

    private static void RemoveData(Node node, SfDiagramComponent diagram)
    {
        if (node.OutEdges.Count > 0)
        {
            for (int i = 0; i < node.OutEdges.Count; i++)
            {
                Connector connector = diagram.GetObject(node.OutEdges[i]) as Connector;
                Node targetnode = diagram.GetObject(connector.TargetID) as Node;
                if (targetnode.OutEdges.Count > 0)
                {
                    RemoveData(targetnode, diagram);
                }
                else
                {
                    MindmapData.Remove(targetnode.Data as MindMapItem);
                }
            }
            MindmapData.Remove(node.Data as MindMapItem);
        }
        else
        {
            MindmapData.Remove(node.Data as MindMapItem);
        }
    }
Quickly Create a Mind Map Using Commands in Blazor Diagram Component

Shortcut keys

Shortcut keys help us quickly create mind map diagrams. You can specify the action that should be executed based on the specific key gestures.

For example, you can specify the Tab key to add a new node to the right, Shift+Tab to the left, and the Delete key to delete a node.

Refer to the following code example.

<SfDiagramComponent @ref="@diagram" ........>
    ........
    ........
    ........

    <CommandManager Commands="commands" Execute="@ExecuteCommand" CanExecute="@CanExecute" />
</SfDiagramComponent>

@code
{
    SfDiagramComponent diagram;
    DiagramObjectCollection<KeyboardCommand> commands;
    ........
    ........
    ........
    ........
    protected override void OnInitialized()
    {
    ........
    ........

        commands = new DiagramObjectCollection<KeyboardCommand>()
        {
            CreateCustomCommand("AddLeftChild",DiagramKeys.Tab,ModifierKeys.None),
            CreateCustomCommand("AddRightChild",DiagramKeys.Tab,ModifierKeys.Shift),
            CreateCustomCommand("DeleteChild",DiagramKeys.Delete,ModifierKeys.None),
        };
    }

    // Method to determine whether this command can execute or not.
    public void CanExecute(CommandKeyArgs args)
    {
        args.CanExecute = true;
    }
    
    // Method to execute the custom command.
    public void ExecuteCommand(CommandKeyArgs obj)
    {
        Node node = (diagram.SelectionSettings.Nodes[0]) as Node;
        if(node != null)
        {
            BranchType type = (node.Data as MindMapItem).Branch;
            if(type == BranchType.Root)
            {
                switch (obj.Name)
                {
                    case "AddLeftChild":
                        _ = this.AddLeftChild();
                        break;
                    case "AddRightChild":
                        _ = this.AddRightChild();
                        break;
                }                
            }
            else
            {
                switch (obj.Name)
                {
                    case "AddRightChild":
                    case "AddLeftChild":
                        _ = (type == BranchType.Left || type == BranchType.SubLeft) ? this.AddLeftChild() : this.AddRightChild();
                        break;
                    case "DeleteChild":
                        _ = this.DeleteChild();
                        break;
                }
            }
        }
    }
    
    // Method to create custom command.
    private KeyboardCommand CreateCustomCommand(string name, DiagramKeys key, ModifierKeys modifierkey)
    {
        KeyboardCommand command = new KeyboardCommand()
        {
           Name = name,
           Gesture = new KeyGesture() { Key = key, Modifiers = modifierkey }
        };
        return command;
    }

    private async Task AddLeftChild()
    {

        int newChildID = diagram.Nodes.Count + 1;
        string newchildColor = "";
        BranchType type = (diagram.SelectionSettings.Nodes[0].Data as MindMapItem).Branch;
        BranchType childType = BranchType.Left;

        switch (type.ToString())
        {
            case "Root":
                childType = BranchType.Left;
                break;
            case "Left":
            case "SubLeft":
                childType = BranchType.SubLeft;
                break;
        }

        if (diagram.SelectionSettings.Nodes[0].Style.Fill == "#034d6d")
        {
            newchildColor = "#1b80c6";
        }
        else
        {
            newchildColor = "#3dbfc9";
        }

        MindMapItem childNode = new MindMapItem()
        {
            Id = newChildID.ToString(),
            ParentId = (diagram.SelectionSettings.Nodes[0].Data as MindMapItem).Id,
            Fill = newchildColor,
            Branch = childType,
            Label = "New Child"
        };
        diagram.BeginUpdate();
        await UpdatePortConnection(childNode, diagram);
        await diagram.EndUpdate();
        MindmapData.Add(childNode);
        diagram.ClearSelection();
        diagram.Select(new ObservableCollection<IDiagramObject>() { diagram.Nodes[diagram.Nodes.Count - 1] });
        diagram.StartTextEdit(diagram.Nodes[diagram.Nodes.Count - 1]);
    }

    private async Task AddRightChild()
    {
        int newChildID = diagram.Nodes.Count + 1;
        string newchildColor = "";
        BranchType type = (diagram.SelectionSettings.Nodes[0].Data as MindMapItem).Branch;
        BranchType childType = BranchType.Left;

        switch (type.ToString())
        {
            case "Root":
                childType = BranchType.Right;
                break;
            case "Right":
            case "SubRight":
                childType = BranchType.SubRight;
                break;
        }

        if (diagram.SelectionSettings.Nodes[0].Style.Fill == "#034d6d")
        {
            newchildColor = "#1b80c6";
        }
        else
        {
            newchildColor = "#3dbfc9";
        }

        MindMapItem childNode = new MindMapItem()
        {
            Id = newChildID.ToString(),
            ParentId = (diagram.SelectionSettings.Nodes[0].Data as MindMapItem).Id,
            Fill = newchildColor,
            Branch = childType,
            Label = "New Child"
        };
        diagram.BeginUpdate();
        await UpdatePortConnection(childNode, diagram);
        await diagram.EndUpdate();
        MindmapData.Add(childNode);
        diagram.ClearSelection();
        diagram.Select(new ObservableCollection<IDiagramObject>() { diagram.Nodes[diagram.Nodes.Count - 1] });
        diagram.StartTextEdit(diagram.Nodes[diagram.Nodes.Count - 1]);
    }

    private async Task DeleteChild()
    {
        Node deleteObject = (diagram.SelectionSettings.Nodes[0]) as Node;
        if (deleteObject != null)
        {
            BranchType type = (deleteObject.Data as MindMapItem).Branch;
            if (type != BranchType.Root)
            {
                diagram.BeginUpdate();
                RemoveData(deleteObject, diagram);
                diagram.Nodes.Remove(deleteObject);
                _ = diagram.EndUpdate();
                _ = diagram.RefreshDataSource();
            }
        }
    }
Interactively Creating a Mind Map Diagram Using Keyboard Shortcut Keys in the Blazor Diagram Component

Expand and collapse child nodes

You can expand and collapse the child nodes in the mind map using the ExpandIcon and CollapseIcon properties.

Refer to the following code example.

private void NodeCreating(IDiagramObject obj)
{
   Node node = obj as Node;
   ........
   ........
   ........

    node.ExpandIcon = new DiagramExpandIcon()
    {
       Shape = DiagramExpandIcons.Minus,
       Height = 15,
       Width = 15,
       CornerRadius = 10,
       OffsetX = (branch == BranchType.Root) ? 0.5 : (branch == BranchType.Right || branch == BranchType.SubRight) ? 0 : 1,
       OffsetY = (branch == BranchType.Root) ? 1 : (branch == BranchType.Right || branch == BranchType.SubRight) ? 0.5 : 0.5
     };
     node.CollapseIcon = new DiagramCollapseIcon()
     {
          Shape = DiagramCollapseIcons.Plus,
          Height = 15,
          Width = 15,
          CornerRadius = 10,
          OffsetX = (branch == BranchType.Root) ? 0.5 : (branch == BranchType.Right || branch == BranchType.SubRight) ? 0 : 1,
          OffsetY = (branch == BranchType.Root) ? 1 : (branch == BranchType.Right || branch == BranchType.SubRight) ? 0.5 : 0.5
      };
}
Expanding and Collapsing Nodes in Blazor Mind Map Diagram

Drag and drop

You can edit the mind map tree structure by dragging the nodes to the required destination. To allow this, add the following code to the Blazor Diagram component’s drop method.

<SfDiagramComponent ........ DragDrop="@Drop">
    ........
    ........
    ........
</SfDiagramComponent>

@code
{
    SfDiagramComponent diagram;
    ........
    ........
    ........

    private async Task Drop(DropEventArgs args)
    {
        diagram.BeginUpdate();
        diagram.StartGroupAction();
        Node element = (args.Element as DiagramSelectionSettings).Nodes[0] as Node;
        Node targetNode = args.Target as Node;
        bool isParent = false;
        List<string> edges = element.OutEdges;
        if (edges != null && edges.Count > 0)
        {
            for (int i = 0; i < edges.Count; i++)
            {
                Connector connector = GetConnector(diagram.Connectors, edges[i]);
                Node childNode = GetNode(diagram.Nodes, connector.TargetID);
                if (targetNode != null && targetNode.ID == childNode.ID)
                    isParent = true;
            }
        }
        if (!isParent)
        {
            Connector connector = GetConnector(diagram.Connectors, element.InEdges[0]);
            Node childNode = GetNode(diagram.Nodes, connector.TargetID);
            diagram.BeginUpdate();
            connector.SourceID = targetNode.ID;
            (element.Data as MindMapItem).Branch = (targetNode.Data as MindMapItem).Branch;
            GetOrientation(targetNode, connector);
            if (edges != null && edges.Count > 0)
            {
                UpdateLayout(edges, targetNode);
            }
            _ = diagram.EndUpdate();
            await diagram.DoLayout();
        }
        else { _ = diagram.DoLayout(); }
        diagram.EndGroupAction();
        _ = diagram.EndUpdate();
    }


    private void UpdateLayout(List<string> edges, Node Target)
    {
        for (int i = 0; i < edges.Count; i++)
        {
            Connector childconnector = GetConnector(diagram.Connectors, edges[i]);
            Node node = GetNode(diagram.Nodes, childconnector.TargetID);
            (node.Data as MindMapItem).Branch = (Target.Data as MindMapItem).Branch;
            List<string> childEdges = node.OutEdges;
            if (childEdges != null && childEdges.Count > 0)
            {
                UpdateLayout(childEdges, Target);
            }
            GetOrientation(Target, childconnector);
        }
    }
    private void GetOrientation(Node node, Connector connector)
    {
        BranchType branch = (node.Data as MindMapItem).Branch;
        if (branch == BranchType.Left || branch == BranchType.SubLeft)
        {
            connector.SourcePortID = "right";
            connector.TargetPortID = "left";
        }
        else if (branch == BranchType.Right || branch == BranchType.SubRight)
        {
            connector.SourcePortID = "left";
            connector.TargetPortID = "right";
        }
    }

    private Connector GetConnector(DiagramObjectCollection<Connector> diagramConnectors, string name)
    {
        for (int i = 0; i < diagramConnectors.Count; i++)
        {
            if (diagramConnectors[i].ID == name)
            {
                return diagramConnectors[i];
            }
        }
        return null;
    }

    private Node GetNode(DiagramObjectCollection<Node> diagramNodes, string name)
    {
        for (int i = 0; i < diagramNodes.Count; i++)
        {
            if (diagramNodes[i].ID == name)
            {
                return diagramNodes[i];
            }
        }
        return null;
    }
Dragging and Dropping Nodes in the Blazor Mind Map

Shape customization

We can easily customize the appearance of each level of nodes by adding backgrounds, border styles, and text styles and visualizing them with a custom UI design.

The NodeCreating and ConnectorCreating methods help specify the custom shape and style for each node and connector based on its level value.

Refer to the following code example.

private void NodeCreating(IDiagramObject obj)
{
   Node node = obj as Node;
   MindMapItem data = node.Data is MindMapItem? node.Data as MindMapItem: null;
   node.Height = 50;
   node.Width = 120;
   if (data is MindMapItem && data.Branch == BranchType.Root)
   {
       node.Shape = new PathShape() { Type = NodeShapes.Path, Data = "M55.7315 17.239C57.8719 21.76 54.6613 27.788 47.1698 26.0787C46.0997 32.309 33.2572 35.323 28.9764 29.2951C25.7658 35.323 10.7829 33.816 10.7829 26.0787C3.29143 30.802 -0.989391 20.253 2.22121 17.239C-0.989317 14.2249 2.22121 6.68993 10.7829 8.39934C13.9935 -0.845086 25.7658 -0.845086 28.9764 5.18301C32.187 0.661909 45.0294 0.661908 47.1698 8.39934C52.5209 5.18301 60.0123 12.7179 55.7315 17.239Z" };
   }
   else if (data is MindMapItem && (data.Branch == BranchType.Left || data.Branch == BranchType.Right))
   {
      node.Shape = new BasicShape() { Type = NodeShapes.Basic, Shape = NodeBasicShapes.Rectangle };
   }
   else
       node.Shape = new BasicShape() { Type = NodeShapes.Basic, Shape = NodeBasicShapes.Ellipse };    ........
        
        ........
        ........
        ........

}

private void ConnectorCreating(IDiagramObject obj)
{
    Connector connector = obj as Connector;
    connector.Type = ConnectorSegmentType.Bezier;
    connector.Constraints = ConnectorConstraints.Default & ~ConnectorConstraints.Select;
    connector.TargetDecorator = new DecoratorSettings() { Shape = DecoratorShape.None };
    connector.SourceDecorator.Shape = DecoratorShape.None;
    Node sourceNode = diagram.GetObject(connector.SourceID) as Node;
    if (sourceNode != null && sourceNode.Data is MindMapItem)
    {
       MindMapItem data = sourceNode.Data as MindMapItem;
       if (data is MindMapItem && data.Branch == BranchType.Root)
       {
           connector.Style = new ShapeStyle() { StrokeColor = "#8E44AD", StrokeWidth = 5 };
       }data
       else if (data is MindMapItem && (data.Branch == BranchType.Left || data.Branch == BranchType.Right))
       {
           connector.Style = new ShapeStyle() { StrokeColor = "#3498DB", StrokeWidth = 5 };
       }
       else
           connector.Style = new ShapeStyle() { StrokeColor = "#3dbfc9", StrokeWidth = 5 };
    }

    ........
    ........
    ........

}
Customizing Node Shapes in a Blazor Mind Map

Spacing and margin

We can adjust the space between each level horizontally and vertically and define a margin around the mind map diagram.

Refer to the following code example.

<SfDiagramComponent @ref="@diagram" Height="690px" InteractionController="@DiagramInteractions.ZoomPan" NodeCreating="@NodeCreating" ConnectorCreating="@ConnectorCreating">
 <DataSourceSettings ID="Id" ParentID="ParentId" DataSource="DataSource"></DataSourceSettings>
 <Layout Type="LayoutType.MindMap" HorizontalSpacing="90" VerticalSpacing="50">
   <LayoutMargin Top="10" Bottom="10" Right="10" Left="10"></LayoutMargin>
 </Layout>
 <SnapSettings Constraints="SnapConstraints.None"/>
</SfDiagramComponent>
Customizing Node Spacing in Blazor Mind Map

Zooming and panning

Viewing a large mind map on a small screen can be challenging. To solve this, we’ll use the zooming and panning features to get a detailed view.

You can zoom in and out of the mind map diagram using the Ctrl + mouse wheel shortcut key.

Refer to the following code example to enable zooming and panning support in the Blazor Diagram component.

<SfDiagramComponent @ref="@Diagram" InteractionController="@DiagramInteractions.ZoomPan">
    ………..
    ………..
</SfDiagramComponent>

Exporting

You can easily export the mind map to different image formats such as PNG, JPEG, and SVG. Refer to the following code example.

@using Syncfusion.Blazor.Diagram

<input type="button" @>

Note: For complete details, refer to the creating a mind map using the Blazor Diagram component documentation.

GitHub reference

Check out the demo for creating a mind map using the Blazor Diagram component in a WebAssembley app on GitHub or Syncfusion’s website.

Conclusion

Thanks for reading! We have learned how to create and customize a mind map using the Syncfusion Blazor Diagram component. You can also create flowcharts, organizational charts, and more with the Diagram component. Try it out and leave your feedback in the comments section.

For existing customers, the new version of Essential Studio® is available for download from the License and Downloads page. If you are not a Syncfusion customer, you can try our 30-day free trial to check out our available features.

For questions, you can contact us through our support forum, support portal, or feedback portal. We are always happy to assist you!

Related blogs

Meet the Author

Sarathkumar V

Sarathkumar is a Product Manager for Diagram and HeatMap products at Syncfusion. He has been a .NET developer since 2013. He is specialized in WPF, UWP, Xamarin and other .Net frameworks.