private static void CenterNodesBetween(TreeNodeModel <T> leftNode, TreeNodeModel <T> rightNode)
        {
            var leftIndex  = leftNode.Parent.Children.IndexOf(rightNode);
            var rightIndex = leftNode.Parent.Children.IndexOf(leftNode);

            var numNodesBetween = rightIndex - leftIndex - 1;

            if (numNodesBetween > 0)
            {
                var distanceBetweenNodes = (leftNode.X - rightNode.X) / (numNodesBetween + 1);

                var count = 1;
                for (var i = leftIndex + 1; i < rightIndex; i++)
                {
                    var middleNode = leftNode.Parent.Children[i];

                    var desiredX = rightNode.X + (distanceBetweenNodes * count);
                    var offset   = desiredX - middleNode.X;
                    middleNode.X   += offset;
                    middleNode.Mod += offset;

                    count++;
                }

                CheckForConflicts(leftNode);
            }
        }
        private static void CalculateInitialX(TreeNodeModel <T> node)
        {
            foreach (var child in node.Children)
            {
                CalculateInitialX(child);
            }

            // if no children
            if (node.IsLeaf())
            {
                // if there is a previous sibling in this set, set X to previous sibling + designated distance
                if (!node.IsLeftMost())
                {
                    node.X = node.GetPreviousSibling().X + NodeSize + SiblingDistance;
                }
                else
                {
                    // if this is the first node in a set, set X to 0
                    node.X = 0;
                }
            }
            // if there is only one child
            else if (node.Children.Count == 1)
            {
                // if this is the first node in a set, set it's X value equal to it's child's X value
                if (node.IsLeftMost())
                {
                    node.X = node.Children[0].X;
                }
                else
                {
                    node.X   = node.GetPreviousSibling().X + NodeSize + SiblingDistance;
                    node.Mod = node.X - node.Children[0].X;
                }
            }
            else
            {
                var leftChild  = node.GetLeftMostChild();
                var rightChild = node.GetRightMostChild();
                var mid        = (leftChild.X + rightChild.X) / 2;

                if (node.IsLeftMost())
                {
                    node.X = mid;
                }
                else
                {
                    node.X   = node.GetPreviousSibling().X + NodeSize + SiblingDistance;
                    node.Mod = node.X - mid;
                }
            }

            if (node.Children.Count > 0 && !node.IsLeftMost())
            {
                // Since subtrees can overlap, check for conflicts and shift tree right if needed
                CheckForConflicts(node);
            }
        }
        // converts list of sample items to hierarchical list of TreeNodeModels
        private static TreeNodeModel <NodeModel> GetSampleTree(List <NodeModel> data)
        {
            var root         = data.FirstOrDefault(p => p.ParentId == string.Empty);
            var rootTreeNode = new TreeNodeModel <NodeModel>(root, null);

            // add tree node children recursively
            rootTreeNode.Children = GetChildNodes(data, rootTreeNode);

            return(rootTreeNode);
        }
        // recursively initialize x, y, and mod values of nodes
        private static void InitializeNodes(TreeNodeModel <T> node, int depth)
        {
            node.X   = -1;
            node.Y   = depth;
            node.Mod = 0;

            foreach (var child in node.Children)
            {
                InitializeNodes(child, depth + 1);
            }
        }
        private static Size GetSize(TreeNodeModel <NodeModel> tree)
        {
            // tree sizes are 0-based, so add 1
            var treeWidth  = tree.Width + 1;
            var treeHeight = tree.Height + 1;

            var size = new Size(Convert.ToInt32(treeWidth * NodeWidth + (treeWidth + 1) * NodeMarginX),
                                treeHeight * NodeHeight + (treeHeight + 1) * NodeMarginY);

            return(size);
        }
        public static void CalculateNodePositions(TreeNodeModel <T> rootNode)
        {
            // initialize node x, y, and mod values
            InitializeNodes(rootNode, 0);

            // assign initial X and Mod values for nodes
            CalculateInitialX(rootNode);

            // ensure no node is being drawn off screen
            CheckAllChildrenOnScreen(rootNode);

            // assign final X values to nodes
            CalculateFinalPositions(rootNode, 0);
        }
        private static List <TreeNodeModel <NodeModel> > GetChildNodes(List <NodeModel> data,
                                                                       TreeNodeModel <NodeModel> parent)
        {
            var nodes = new List <TreeNodeModel <NodeModel> >();

            foreach (var item in data.Where(p => p.ParentId == parent.Item.Id))
            {
                var treeNode = new TreeNodeModel <NodeModel>(item, parent);
                treeNode.Children = GetChildNodes(data, treeNode);
                nodes.Add(treeNode);
            }

            return(nodes);
        }
        private static void GetRightContour(TreeNodeModel <T> node, float modSum, ref Dictionary <int, float> values)
        {
            if (!values.ContainsKey(node.Y))
            {
                values.Add(node.Y, node.X + modSum);
            }
            else
            {
                values[node.Y] = Math.Max(values[node.Y], node.X + modSum);
            }

            modSum += node.Mod;
            foreach (var child in node.Children)
            {
                GetRightContour(child, modSum, ref values);
            }
        }
        private static void CalculateFinalPositions(TreeNodeModel <T> node, float modSum)
        {
            node.X += modSum;
            modSum += node.Mod;

            foreach (var child in node.Children)
            {
                CalculateFinalPositions(child, modSum);
            }

            if (node.Children.Count == 0)
            {
                node.Width  = node.X;
                node.Height = node.Y;
            }
            else
            {
                node.Width  = node.Children.OrderByDescending(p => p.Width).First().Width;
                node.Height = node.Children.OrderByDescending(p => p.Height).First().Height;
            }
        }
        private static void CheckForConflicts(TreeNodeModel <T> node)
        {
            const float minDistance = TreeDistance + NodeSize;
            var         shiftValue  = 0F;

            var nodeContour = new Dictionary <int, float>();

            GetLeftContour(node, 0, ref nodeContour);

            var sibling = node.GetLeftMostSibling();

            while (sibling != null && sibling != node)
            {
                var siblingContour = new Dictionary <int, float>();
                GetRightContour(sibling, 0, ref siblingContour);

                for (var level = node.Y + 1;
                     level <= Math.Min(siblingContour.Keys.Max(), nodeContour.Keys.Max());
                     level++)
                {
                    var distance = nodeContour[level] - siblingContour[level];
                    if (distance + shiftValue < minDistance)
                    {
                        shiftValue = minDistance - distance;
                    }
                }

                if (shiftValue > 0)
                {
                    node.X   += shiftValue;
                    node.Mod += shiftValue;

                    CenterNodesBetween(node, sibling);

                    shiftValue = 0;
                }

                sibling = sibling.GetNextSibling();
            }
        }
        private static void CheckAllChildrenOnScreen(TreeNodeModel <T> node)
        {
            var nodeContour = new Dictionary <int, float>();

            GetLeftContour(node, 0, ref nodeContour);

            float shiftAmount = 0;

            foreach (var y in nodeContour.Keys)
            {
                if (nodeContour[y] + shiftAmount < 0)
                {
                    shiftAmount = nodeContour[y] * -1;
                }
            }

            if (shiftAmount > 0)
            {
                node.X   += shiftAmount;
                node.Mod += shiftAmount;
            }
        }
Exemple #12
0
 public TreeNodeModel(T item, TreeNodeModel <T> parent)
 {
     Item     = item;
     Parent   = parent;
     Children = new List <TreeNodeModel <T> >();
 }
        private static void DrawNode(TreeNodeModel <NodeModel> node, Graphics graphic)
        {
            // Set the pen
            var nodePen = node.Item.Colour;

            // rectangle where node will be positioned
            var nodeRect = new Rectangle(Convert.ToInt32(NodeMarginX + node.X * (NodeWidth + NodeMarginX)),
                                         NodeMarginY + node.Y * (NodeHeight + NodeMarginY), NodeWidth, NodeHeight);

            // draw box
            if (!node.Item.IsCompressed)
            {
                graphic.DrawRectangle(nodePen, nodeRect);
            }

            // draw content
            var font       = new Font(FontFamily.GenericMonospace, 8);
            var stringSize = graphic.MeasureString(node.ToString(), font);

            graphic.DrawString(node.ToString(), font, nodePen.Brush, nodeRect.X + NodeWidth / 2 - stringSize.Width / 2,
                               nodeRect.Y + NodeHeight / 2 - stringSize.Height / 2);

            // draw line to parent
            if (node.Parent != null)
            {
                var nodeTopMiddle    = new Point(nodeRect.X + nodeRect.Width / 2, nodeRect.Y);
                var nodeBottomMiddle = new Point(nodeTopMiddle.X, nodeTopMiddle.Y - NodeMarginY / 2);
                graphic.DrawLine(nodePen, nodeTopMiddle, nodeBottomMiddle);
            }

            // draw line to children
            if (node.Children.Count > 0)
            {
                var nodeBottomMiddle = new Point(nodeRect.X + nodeRect.Width / 2, nodeRect.Y + nodeRect.Height);
                var nodeTopMiddle    = new Point(nodeBottomMiddle.X, nodeBottomMiddle.Y + NodeMarginY / 2);
                graphic.DrawLine(nodePen, nodeBottomMiddle, nodeTopMiddle);

                // draw line over children
                if (node.Children.Count > 1)
                {
                    var childrenLineStartX = Convert.ToInt32(NodeMarginX + node.GetRightMostChild().X *
                                                             // ReSharper disable once PossibleLossOfFraction
                                                             (NodeWidth + NodeMarginX) + NodeWidth / 2);
                    var childrenLineStartY = nodeBottomMiddle.Y + NodeMarginY / 2;
                    var childrenLineStart  = new Point(childrenLineStartX, childrenLineStartY);

                    var childrenLineEndX = Convert.ToInt32(NodeMarginX +
                                                           node.GetLeftMostChild().X *(NodeWidth + NodeMarginX) +
                                                           // ReSharper disable once PossibleLossOfFraction
                                                           NodeWidth / 2);
                    var childrenLineEndY = nodeBottomMiddle.Y + NodeMarginY / 2;
                    var childrenLineEnd  = new Point(childrenLineEndX, childrenLineEndY);

                    graphic.DrawLine(Pens.Black, childrenLineStart, childrenLineEnd);
                }
            }

            foreach (var item in node.Children)
            {
                DrawNode(item, graphic);
            }
        }
 private static void PaintTree(Graphics graphic, TreeNodeModel <NodeModel> tree)
 {
     graphic.Clear(Color.White);
     DrawNode(tree, graphic);
 }