Skip to main content
All docs
V24.2

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

Calculates node bounds.

Namespace: DevExpress.XtraCharts.Sankey

Assembly: DevExpress.XtraCharts.v24.2.dll

Declaration

public virtual void CalculateNodeBounds(
    IEnumerable<ISankeyNodeLayoutItem> nodes,
    DXRectangle bounds
)

Parameters

Name Type Description
nodes IEnumerable<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:

Custom Sankey layout algorithm

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);
        }
    }
}
See Also