Click here to Skip to main content
Click here to Skip to main content

JavaScript Horizontal Tree

By , 1 Jul 2006
 

Sample Image - Horizontal Tree.png

Introduction

Recently, I had a task to make a horizontal tree using JavaScript. I thought that I would find millions of examples for a tree on the internet, but I didn't find anything useful. We all know the vertical tree which is the most commonly available on the internet, as it's used for many scenarios like navigation menus etc., but what if we wanted to represent the info in a horizontal tree format, which will help the user to have a more intensive view for the data on the tree? I didn't want to waste time building something from scratch, so I've took the code here and developed another version from it to draw a horizontal tree.

Using the code

The main idea is that instead of building tree nodes as a DIV under DIV, we will use table and table cells to represent a level of node, so whenever I start a new level, I will draw a new table, and for every node, I will put it in a table cell, for example:

str += ' <td valign=top align=center > '; 
str += this.node(cn, n);
str += ' </td> ';

Now, I think I should explain what the biggest problem I had when I developed this script, it's the lines between the nodes. So I started with a trivial idea or solution which is putting a border-top style for the table cell that contains a child node, and then I had to go with this idea and split each table cell that contains a child node into a new table with two rows: one for the lines and the other for the node text, icon and plus/minus button if it exists. The first row in that table is split into three cells: the first cell should have a border top in any of these two cases:

  1. the child node is a rightmost node.
  2. the child node is a middle node.

The second cell will contain a vertical line, and this line should be displayed in any case. The third cell should have a border top in any of these two cases:

  1. The child node is a leftmost node.
  2. The child node is a middle node.

So, I had to add three new properties to the tree node object: one if this node is a leftmost node or not, the second if this node is a rightmost node or not, and the third if the node is the only child or not. If the three values are false, then this node is a middle node. I had to keep track of how much children every parent has, and the index of the node between the parent and the children, and based on these numbers, I could decide which node is at the very left, which is at the very right, and which is an only child. And, here's the most effective part of the code:

// Creates the tree structure 
dTree.prototype.addNode = function(pNode) 
{ 
    var str = ''; 
    str += '<table border=0 ' + 
           'cellpadding=0 cellspacing=0 >'; 
    str += ' <tr>'; 
    var n=0; 
    if (this.config.inOrder) 
        n = pNode._ai; 

    var childsIndex =0;
    
    for (n; n<this.aNodes.length; n++)
    // loop through child nodes of each parent
    { 
        if (this.aNodes[n].pid == pNode.id) 
        { 
        var cn = this.aNodes[n]; 
        cn._p = pNode; cn._ai = n; 
        this.setCS(cn); 
        // Checks if a node has any children
        // and if it is the last sibling 
        cn._childIndex = childsIndex++;
        // set the index of the node
        // among its parent childs

        if(cn._p._children <= 1)
        // if this is the only child
            cn._isOnly; 
        else 
        { 
            if(cn._childIndex == 0)
            // if it's the very left node 
                cn._isLeft=true; 
            if(cn._childIndex == cn._p._children-1)
            // if it's the very right node 
                cn._isRight=true; 
        } 
        if (!cn.target && this.config.target) 
            cn.target = this.config.target; 
        if (cn._hc && !cn._io && this.config.useCookies) 
            cn._io = this.isOpen(cn.id); 
        if (!this.config.folderLinks && cn._hc) 
            cn.url = null; 
        if (this.config.useSelection && cn.id == 
            this.selectedNode && !this.selectedFound) 
        { 
            cn._is = true; this.selectedNode = n; 
            this.selectedFound = true; 
        } 
        str += ' <td valign=top align=center > '; 
        str += this.node(cn, n); 
        str += ' </td> '; 
        
        if (cn._ls) 
            break; 
        } 
    } 
    str += ' </tr>';
    str += '</table>';

    return str; 
    }; 

// Creates the node icon, url and text 
dTree.prototype.node = function(node, nodeId) 
{ 

    if(node._p._children <= 1)
        node._isOnly=true;

    var str = '<div class="dTreeNode" style="white-space:nowrap">'; 
    str += '<table border="0" cellpadding="0" ' + 
           'cellspacing="0" width="100%" >';
    str += '<tr>'; // first level of lines
    str += ' <td align="center" width="52%" ';
    
    if (this.root.id != node.pid) // if it's not a root node 
    { 
        if(this.config.useLines) // if we using line
        { 
            if(node._isOnly) // if it's the only child 
            { 
                str += ''; 
            } 
            else if(node._isLeft) // if it's the very left node 
            { 
                str += ''; 
            } 
            else if(node._isRight) // if it's the very right node 
            { 
                str += ' style="border-top-width:1px;' + 
                       'border-top-style:dotted;' + 
                       'border-top-color:Gray;" '; 
            } 
            else // if it's the middle node 
            { 
                str += ' style="border-top-width:1px;border' + 
                       '-top-style:dotted;border-top-color:Gray;" '; 
            } 
        } 
    } 
    str += ' >&nbsp; '; 

    str += ' </td>';
    str += ' <td valign="top" style="padding-top:0px;" ' + 
           'align="center" width="1%" ';
    str += ' >'; 
    
    if (this.root.id != node.pid)
    /// if this node isn't a first level node 
    { 
        str += '<img src="'; 
        if(this.config.useLines) 
        { 
            str += this.icon.line;
        } 
        else 
        { 
            str += this.icon.empty; 
        } 
        str += '" alt="" />'; 
    }


    str += ' </td>'; 
    str += ' <td align="center" width="52%" '; 

    if (this.root.id != node.pid) 
    { 
        if(this.config.useLines) 
        { 
            if(node._isOnly) 
                str += ' '; 
            else if(node._isLeft) 
                str += ' style="border-top-width:1px;border' + 
                       '-top-style:dotted;border-top-color:Gray;" '; 
            else if(node._isRight) 
                str += ''; 
            else 
                str += ' style="border-top-width:1px;border' + 
                       '-top-style:dotted;border-top-color:Gray;" '; 
        } 
    } 
    str += ' >&nbsp; '; 
    str += ' </td>'; 
    str += '</tr>'; 

    str += '<tr>'; 
    str += ' <td align="center" colspan="3">'; 
    str += '<table border=0 cellpadding="0" cellspacing="0" >'; 
    str += '<tr><td valign=top align=center>' + 
           this.indent(node, nodeId); 
    
    if (this.config.useIcons) 
    { 
        if (!node.icon) 
            node.icon = (this.root.id == node.pid) ? 
                         this.icon.root : ((node._hc) ? 
                         this.icon.folder : this.icon.node); 
        if (!node.iconOpen) 
            node.iconOpen = (node._hc) ? 
                             this.icon.folderOpen : 
                             this.icon.node; 
        if (this.root.id == node.pid) 
        { 
            node.icon = this.icon.root; 
            node.iconOpen = this.icon.root; 
        } 
        
        str += '<img id="i' + this.obj + nodeId + '" src="' + 
               ((node._io) ? node.iconOpen : node.icon) + '" alt="" />'; 
    } 
    str+="</td></tr><tr><td valign=top" + 
         " align=center style='white-space:nowrap'>";

    if (node.url) 
    { 
        str += '<a id="s' + this.obj + nodeId + '" class="' + 
               ((this.config.useSelection) ? ((node._is ? 'nodeSel' : 
                 'node')) : 'node') + '" href="' + node.url + '"'; 
        if (node.title) 
            str += ' title="' + node.title + '"'; 
        if (node.target) 
            str += ' target="' + node.target + '"'; 
        if (this.config.useStatusText) 
            str += ' onmouseover="window.status=\'' + node.name + 
                   '\';return true;" ' + 
                   'onmouseout="window.status=\'\';return true;" '; 
        if (this.config.useSelection && ((node._hc && 
            this.config.folderLinks) || !node._hc)) 
            str += ' onclick="javascript: ' + this.obj + 
                   '.s(' + nodeId + ');"'; 
        str += '>'; 
    } 
    else if ((!this.config.folderLinks || !node.url) && 
               node._hc && node.pid != this.root.id) 
            str += '<a href="javascript: ' + this.obj + 
                   '.o(' + nodeId + ');" class="node">'; 

    str += node.name;
    if (node.url || ((!this.config.folderLinks || 
                      !node.url) && node._hc)) 
    str += '</a>'; 
    str += '</div>'; 
    str += '</td></tr></table>'; 
    str += '</td></tr></table>'; 

    if (node._hc) // if this node have children
    { 
        str += '<div id="d' + this.obj + nodeId + '" class="clip" ' + 
               'style="display:' + ((node._io) ? 'block' : 'none') + ';">'; 
        str += '<table border=0 cellpadding=0 cellspacing=0>';
        str += '<tr><td height="9" align="center"><img src="' + 
               this.icon.smallLine+'" alt="" border=0></td></tr>';
        str += '<tr><td>';

        str += this.addNode(node); 

        str += '</td></tr></table>';
        str += '</div>'; 
    } 
    this.aIndent.pop(); 
    return str; 
};

Points of interest

The most important thing I learned from this script is how much recursion can be effective in JavaScript. Also, it was a very good experiment to go with a trivial idea to build good lines in a tree. I think it's pretty stable now.

History

This is my first article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Mahmoud Tahoon
Web Developer
Egypt Egypt
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionJavaScript Horizontal TreememberBiswa_c23 Apr '12 - 2:33 
Grate Work , wise you all the best !!
BugConnection line can not be aligned when nodes is too manymembermaxmas22 Feb '12 - 21:14 
Can you continue to support the code? D'Oh! | :doh:
When the node is too many, the connection line can not be aligned.
Can you fixed this problem? Big Grin | :-D
 

Example (661 nodes): http://www.maxmas.biz/dtree/
GeneralMy vote of 5memberMember 786771220 Jun '11 - 0:55 
it is toooooo usefull to me and very very thank you mohammad
Questionhorizontal tree with javascriptmemberBadari Narayana12 Jan '11 - 18:32 
Hello Mahmoud Tahoon,
 
This article excellent.When i click the parent node it shows child nodes.it's fine. Suppose parent hava a 100 childs But my requirement
in this consept showing only one node.When i click that node it shows another 99 nodes in same level(expandable another nodes in same level) And also But this article not supported browsers like Internet Exploser.

Please help me
 
Note:I don't want verticall tree.
GeneralRe: horizontal tree with javascriptmemberBassam Abdul-Baki18 Jan '11 - 3:04 
How will you know which child out of the 100 to display if you do not see them all first?
GeneralList items instead of tablesmemberanand sueman14 Dec '10 - 1:15 
I was wondering why you used tables instead of list items
GeneralFamily TreememberBahraini015 Apr '10 - 23:44 
I've read your article ,it is nice but I need to use the tree for drawing family tree.
 
Could I append Child automatically to a node? Could I add another tree inside the parent tree? Could the node has mutiple parents?
 
I hope if you could help me in that.
 
Thanks and Regards,
QuestionHow to generate dynamic node from the database in horizontal tree view. please help mememberritesh suhane1 Mar '10 - 19:20 
hi. I am ritesh suhane
 
I need to create horizontal tree view from the database.
In database "node" table contains four fields "Node_Id", "Left_Node_Id", "Right_Node_Id", "Root_Id". I need to display all nodes as the above figure. please help me.
 
Thank you.
QuestionHowto dynamicly add a node to the treememberhacking_mike27 Aug '09 - 1:24 
Is there an (ajax?) way to dynamicly add a node to the tree?
AnswerRe: Howto dynamicly add a node to the treememberhacking_mike28 Aug '09 - 4:48 
Please help!!!!
GeneralPlease Helpmemberluo_fen_fang21 May '09 - 19:16 
Hi. I am facing an issue when the tree is over 900 nodes.
I keep receiving this warning message. "A script on this page is causing the Internet Explorer
to run slowly. If it continues to run, the computer may become unresponsive. Do you want to abort the script?"
I do not want to change the MaxScriptStatements settings in the Registry editor because
all the client pc will be affected. Is there any workaround? Thanks in advance.
 
modified on Tuesday, May 26, 2009 1:33 AM

GeneralHuge Data Problem.memberhymns27 Apr '09 - 5:24 
I've problem when the data bigger. Tree will corrupted. Can you fixed for this problem?
 
Example: htree example
Generalthanks very muchmember21cn_zy24 Jun '08 - 16:38 
thanks very much
GeneralGreat work, but look thismemberzenhaust27 Apr '08 - 12:47 
Hi boys,
 
look this horizontal tree.
 
Horizontal tree object javascript
 
It's a great work too.
GeneralVertical Menu limitmemberBoon8230 Dec '07 - 18:33 
I think there is maximum 11 to 13 level for the vertical menu. If more than that, the node would not show out anymore. Anyone know how to solve this? Please advise. Thanks
GeneralRe: Vertical Menu limitmembernina_lyy15 May '08 - 17:22 
I have the same problem. Please advise.
GeneralRe: Vertical Menu limitmembergirishoak4 Jan '09 - 18:44 
Even I have the same problem. Please advise.Has anybody got solution for this?
GeneralRe: Vertical Menu limitmembersuperb12 May '11 - 23:14 
even i m also facing the same problem the tree view is not extending..
its jst displaying at near 50 nods only..
reply if any one has solution...
Generalgreat workmemberadi_99924 Sep '07 - 1:33 
superb work man..
 
adi_999

Questionfunctioning of the codememberseralan27 Jul '07 - 4:53 
hello friends, i have used this code in my project,every thin is working fine. but i'm facing some problem
 
as per the code if we give mytree.openTo(4,true) the tree should be open to certain node.
 
in my project i'm dynamically constructing three dimensional array and using in the code dtree.js, it displayed the tree successively. but the openTo() function is not opening the tree to certain node.in my code i've written after constructing the tree:
 
mytree.closeAll();
mytree.openTo(15,true);
 
this is the problem: if there is any solution foer this please mailto: saravana_07@yahoo.co.inRose | [Rose]
AnswerRe: functioning of the codememberadi_9994 Oct '07 - 21:25 
Hi,
may be the reply might be late,but it might be helping others who check this
 
Replace the openTo function in vertdtree.js with the following code.
With this, tree opens upto the specified node
 
***************************
// Opens the tree to a specific node
 
dTree.prototype.openTo = function(nId, bSelect, bFirst) {
if (!bFirst) {
for (var n=0; nadi_999
QuestionPrint Problemmembershelal16 Aug '06 - 22:45 
Hi,
First of all, i would like to thank you for this good work..
it is very useful script.
i tried it with large input data and it works successfully.
the problem is my tree is very wide..when i wanted to print it, only the most left side of the page is printed...
I need to print the whole tree, even if it will printed on more than one paper.
if you have any idea how to solve that, it will be much appreciated.
thanks

 
shelal
AnswerRe: Print Problemmemberharidip14 Jun '09 - 19:29 
I am also facing same problem for printing horizontally wide tree.
If you find any solution please please inform me on my email id "Harikrushna.trivedi@RIL.com".
 
This problem become headach for me and its a stopper for my project.
 
Thanx in advance
 
HARI TRIVEDI
RELIANCE IND. LTD.
JAMNAGAR - INDIA
+91 9724347751
HARIKRUSHNA.TRIVEDI@RIL.COM
GeneralMy Example [modified*3]memberBassam Abdul-Baki7 Aug '06 - 9:45 
<html>
<head>
<title>Tree Example</title>
<link rel="StyleSheet" href="dtree/dtree.css" type="text/css" />
<script type="text/javascript" src="dtree/vertdtree.js"></script>
<script language="JavaScript">
</script>
</head>
<body>
<h1 align="center">Collatz Problem</h1>
<br/>
<div align="center">
<script language="JavaScript">
mytree = new dTree('mytree');
 
var maxLoop = 100;
nID = new Array();
pID = new Array();

nID.push(1);
nID.push(2);
nID.push(4);
nID.push(8);

pID.push(-1);
pID.push(0);
pID.push(1);
pID.push(2);

for (var i = 3; i < maxLoop; i++)
{
if ((nID[i] % 6) == 4)
{
nID.push((nID[i] - 1) / 3);
pID.push(i);
}
nID.push(2 * nID[i]);
pID.push(i);
}

for (var i = 0; i < maxLoop; i++)
{
mytree.add(i, pID[i], nID[i], '', nID[i], '', '');
}
 
document.write(mytree);
</script>
</div>
</body>
</html>
 
Last modified: Thursday, August 10, 2006 2:42:30 PM --
rtIcon" src="chrome://targetalert/content/skin/new.png"> - LinkedIn<img class="TargetAlertIcon" src="chrome://targetalert/content/skin/new.png">
 
Last modified: Monday, August 07, 2006 2:42:58 PM --

GeneralRe: My ExamplememberBassam Abdul-Baki10 Aug '06 - 9:47 
There seems to be a bug somewhere in IE/FireFox/this code where I can't add any more nodes.
 

"People who want to share their religious views with you almost never want you to share yours with them." - Anonymous
 
Web - Blog - RSS - Math - LinkedIn

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 1 Jul 2006
Article Copyright 2006 by Mahmoud Tahoon
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid