How to: Implement a Custom Layout Algorithm

  • 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.

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;
        }

    }
}