Back to Devexpress

How to: Implement a Custom Layout Algorithm

windowsforms-115760-controls-and-libraries-treemap-layout-algorithms-examples-how-to-implement-a-custom-layout-algorithm.md

latest7.5 KB
Original Source

How to: Implement a Custom Layout Algorithm

  • Nov 13, 2018
  • 3 minutes to read

To implement a custom layout algorithm that can be used to place tree map items into a parent container and set their size, design a class implementing the ITreeMapLayoutAlgorithm interface and implement its ITreeMapLayoutAlgorithm.Calculate method.

csharp
using DevExpress.TreeMap;
using DevExpress.XtraTreeMap;
using System.Collections.Generic;
using System.Linq;

namespace CustomLayoutAlgorithmSample {
    class CustomLayoutAlgorithm : ITreeMapLayoutAlgorithm, IComparer<ITreeMapItemLayout> {
        public TreeMapLayoutDirection Direction {
            get; set;
        }

        public event LayoutAlgorithmChangedEventHandler LayoutAlgorithmChanged;

        public void Calculate(IEnumerable<ITreeMapItemLayout> items, double width, double height, int groupLevel) {
            double unlayoutedItemsWeight = 0;
            foreach(var item in items)
                unlayoutedItemsWeight += item.Weight;

            var sortedItems = items.ToList();
            sortedItems.Sort(this);

            TreeMapRect emptySpace = new TreeMapRect(0, 0, width, height);
            foreach(var item in sortedItems) {
                double itemWidth;
                double itemHeight;

                double newEmptySpaceX;
                double newEmptySpaceY;
                double newEmptySpaceWidth;
                double newEmptySpaceHeight;

                if(emptySpace.Width / emptySpace.Height > 1) {
                    itemWidth = emptySpace.Width * item.Weight / unlayoutedItemsWeight;
                    itemHeight = emptySpace.Height;

                    newEmptySpaceX = emptySpace.X + itemWidth;
                    newEmptySpaceY = emptySpace.Y;
                    newEmptySpaceHeight = emptySpace.Height;

                    newEmptySpaceWidth = emptySpace.Width - itemWidth;
                    newEmptySpaceWidth = newEmptySpaceWidth < 0 ? 0 : newEmptySpaceWidth;
                }
                else {
                    itemWidth = emptySpace.Width;
                    itemHeight = emptySpace.Height * item.Weight / unlayoutedItemsWeight;

                    newEmptySpaceX = emptySpace.X;
                    newEmptySpaceY = emptySpace.Y + itemHeight;
                    newEmptySpaceWidth = emptySpace.Width;

                    newEmptySpaceHeight = emptySpace.Height - itemHeight;
                    newEmptySpaceHeight = newEmptySpaceHeight < 0 ? 0 : newEmptySpaceHeight;
                }
                item.Layout = new TreeMapRect(emptySpace.X, emptySpace.Y, itemWidth, itemHeight);
                emptySpace = new TreeMapRect(
                    newEmptySpaceX,
                    newEmptySpaceY,
                    newEmptySpaceWidth,
                    newEmptySpaceHeight);
                unlayoutedItemsWeight -= item.Weight;
            }
        }

        public int Compare(ITreeMapItemLayout x, ITreeMapItemLayout y) {
            if(x.Weight > y.Weight) return -1;
            else if(x.Weight < y.Weight) return 1;
            else return 0;
        }

    }
}
csharp
using System;
using System.Windows.Forms;

namespace CustomLayoutAlgorithmSample {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e) {
            treeMap.LayoutAlgorithm = new CustomLayoutAlgorithm();
        }
    }
}
vb
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Threading.Tasks
Imports System.Windows.Forms

Namespace CustomLayoutAlgorithmSample
    Friend NotInheritable Class Program

        Private Sub New()
        End Sub

        ''' <summary>
        ''' The main entry point for the application.
        ''' </summary>
        <STAThread> _
        Shared Sub Main()
            Application.EnableVisualStyles()
            Application.SetCompatibleTextRenderingDefault(False)
            Application.Run(New Form1())
        End Sub
    End Class
End Namespace
vb
Imports DevExpress.TreeMap
Imports DevExpress.XtraTreeMap

Namespace CustomLayoutAlgorithmSample
    Friend Class CustomLayoutAlgorithm
        Implements ITreeMapLayoutAlgorithm, IComparer(Of ITreeMapItemLayout)

        Public Property Direction() As TreeMapLayoutDirection

        Public Event LayoutAlgorithmChanged As LayoutAlgorithmChangedEventHandler Implements ITreeMapLayoutAlgorithm.LayoutAlgorithmChanged

        Public Sub Calculate(ByVal items As IEnumerable(Of ITreeMapItemLayout), ByVal width As Double, ByVal height As Double, ByVal groupLevel As Integer) Implements ITreeMapLayoutAlgorithm.Calculate
            Dim unlayoutedItemsWeight As Double = 0
            For Each item In items
                unlayoutedItemsWeight += item.Weight
            Next item

            Dim sortedItems = items.ToList()
            sortedItems.Sort(Me)

            Dim emptySpace As New TreeMapRect(0, 0, width, height)
            For Each item In sortedItems
                Dim itemWidth As Double
                Dim itemHeight As Double

                Dim newEmptySpaceX As Double
                Dim newEmptySpaceY As Double
                Dim newEmptySpaceWidth As Double
                Dim newEmptySpaceHeight As Double

                If (emptySpace.Width > emptySpace.Height) Then
                    itemWidth = emptySpace.Width * item.Weight / unlayoutedItemsWeight
                    itemHeight = emptySpace.Height

                    newEmptySpaceX = emptySpace.X + itemWidth
                    newEmptySpaceY = emptySpace.Y
                    newEmptySpaceHeight = emptySpace.Height

                    newEmptySpaceWidth = emptySpace.Width - itemWidth
                    newEmptySpaceWidth = If(newEmptySpaceWidth < 0, 0, newEmptySpaceWidth)
                Else
                    itemWidth = emptySpace.Width
                    itemHeight = emptySpace.Height * item.Weight / unlayoutedItemsWeight

                    newEmptySpaceX = emptySpace.X
                    newEmptySpaceY = emptySpace.Y + itemHeight
                    newEmptySpaceWidth = emptySpace.Width

                    newEmptySpaceHeight = emptySpace.Height - itemHeight
                    newEmptySpaceHeight = If(newEmptySpaceHeight < 0, 0, newEmptySpaceHeight)
                End If
                item.Layout = New TreeMapRect(emptySpace.X, emptySpace.Y, itemWidth, itemHeight)
                emptySpace = New TreeMapRect(newEmptySpaceX, newEmptySpaceY, newEmptySpaceWidth, newEmptySpaceHeight)
                unlayoutedItemsWeight -= item.Weight
            Next item
        End Sub

        Public Function Compare(ByVal x As ITreeMapItemLayout, ByVal y As ITreeMapItemLayout) As Integer Implements IComparer(Of ITreeMapItemLayout).Compare
            If x.Weight > y.Weight Then
                Return -1
            ElseIf x.Weight < y.Weight Then
                Return 1
            Else
                Return 0
            End If
        End Function

    End Class
End Namespace