Skip to content

Commit fdfffa7

Browse files
committed
1007315: ForceDirected
1 parent f892c14 commit fdfffa7

8 files changed

Lines changed: 704 additions & 92 deletions
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
@page "/ForceDirectedTreeDataSource"
2+
@using Syncfusion.Blazor.Diagram
3+
4+
<SfDiagramComponent Height="600px" NodeCreating="@OnNodeCreating">
5+
<DataSourceSettings ID="Id" ParentID="Manager" DataSource="@_dataSource"></DataSourceSettings>
6+
<Layout Type="LayoutType.ForceDirectedTree" @bind-ForceDirectedTreeLayoutSettings="@_forceDirectedSettings"></Layout>
7+
<SnapSettings Constraints="@SnapConstraints.None"></SnapSettings>
8+
</SfDiagramComponent>
9+
10+
@code
11+
{
12+
private ForceDirectedTreeLayoutSettings _forceDirectedSettings = new ForceDirectedTreeLayoutSettings()
13+
{
14+
ConnectorLength = 100,
15+
AttractionStrength = 0.7,
16+
RepulsionStrength = 6000,
17+
MaximumIteration = 350
18+
};
19+
20+
private void OnNodeCreating(IDiagramObject obj)
21+
{
22+
Node node = obj as Node;
23+
node.Height = 40;
24+
node.Width = 40;
25+
node.Shape = new BasicShape()
26+
{
27+
Type = NodeShapes.Basic,
28+
Shape = NodeBasicShapes.Ellipse,
29+
};
30+
node.Style = new ShapeStyle() { Fill = "darkcyan", StrokeWidth = 3, StrokeColor = "Black" };
31+
}
32+
33+
public class ForceDirectedDetails
34+
{
35+
public string Id { get; set; }
36+
public string Role { get; set; }
37+
public string Manager { get; set; }
38+
}
39+
40+
private List<ForceDirectedDetails> _dataSource = new List<ForceDirectedDetails>()
41+
{
42+
new ForceDirectedDetails() { Id = "parent", Role = "Board" },
43+
new ForceDirectedDetails() { Id = "1", Role = "General Manager", Manager = "parent" },
44+
new ForceDirectedDetails() { Id = "2", Role = "Human Resource Manager", Manager = "1" },
45+
new ForceDirectedDetails() { Id = "3", Role = "Trainers", Manager = "2" },
46+
new ForceDirectedDetails() { Id = "4", Role = "Recruiting Team", Manager = "2" },
47+
new ForceDirectedDetails() { Id = "5", Role = "Finance Asst. Manager", Manager = "2" },
48+
new ForceDirectedDetails() { Id = "6", Role = "Design Manager", Manager = "1" },
49+
new ForceDirectedDetails() { Id = "7", Role = "Design Supervisor", Manager = "6" },
50+
new ForceDirectedDetails() { Id = "8", Role = "Development Supervisor", Manager = "6" },
51+
new ForceDirectedDetails() { Id = "9", Role = "Drafting Supervisor", Manager = "6" },
52+
new ForceDirectedDetails() { Id = "10", Role = "Operation Manager", Manager = "1" },
53+
new ForceDirectedDetails() { Id = "11", Role = "Statistic Department", Manager = "10" },
54+
new ForceDirectedDetails() { Id = "12", Role = "Logistic Department", Manager = "10" },
55+
new ForceDirectedDetails() { Id = "16", Role = "Marketing Manager", Manager = "1" },
56+
new ForceDirectedDetails() { Id = "17", Role = "Oversea sales Manager", Manager = "16" },
57+
new ForceDirectedDetails() { Id = "18", Role = "Petroleum Manager", Manager = "16" },
58+
new ForceDirectedDetails() { Id = "20", Role = "Service Dept. Manager", Manager = "16" },
59+
new ForceDirectedDetails() { Id = "21", Role = "Quality Department", Manager = "16" }
60+
};
61+
}
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
@page "/ForceDirectedTreeLayout"
2+
3+
@using Syncfusion.Blazor.Diagram
4+
5+
<SfDiagramComponent @ref="_diagramComponent" Height="690px" Width="100%" @bind-Nodes="@_nodes" @bind-Connectors="@_connectors" Created="@OnCreated">
6+
<SnapSettings Constraints="@SnapConstraints.None"></SnapSettings>
7+
<Layout Type="LayoutType.ForceDirectedTree" @bind-ForceDirectedTreeLayoutSettings="@_layoutSettings"></Layout>
8+
</SfDiagramComponent>
9+
10+
@code {
11+
private SfDiagramComponent _diagramComponent;
12+
private DiagramObjectCollection<Node> _nodes = new DiagramObjectCollection<Node>();
13+
private DiagramObjectCollection<Connector> _connectors = new DiagramObjectCollection<Connector>();
14+
15+
private ForceDirectedTreeLayoutSettings _layoutSettings = new ForceDirectedTreeLayoutSettings
16+
{
17+
ConnectorLength = 120,
18+
MaximumIteration = 1500,
19+
RepulsionStrength = 20000,
20+
AttractionStrength = 0.8
21+
};
22+
23+
private int _departmentsUnderCeo = 4;
24+
private int _managersPerDepartment = 4;
25+
private int _teamsPerManager = 6;
26+
27+
protected override void OnInitialized()
28+
{
29+
InitializeDiagram();
30+
}
31+
32+
private void InitializeDiagram()
33+
{
34+
List<OrganizationItem> organizationData = GetCompanyOrganizationData();
35+
PopulateDiagramFromOrganizationData(organizationData);
36+
}
37+
38+
private void PopulateDiagramFromOrganizationData(IEnumerable<OrganizationItem> organizationItems)
39+
{
40+
Dictionary<string, OrganizationItem> itemsById = organizationItems.ToDictionary(item => item.Id);
41+
foreach (OrganizationItem item in organizationItems)
42+
{
43+
Node node = CreateOrganizationNode(item);
44+
_nodes!.Add(node);
45+
if (!string.IsNullOrEmpty(item.ParentId) && itemsById.ContainsKey(item.ParentId))
46+
{
47+
_connectors!.Add(CreateNodeConnector(item.ParentId, item.Id));
48+
}
49+
}
50+
}
51+
52+
private void OnCreated()
53+
{
54+
FitOptions options = new FitOptions() { Mode = FitMode.Both, Region = DiagramRegion.Content };
55+
_diagramComponent.FitToPage(options);
56+
}
57+
58+
private Node CreateOrganizationNode(OrganizationItem item)
59+
{
60+
ShapeStyle nodeStyle = new ShapeStyle { Fill = "orange", StrokeWidth = 2, StrokeColor = "#8c8c8c" };
61+
double nodeWidth = 35;
62+
double nodeHeight = 35;
63+
Shape nodeShape = new BasicShape() { Shape = NodeBasicShapes.Ellipse };
64+
switch (item.Level)
65+
{
66+
case OrganizationLevel.Header:
67+
nodeStyle.Fill = "#f39c12";
68+
nodeWidth = nodeHeight = 140;
69+
nodeShape = new BasicShape { Shape = NodeBasicShapes.Ellipse };
70+
break;
71+
case OrganizationLevel.Department:
72+
nodeStyle.Fill = "#27ae60";
73+
nodeWidth = nodeHeight = 120;
74+
nodeShape = new BasicShape { Shape = NodeBasicShapes.Ellipse };
75+
break;
76+
case OrganizationLevel.Manager:
77+
nodeStyle.Fill = "#2980b9";
78+
nodeShape = new BasicShape { Shape = NodeBasicShapes.Ellipse };
79+
nodeWidth = nodeHeight = 100;
80+
break;
81+
case OrganizationLevel.Team:
82+
nodeStyle.Fill = "#f39c12";
83+
nodeShape = new BasicShape { Shape = NodeBasicShapes.Ellipse };
84+
nodeWidth = nodeHeight = 80;
85+
break;
86+
}
87+
return new Node
88+
{
89+
ID = item.Id,
90+
Width = nodeWidth,
91+
Height = nodeHeight,
92+
Shape = nodeShape,
93+
Annotations = new DiagramObjectCollection<ShapeAnnotation>
94+
{
95+
new ShapeAnnotation
96+
{
97+
ID = $"{item.Id}_label",
98+
Content = item.Name,
99+
Style = new TextStyle() { FontSize = 18, Bold = true, Color = "white" }
100+
}
101+
},
102+
Style = nodeStyle
103+
};
104+
}
105+
106+
private Connector CreateNodeConnector(string sourceNodeId, string targetNodeId)
107+
{
108+
return new Connector
109+
{
110+
ID = $"{sourceNodeId}_{targetNodeId}",
111+
SourceID = sourceNodeId,
112+
TargetID = targetNodeId,
113+
Type = ConnectorSegmentType.Straight
114+
};
115+
}
116+
117+
public enum OrganizationLevel
118+
{
119+
Header,
120+
Department,
121+
Manager,
122+
Team
123+
}
124+
125+
public class OrganizationItem
126+
{
127+
public string Id { get; set; } = "";
128+
public string? ParentId { get; set; }
129+
public string Name { get; set; } = "";
130+
public OrganizationLevel Level { get; set; }
131+
}
132+
133+
private static List<OrganizationItem> BuildOrganizationData(int departmentCount, int managersPerDepartment, int teamsPerManager)
134+
{
135+
List<OrganizationItem> organizationData = new List<OrganizationItem>
136+
{
137+
new OrganizationItem { Id = "departments", ParentId = null, Name = "Departments", Level = OrganizationLevel.Header }
138+
};
139+
// Create departments
140+
for (int departmentIndex = 1; departmentIndex <= departmentCount; departmentIndex++)
141+
{
142+
string departmentId = $"dept_{departmentIndex}";
143+
organizationData.Add(new OrganizationItem { Id = departmentId, ParentId = "departments", Name = $"Department {departmentIndex}", Level = OrganizationLevel.Department });
144+
// Create managers for each department
145+
for (int managerIndex = 1; managerIndex <= managersPerDepartment; managerIndex++)
146+
{
147+
string managerId = $"{departmentId}_mgr_{managerIndex}";
148+
organizationData.Add(new OrganizationItem { Id = managerId, ParentId = departmentId, Name = $"Manager {departmentIndex}.{managerIndex}", Level = OrganizationLevel.Manager });
149+
// Create teams for each manager
150+
for (int teamIndex = 1; teamIndex <= teamsPerManager; teamIndex++)
151+
{
152+
string teamId = $"{managerId}_team_{teamIndex}";
153+
organizationData.Add(new OrganizationItem
154+
{
155+
Id = teamId,
156+
ParentId = managerId,
157+
Name = $"Team {departmentIndex}.{managerIndex}.{teamIndex}",
158+
Level = OrganizationLevel.Team
159+
});
160+
}
161+
}
162+
}
163+
return organizationData;
164+
}
165+
166+
// Realistic software company hierarchy: 1 CEO with 4 departments, each with managers and their respective teams
167+
private static List<OrganizationItem> GetCompanyOrganizationData()
168+
{
169+
List<OrganizationItem> companyData = new List<OrganizationItem>();
170+
// CEO level
171+
companyData.Add(new OrganizationItem { Id = "departments", ParentId = null, Name = "Departments", Level = OrganizationLevel.Header });
172+
// Department level (Level 2)
173+
List<OrganizationItem> departmentList = new List<OrganizationItem>
174+
{
175+
new OrganizationItem { Id = "uxTeam", ParentId = "departments", Name = "UX Team", Level = OrganizationLevel.Department },
176+
new OrganizationItem { Id = "devTeam", ParentId = "departments", Name = "Development Team", Level = OrganizationLevel.Department },
177+
new OrganizationItem { Id = "salesTeam", ParentId = "departments", Name = "Sales Team", Level = OrganizationLevel.Department },
178+
new OrganizationItem { Id = "hrTeam", ParentId = "departments", Name = "HR Team", Level = OrganizationLevel.Department }
179+
};
180+
foreach (OrganizationItem department in departmentList)
181+
companyData.Add(department);
182+
// Managers per department (Level 3) - 4 managers per department
183+
Dictionary<string, (string id, string name)[]> managersByDepartment = new Dictionary<string, (string id, string name)[]>
184+
{
185+
["uxTeam"] = new[]
186+
{
187+
("mgr1", "Manager-1"),
188+
("mgr2", "Manager-2"),
189+
},
190+
["devTeam"] = new[]
191+
{
192+
("po1", "PO-1"),
193+
("po2", "PO-2"),
194+
("po3", "PO-3"),
195+
("po4", "PO-4"),
196+
},
197+
["salesTeam"] = new[]
198+
{
199+
("agm1", "AGM-1"),
200+
("agm2", "AGM-2"),
201+
},
202+
["hrTeam"] = new[]
203+
{
204+
("hr_mgr", "Manager"),
205+
},
206+
};
207+
foreach (string departmentKey in managersByDepartment.Keys)
208+
{
209+
foreach ((string id, string name) manager in managersByDepartment[departmentKey])
210+
companyData.Add(new OrganizationItem { Id = manager.id, ParentId = departmentKey, Name = manager.name, Level = OrganizationLevel.Manager });
211+
}
212+
// Teams per manager (Level 4) - Variable count based on requirements
213+
Dictionary<string, int> teamCountByManagerId = new Dictionary<string, int>
214+
{
215+
["mgr1"] = 3,
216+
["mgr2"] = 3,
217+
["po1"] = 4,
218+
["po2"] = 4,
219+
["po3"] = 4,
220+
["po4"] = 4,
221+
["agm1"] = 3,
222+
["agm2"] = 3,
223+
["hr_mgr"] = 2,
224+
};
225+
foreach (string departmentKey in managersByDepartment.Keys)
226+
{
227+
foreach ((string managerId, string managerName) manager in managersByDepartment[departmentKey])
228+
{
229+
int teamCount = teamCountByManagerId.ContainsKey(manager.managerId) ? teamCountByManagerId[manager.managerId] : 0;
230+
for (int teamIndex = 1; teamIndex <= teamCount; teamIndex++)
231+
{
232+
string teamId = $"{manager.managerId}_t{teamIndex}";
233+
companyData.Add(new OrganizationItem
234+
{
235+
Id = teamId,
236+
ParentId = manager.managerId,
237+
Name = $"Team-{teamIndex}",
238+
Level = OrganizationLevel.Team
239+
});
240+
}
241+
}
242+
}
243+
return companyData;
244+
}
245+
}

Diagram/Server/Pages/Layout/HeirarchicalLayout.razor

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
@using Syncfusion.Blazor.Diagram
44

5-
<SfDiagramComponent Height="600px" Nodes="@nodes" Connectors="@connectors" NodeCreating="@OnNodeCreating" ConnectorCreating="@OnConnectorCreating">
6-
<Layout Type="LayoutType.HierarchicalTree" @bind-HorizontalSpacing="@HorizontalSpacing" @bind-VerticalSpacing="@VerticalSpacing">
5+
<SfDiagramComponent Height="600px" Nodes="@_nodes" Connectors="@_connectors" NodeCreating="@OnNodeCreating" ConnectorCreating="@OnConnectorCreating">
6+
<Layout Type="LayoutType.HierarchicalTree" @bind-HorizontalSpacing="@_horizontalSpacing" @bind-VerticalSpacing="@_verticalSpacing">
77
</Layout>
88
<SnapSettings>
99
<HorizontalGridLines LineColor="white" LineDashArray="2,2">
@@ -15,12 +15,12 @@
1515

1616
@code
1717
{
18-
private int left = 40;
19-
private int top = 50;
20-
private DiagramObjectCollection<Node> nodes = new DiagramObjectCollection<Node>();
21-
private DiagramObjectCollection<Connector> connectors = new DiagramObjectCollection<Connector>();
22-
private int HorizontalSpacing = 40;
23-
private int VerticalSpacing = 40;
18+
private int _left = 40;
19+
private int _top = 50;
20+
private DiagramObjectCollection<Node> _nodes = new DiagramObjectCollection<Node>();
21+
private DiagramObjectCollection<Connector> _connectors = new DiagramObjectCollection<Connector>();
22+
private int _horizontalSpacing = 40;
23+
private int _verticalSpacing = 40;
2424

2525
private void OnNodeCreating(IDiagramObject obj)
2626
{
@@ -40,17 +40,17 @@
4040
protected override void OnInitialized()
4141
{
4242
//Initializing node and connectors.
43-
nodes = new DiagramObjectCollection<Node>()
43+
_nodes = new DiagramObjectCollection<Node>()
4444
{
45-
new Node() { ID="node1", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Steve-Ceo" } } },
46-
new Node() { ID="node2", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Kevin-Manager" } } },
47-
new Node() { ID="node3", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Peter-Manager" } } },
48-
new Node() { ID="node4", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Jim-CSE" } } },
49-
new Node() { ID="node5", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Martin-CSE" } } },
50-
new Node() { ID="node6", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "John-Manager" } } },
51-
new Node() { ID="node7", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Mary-CSE" } } },
45+
new Node() { ID = "node1", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Steve-Ceo" } } },
46+
new Node() { ID = "node2", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Kevin-Manager" } } },
47+
new Node() { ID = "node3", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Peter-Manager" } } },
48+
new Node() { ID = "node4", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Jim-CSE" } } },
49+
new Node() { ID = "node5", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Martin-CSE" } } },
50+
new Node() { ID = "node6", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "John-Manager" } } },
51+
new Node() { ID = "node7", Annotations = new DiagramObjectCollection<ShapeAnnotation>() { new ShapeAnnotation { Content = "Mary-CSE" } } },
5252
};
53-
connectors = new DiagramObjectCollection<Connector>()
53+
_connectors = new DiagramObjectCollection<Connector>()
5454
{
5555
new Connector() { ID = "connector1", SourceID = "node1", TargetID = "node2" },
5656
new Connector() { ID = "connector2", SourceID = "node1", TargetID = "node3" },

0 commit comments

Comments
 (0)