Back to Devexpress

SankeyLayoutAlgorithmBase.CalculateNodeBounds(IEnumerable<ISankeyNodeLayoutItem>, DXRectangle) Method

corelibraries-devexpress-dot-xtracharts-dot-sankey-dot-sankeylayoutalgorithmbase-dot-calculatenodebounds-x28-ienumerable-isankeynodelayoutitem-dxrectangle-x29.md

latest8.6 KB
Original Source

SankeyLayoutAlgorithmBase.CalculateNodeBounds(IEnumerable<ISankeyNodeLayoutItem>, DXRectangle) Method

Calculates node bounds.

Namespace : DevExpress.XtraCharts.Sankey

Assembly : DevExpress.XtraCharts.v25.2.dll

NuGet Package : DevExpress.Charts

Declaration

csharp
public virtual void CalculateNodeBounds(
    IEnumerable<ISankeyNodeLayoutItem> nodes,
    DXRectangle bounds
)
vb
Public Overridable Sub CalculateNodeBounds(
    nodes As IEnumerable(Of ISankeyNodeLayoutItem),
    bounds As DXRectangle
)

Parameters

NameTypeDescription
nodesIEnumerable<ISankeyNodeLayoutItem>

The node collection.

| | bounds | DevExpress.Utils.DXRectangle |

Sankey diagram bounds without titles and paddings.

|

Remarks

To implement a custom layout, create a descendant of the SankeyLayoutAlgorithmBase class. Override the SankeyLayoutAlgorithmBase.CalculateNodeBounds method to specify node bounds:

csharp
using DevExpress.Charts.Sankey;
using DevExpress.XtraCharts.Sankey;
using System;
using System.Collections.Generic;
using System.Linq;

private void Form1_Load(object sender, EventArgs e) {
     SankeyDiagramControl sankeyDiagramControl1 = new SankeyDiagramControl();
     this.Controls.Add(sankeyDiagramControl1);
    List<SankeyItem> data = new List<SankeyItem> {
        new SankeyItem { Source = "France", Target = "UK", Value = 53 },
        new SankeyItem { Source = "Australia", Target = "UK", Value = 72 },
        new SankeyItem { Source = "France", Target = "Canada", Value = 81 },
        new SankeyItem { Source = "China", Target = "Canada", Value = 96 },
        new SankeyItem { Source = "UK", Target = "France", Value = 61 },
        new SankeyItem { Source = "Canada", Target = "France", Value = 89 } 
    };
    sankeyDiagramControl1.DataSource = data;
    sankeyDiagramControl1.SourceDataMember = "Source";
    sankeyDiagramControl1.TargetDataMember = "Target";
    sankeyDiagramControl1.WeightDataMember = "Value";

    sankeyDiagramControl1.LayoutAlgorithm = new MyLayoutAlgorithm();
    sankeyDiagramControl1.Width = 640;
    sankeyDiagramControl1.Height = 360;
}

public class SankeyItem {
    public string Source { get; set; }
    public string Target { get; set; }
    public double Value { get; set; }
}
public class MyLayoutAlgorithm : SankeyLayoutAlgorithmBase {

    void SpreadLevelIndex(ISankeyNodeLayoutItem node, int startingLevelIndex = 0) {
        node.LevelIndex = startingLevelIndex;
        if (node.OutputLinks == null)
            return;
        foreach (var outputLink in node.OutputLinks)
            SpreadLevelIndex(outputLink.Target, startingLevelIndex + 1);
    }
    public override void CalculateNodeBounds(IEnumerable<ISankeyNodeLayoutItem> nodes, DevExpress.Utils.DXRectangle bounds) {
        foreach (var node in nodes)
            if (node.InputLinks == null || node.InputLinks.Count == 0)
                SpreadLevelIndex(node);
        int nodeWidth = bounds.Width / 10;
        int nodeHeight = bounds.Height / 10;
        int levelCount = nodes.Max(node => node.LevelIndex) + 1;
        int spaceBetweenLevels = (bounds.Width - nodeWidth) / (levelCount - 1);
        int maxNodeCountInALevel = nodes.GroupBy(node => node.LevelIndex).Max(group => group.Count());
        int spaceBetweenNodes = (bounds.Height - nodeHeight) / (maxNodeCountInALevel - 1);
        Dictionary<int, int> levelNodeCountPairs = new Dictionary<int, int>();
        foreach (var node in nodes) {
            if (!levelNodeCountPairs.TryGetValue(node.LevelIndex, out int nodeCount))
                levelNodeCountPairs.Add(node.LevelIndex, 0);
            levelNodeCountPairs[node.LevelIndex]++;
            node.Bounds = new DevExpress.Utils.DXRectangle(bounds.Left + node.LevelIndex * spaceBetweenLevels, bounds.Top + nodeCount * spaceBetweenNodes, nodeWidth, nodeHeight);
        }
    }
}
vb
Imports DevExpress.Charts.Sankey
Imports DevExpress.Utils
Imports DevExpress.XtraCharts.Sankey
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim sankeyDiagramControl1 As SankeyDiagramControl = New SankeyDiagramControl()
        Me.Controls.Add(sankeyDiagramControl1)
        Dim data As List(Of SankeyItem) = New List(Of SankeyItem) From {
        New SankeyItem With {
            .Source = "France",
            .Target = "UK",
            .Value = 53
        },
        New SankeyItem With {
            .Source = "Australia",
            .Target = "UK",
            .Value = 72
        },
        New SankeyItem With {
            .Source = "France",
            .Target = "Canada",
            .Value = 81
        },
        New SankeyItem With {
            .Source = "China",
            .Target = "Canada",
            .Value = 96
        },
        New SankeyItem With {
            .Source = "UK",
            .Target = "France",
            .Value = 61
        },
        New SankeyItem With {
            .Source = "Canada",
            .Target = "France",
            .Value = 89
        }
    }
        sankeyDiagramControl1.DataSource = data
        sankeyDiagramControl1.SourceDataMember = "Source"
        sankeyDiagramControl1.TargetDataMember = "Target"
        sankeyDiagramControl1.WeightDataMember = "Value"
        sankeyDiagramControl1.LayoutAlgorithm = New MyLayoutAlgorithm()
        sankeyDiagramControl1.Width = 640
        sankeyDiagramControl1.Height = 360
    End Sub

    Public Class SankeyItem
        Public Property Source As String
        Public Property Target As String
        Public Property Value As Double
    End Class

    Public Class MyLayoutAlgorithm
        Inherits SankeyLayoutAlgorithmBase

        Private Sub SpreadLevelIndex(ByVal node As ISankeyNodeLayoutItem, ByVal Optional startingLevelIndex As Integer = 0)
            node.LevelIndex = startingLevelIndex
            If node.OutputLinks Is Nothing Then Return

            For Each outputLink In node.OutputLinks
                SpreadLevelIndex(outputLink.Target, startingLevelIndex + 1)
            Next
        End Sub

        Public Overrides Sub CalculateNodeBounds(ByVal nodes As IEnumerable(Of ISankeyNodeLayoutItem), ByVal bounds As DevExpress.Utils.DXRectangle)
            For Each node In nodes
                If node.InputLinks Is Nothing OrElse node.InputLinks.Count = 0 Then SpreadLevelIndex(node)
            Next

            Dim nodeWidth As Integer = bounds.Width / 10
            Dim nodeHeight As Integer = bounds.Height / 10
            Dim levelCount As Integer = nodes.Max(Function(node) node.LevelIndex) + 1
            Dim spaceBetweenLevels As Integer = (bounds.Width - nodeWidth) / (levelCount - 1)
            Dim maxNodeCountInALevel As Integer = nodes.GroupBy(Function(node) node.LevelIndex).Max(Function(group) group.Count())
            Dim spaceBetweenNodes As Integer = (bounds.Height - nodeHeight) / (maxNodeCountInALevel - 1)
            Dim levelNodeCountPairs As Dictionary(Of Integer, Integer) = New Dictionary(Of Integer, Integer)()
            Dim nodeCount As Integer = Nothing

            For Each node In nodes
                If Not levelNodeCountPairs.TryGetValue(node.LevelIndex, nodeCount) Then levelNodeCountPairs.Add(node.LevelIndex, 0)
                levelNodeCountPairs(node.LevelIndex) += 1
                node.Bounds = New DXRectangle(bounds.Left + node.LevelIndex * spaceBetweenLevels, bounds.Top + nodeCount * spaceBetweenNodes, nodeWidth, nodeHeight)
            Next
        End Sub
    End Class
End Class

See Also

SankeyLayoutAlgorithmBase Class

SankeyLayoutAlgorithmBase Members

DevExpress.XtraCharts.Sankey Namespace