TL;DR: Want to refine your diagram clarity? Syncfusion Blazor Diagram Library introduces a vital update: the line routing feature, designed to refine diagram clarity by smartly adjusting connector paths to prevent overlaps with nodes. This blog highlights the importance of line routing in creating more organized diagrams, breaks down how to enable it, and explores the classic and advanced routing strategies available to users.
We’re excited to announce a significant update to our Syncfusion Blazor Diagram Library: the addition of a line routing feature. This powerful feature helps you create more precise and organized diagrams by intelligently adjusting the paths of connectors to avoid overlapping with nodes.
In this blog, we’ll explore how line routing works, demonstrate its usage with examples, and discuss the different routing strategies available.
Let’s get started!
In diagramming, Connectors are used to link nodes or points, representing the relationships between them. However, when nodes are positioned close to connectors, overlapping can occur, reducing the clarity of your diagram. Line routing addresses this issue by adjusting the geometry of connectors to prevent overlaps with nodes.
Activating line routing in your diagram is straightforward. Simply add the Routing enum value to the Constraints property of the Blazor Diagram component.
Here’s a basic example to demonstrate how to enable default routing.
@using Syncfusion.Blazor.Diagram <SfDiagramComponent Width="1000px" Height="500px" Connectors="@connectors" Nodes="@nodes" Constraints="@diagramConstraints"> </SfDiagramComponent> @code { // Enable routing constraints for diagram. DiagramConstraints diagramConstraints = DiagramConstraints.Default | DiagramConstraints.Routing; // Initialize the node collection. DiagramObjectCollection<Node> nodes = new DiagramObjectCollection<Node>(); // Initialize the connector collection. DiagramObjectCollection<Connector> connectors = new DiagramObjectCollection<Connector>(); protected override void OnInitialized() { nodes = new DiagramObjectCollection<Node>() { new Node() { ID = "node1", OffsetX = 100, OffsetY = 300, Width = 100, Height =100 }, new Node() { ID = "node2", OffsetX = 600, OffsetY = 100, Width = 100, Height = 100 }, new Node() { ID = "node3", OffsetX = 400, OffsetY = 250, Width = 100, Height = 100 } }; connectors = new DiagramObjectCollection<Connector>(){ new Connector() { ID = "connector1", SourceID = "node1", TargetID = "node2", Type = ConnectorSegmentType.Orthogonal } }; } }
The following GIF image demonstrates how to route the connector based on the nodes during interaction.
The Syncfusion Blazor Diagram library offers two types of routing strategies:
The Classic routing algorithm adds additional segments based on the position and dimensions of obstacles in the path. This method prioritizes navigating around obstacles efficiently, even if it means having a longer path or more bends. Using the Classic routing when avoiding obstacles is crucial.
Refer to the following code example.
@using Syncfusion.Blazor.Diagram <SfDiagramComponent Width="1000px" Height="500px" Connectors="@connectors" Nodes="@nodes" Constraints="@diagramConstraints"> <LineRoutingSettings RoutingType="@routingTypes"></LineRoutingSettings> </SfDiagramComponent> @code { // Set the type of the routing. RoutingTypes routingTypes = RoutingTypes.Classic; // Enable routing constraints for diagram. DiagramConstraints diagramConstraints = DiagramConstraints.Default | DiagramConstraints.Routing; // Initialize the node collection. DiagramObjectCollection<Node> nodes = new DiagramObjectCollection<Node>(); // Initialize the connector collection. DiagramObjectCollection<Connector> connectors = new DiagramObjectCollection<Connector>(); protected override void OnInitialized() { nodes = new DiagramObjectCollection<Node>() { new Node() { ID = "node1", OffsetX = 100, OffsetY = 300, Width = 100, Height =100 }, new Node() { ID = "node2", OffsetX = 600, OffsetY = 100, Width = 100, Height = 100 }, new Node() { ID = "node3", OffsetX = 400, OffsetY = 250, Width = 100, Height = 100 } }; connectors = new DiagramObjectCollection<Connector>(){ new Connector() { ID = "connector1", SourceID = "node1", TargetID = "node2", Type = ConnectorSegmentType.Orthogonal } }; } }
The Advanced routing algorithm evaluates all possible geometrical paths for a connector, aiming to find the one with minimal bends and the shortest length. Use the advanced routing for a more optimized path with fewer bends, even if it brings connectors closer to obstacles.
Refer to the following code example.
@using Syncfusion.Blazor.Diagram <SfDiagramComponent Width="1000px" Height="500px" Connectors="@connectors" Nodes="@nodes" Constraints="@diagramConstraints"> <LineRoutingSettings RoutingType="@routingTypes" ObstaclePadding="@padding"></LineRoutingSettings> </SfDiagramComponent> @code { // Set the type of the routing. RoutingTypes routingTypes = RoutingTypes.Advanced; // Set the padding for the obstacle. double padding = 20; // Enable routing constraints for diagram. DiagramConstraints diagramConstraints = DiagramConstraints.Default | DiagramConstraints.Routing; // Initialize the node collection. DiagramObjectCollection<Node> nodes = new DiagramObjectCollection<Node>(); // Initialize the connector collection. DiagramObjectCollection<Connector> connectors = new DiagramObjectCollection<Connector>(); protected override void OnInitialized() { nodes = new DiagramObjectCollection<Node>() { new Node() { ID = "node1", OffsetX = 100, OffsetY = 300, Width = 100, Height =100 }, new Node() { ID = "node2", OffsetX = 600, OffsetY = 100, Width = 100, Height = 100 }, new Node() { ID = "node3", OffsetX = 400, OffsetY = 250, Width = 100, Height = 100 } }; connectors = new DiagramObjectCollection<Connector>(){ new Connector() { ID = "connector1", SourceID = "node1", TargetID = "node2", Type = ConnectorSegmentType.Orthogonal } }; } }
By default, connectors treat all nodes as obstacles. However, you can disable this behavior by removing the RoutingObstacle from a node’s Constraints property, allowing connectors to ignore specific nodes.
Refer to the following code example.
@using Syncfusion.Blazor.Diagram <SfDiagramComponent Width="1000px" Height="500px" NodeCreating="@OnNodeCreating" ConnectorCreating="@OnConnectorCreating" Connectors="@connectors" Nodes="@nodes" Constraints="@diagramConstraints"> <SnapSettings Constraints="SnapConstraints.None"></SnapSettings> </SfDiagramComponent> @code { // Enable routing constraints for the diagram. DiagramConstraints diagramConstraints = DiagramConstraints.Default | DiagramConstraints.Routing; // Initialize the node collection. DiagramObjectCollection<Node> nodes = new DiagramObjectCollection<Node>(); // Initialize the connector collection. DiagramObjectCollection<Connector> connectors = new DiagramObjectCollection<Connector>(); protected override void OnInitialized() { nodes = new DiagramObjectCollection<Node>() { new Node() { ID = "Source", OffsetX = 100, OffsetY = 300, Width = 100, Height =100, Annotations= new DiagramObjectCollection<ShapeAnnotation>(){ new ShapeAnnotation() { Content="Source" } }, Ports=new DiagramObjectCollection<PointPort>(){ new PointPort(){ ID="port1", Offset=new DiagramPoint() { X = 1, Y = 0.5 } } } }, new Node() { ID = "Target", OffsetX = 800, OffsetY = 300, Width = 100, Height = 100, Annotations= new DiagramObjectCollection<ShapeAnnotation>(){ new ShapeAnnotation() { Content="Target" } }, Ports=new DiagramObjectCollection<PointPort>(){ new PointPort(){ ID="port1", Offset=new DiagramPoint() { X = 0, Y = 0.5 } } } }, new Node() { ID = "RoutingObstacle", OffsetX = 300, OffsetY = 300, Width = 100, Height = 100, Annotations= new DiagramObjectCollection<ShapeAnnotation>(){ new ShapeAnnotation() { Content="Routing Obstacle" } }, }, new Node() { ID = "NonRoutingObstacle", OffsetX = 500, OffsetY = 250, Width = 100, Height = 100, Annotations= new DiagramObjectCollection<ShapeAnnotation>(){ new ShapeAnnotation() { Content="Non-Routing Obstacle" } }, Constraints = NodeConstraints.Default & ~NodeConstraints.RoutingObstacle } }; connectors = new DiagramObjectCollection<Connector>(){ new Connector() { ID = "connector1", SourceID = "Source", TargetID = "Target", SourcePortID="port1", TargetPortID="port1", Type = ConnectorSegmentType.Orthogonal } }; } private void OnNodeCreating(IDiagramObject obj) { if (obj is Node node) { node.Style = new ShapeStyle() { Fill = "#6BA5D7", StrokeColor = "#6BA5D7" }; } } private void OnConnectorCreating(IDiagramObject obj) { if (obj is Connector connector) { connector.Style = new ShapeStyle() { StrokeColor = "#6BA5D7", StrokeWidth = 1 }; connector.TargetDecorator = new DecoratorSettings() { Shape = DecoratorShape.Arrow, Style = new ShapeStyle() { Fill = "#6BA5D7", StrokeColor = "#6BA5D7", StrokeWidth = 1 } }; } } }
Refer to the following image.
Each connector’s routing process can be controlled independently by adjusting its Constraints property. Remove the InheritRouting enum value to set routing specifically for a connector.
@using Syncfusion.Blazor.Diagram <SfDiagramComponent Width="1000px" Height="500px" NodeCreating="@OnNodeCreating" ConnectorCreating="@OnConnectorCreating" Connectors="@connectors" Nodes="@nodes" Constraints="@diagramConstraints"> <SnapSettings Constraints="SnapConstraints.None"></SnapSettings> </SfDiagramComponent> @code { // Enable routing constraints for the diagram. DiagramConstraints diagramConstraints = DiagramConstraints.Default | DiagramConstraints.Routing; //Initialize the node collection. DiagramObjectCollection<Node> nodes = new DiagramObjectCollection<Node>(); //Initialize the connector collection. DiagramObjectCollection<Connector> connectors = new DiagramObjectCollection<Connector>(); protected override void OnInitialized() { nodes = new DiagramObjectCollection<Node>() { new Node() { ID = "Source", OffsetX = 90, OffsetY = 290, Width = 100, Height =100, Annotations= new DiagramObjectCollection<ShapeAnnotation>(){ new ShapeAnnotation() { Content="Source1" } }, Ports=new DiagramObjectCollection<PointPort>(){ new PointPort(){ ID="port1", Offset=new DiagramPoint() { X = 1, Y = 0.5 } } } }, new Node() { ID = "Target", OffsetX = 700, OffsetY = 304, Width = 100, Height = 100, Annotations= new DiagramObjectCollection<ShapeAnnotation>(){ new ShapeAnnotation() { Content="Target1" } }, Ports=new DiagramObjectCollection<PointPort>(){ new PointPort(){ ID="port1", Offset=new DiagramPoint() { X = 0, Y = 0.5 } } } }, new Node() { ID = "Source2", OffsetX = 120, OffsetY = 150, Width = 100, Height = 100, Annotations= new DiagramObjectCollection<ShapeAnnotation>(){ new ShapeAnnotation() { Content="Source2" } }, }, new Node() { ID = "Target2", OffsetX = 490, OffsetY = 250, Width = 100, Height = 100, Annotations= new DiagramObjectCollection<ShapeAnnotation>(){ new ShapeAnnotation() { Content="Target2" } } }, new Node() { ID = "Obstacle", OffsetX = 291, OffsetY = 300, Width = 100, Height = 100, Annotations= new DiagramObjectCollection<ShapeAnnotation>(){ new ShapeAnnotation() { Content="Obstacle" } }, }, }; connectors = new DiagramObjectCollection<Connector>(){ new Connector() { ID = "connector1", SourceID = "Source", TargetID = "Target", Type = ConnectorSegmentType.Orthogonal, // Disable the inherited routing for the connector. Constraints = ConnectorConstraints.Default & ~ConnectorConstraints.InheritRouting, Annotations = new DiagramObjectCollection<PathAnnotation>(){ new PathAnnotation(){ Content = "Without Routing" } } }, new Connector() { ID = "connector2", SourceID = "Source2", TargetID = "Target2", Type = ConnectorSegmentType.Orthogonal, // Enable the routing for the connector. Constraints = (ConnectorConstraints.Default & ~ConnectorConstraints.InheritRouting) | ConnectorConstraints.Routing, Annotations = new DiagramObjectCollection<PathAnnotation>(){ new PathAnnotation(){ Content = "With Routing" } } } }; } private void OnNodeCreating(IDiagramObject obj) { if (obj is Node node) { node.Style = new ShapeStyle() { Fill = "#6BA5D7", StrokeColor = "#6BA5D7" }; } } private void OnConnectorCreating(IDiagramObject obj) { if (obj is Connector connector) { connector.Style = new ShapeStyle() { StrokeColor = "#6BA5D7", StrokeWidth = 1 }; connector.TargetDecorator = new DecoratorSettings() { Shape = DecoratorShape.Arrow, Style = new ShapeStyle() { Fill = "#6BA5D7", StrokeColor = "#6BA5D7", StrokeWidth = 1 } }; } } }
Refer to the following image.
The ObstaclePadding property defines the minimum distance between the connectors and obstacles when the advanced routing is enabled. This ensures connectors are routed with precise spacing around obstacles, enhancing diagram readability. The ObstaclePadding property is applicable only when the RoutingType property is set to RoutingTypes.Advanced. The default value of ObstaclePadding is 12.
Refer to the following code example.
@using Syncfusion.Blazor.Diagram <SfDiagramComponent Width="1000px" Height="500px" Connectors="@connectors" Nodes="@nodes" Constraints="@diagramConstraints"> <LineRoutingSettings RoutingType="@routingTypes" ObstaclePadding="@padding"></LineRoutingSettings> </SfDiagramComponent> @code { // Set the type of the routing. RoutingTypes routingTypes = RoutingTypes.Advanced; // Set the padding for the obstacle. double padding = 20; // Enable routing constraints for diagram. DiagramConstraints diagramConstraints = DiagramConstraints.Default | DiagramConstraints.Routing; // Initialize the node collection. DiagramObjectCollection<Node> nodes = new DiagramObjectCollection<Node>(); // Initialize the connector collection. DiagramObjectCollection<Connector> connectors = new DiagramObjectCollection<Connector>(); protected override void OnInitialized() { nodes = new DiagramObjectCollection<Node>() { new Node() { ID = "node1", OffsetX = 100, OffsetY = 300, Width = 100, Height =100 }, new Node() { ID = "node2", OffsetX = 600, OffsetY = 100, Width = 100, Height = 100 }, new Node() { ID = "node3", OffsetX = 400, OffsetY = 250, Width = 100, Height = 100 } }; connectors = new DiagramObjectCollection<Connector>(){ new Connector() { ID = "connector1", SourceID = "node1", TargetID = "node2", Type = ConnectorSegmentType.Orthogonal } }; } }
For more details, refer to the line routing in Blazor Diagram documentation and web and GitHub demos.
Thanks for reading! The line routing feature in the Syncfusion Blazor Diagram Library offers a robust solution for creating clear and organized diagrams. This feature is available in the 2024 volume 2 release. By adjusting connector paths to avoid node overlaps, you can enhance the readability of your diagrams. Try the different routing strategies and customize the behavior for Nodes and Connectors to suit your specific needs. We hope this feature helps you create more effective visual representations of your data and processes.
You can check out all the new features introduced in this 2024 volume 2 in our Release Notes and What’s New pages.
The existing customers can download the new version of Essential Studio® on the License and Downloads page. If you are not a Syncfusion customer, try our 30-day free trial to check out our incredible features.
You can also contact us through our support forums, support portal, or feedback portal. As always, we are happy to assist you!