All docs
V21.2
21.2
21.1
20.2
The page you are viewing does not exist in version 20.2.
20.1
The page you are viewing does not exist in version 20.1.
19.2
The page you are viewing does not exist in version 19.2.
19.1
The page you are viewing does not exist in version 19.1.
18.2
The page you are viewing does not exist in version 18.2.
18.1
The page you are viewing does not exist in version 18.1.
17.2
The page you are viewing does not exist in version 17.2.

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

Calculates node bounds.

Namespace: DevExpress.Xpf.Charts.Sankey

Assembly: DevExpress.Xpf.Charts.v21.2.dll

Declaration

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

Parameters

Name Type Description
nodes IEnumerable<ISankeyNodeLayoutItem>

The node collection.

bounds Rectangle

Sankey diagram bounds without titles and paddings.

Remarks

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

Custom Sankey layout algorithm

<dxsa:SankeyDiagramControl x:Name="sankeyDiagramControl1" DataSource="{Binding Data}" 
                            SourceDataMember="Source" 
                            TargetDataMember="Target" 
                            WeightDataMember="Value">
    <dxsa:SankeyDiagramControl.DataContext>
        <local:SankeyViewModel/>
    </dxsa:SankeyDiagramControl.DataContext>
    <dxsa:SankeyDiagramControl.LayoutAlgorithm>
        <local:MyLayoutAlgorithm/>
    </dxsa:SankeyDiagramControl.LayoutAlgorithm>
</dxsa:SankeyDiagramControl>
public class SankeyViewModel {
    public List<SankeyItem> Data {
        get { return GetData(); }
    }
    public List<SankeyItem> GetData() {
        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 }
        };
        return data;
    }
}
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);
    }
    protected override ChartDependencyObject CreateObject() => new MyLayoutAlgorithm();
    public override void CalculateNodeBounds(IEnumerable<ISankeyNodeLayoutItem> nodes, System.Drawing.Rectangle 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 System.Drawing.Rectangle(bounds.Left + node.LevelIndex * spaceBetweenLevels, bounds.Top + nodeCount * spaceBetweenNodes, nodeWidth, nodeHeight);
        }
    }
}
See Also