Click here to Skip to main content
11,441,974 members (73,016 online)
Click here to Skip to main content

JavaScript Horizontal Tree

, 1 Jul 2006
Rate this:
Please Sign up or sign in to vote.
Horizontal treeview for JavaScript.

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

Share

About the Author

Mahmoud Tahoon
Web Developer
Egypt Egypt
No Biography provided

Comments and Discussions

 
You must Sign In to use this message board.
    Spacing  Noise  Layout  Per page   
QuestionWordpress Plugin
Member 1089901622-Jun-14 0:43
memberMember 1089901622-Jun-14 0:43 
Is there any wordpress plugin for the Same..??
QuestionThanks for such a great work
Member 1043622425-Mar-14 22:59
memberMember 1043622425-Mar-14 22:59 
I really searched around allot but your code is awesome.
QuestionJavaScript Horizontal Tree
Biswa_c23-Apr-12 3:33
memberBiswa_c23-Apr-12 3:33 
Grate Work , wise you all the best !!
BugConnection line can not be aligned when nodes is too many
maxmas22-Feb-12 22:14
membermaxmas22-Feb-12 22: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 5
Member 786771220-Jun-11 1:55
memberMember 786771220-Jun-11 1:55 
it is toooooo usefull to me and very very thank you mohammad
Questionhorizontal tree with javascript
Badari Narayana12-Jan-11 19:32
memberBadari Narayana12-Jan-11 19: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 javascript
Bassam Abdul-Baki18-Jan-11 4:04
memberBassam Abdul-Baki18-Jan-11 4: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 tables
anand sueman14-Dec-10 2:15
memberanand sueman14-Dec-10 2:15 
I was wondering why you used tables instead of list items
GeneralFamily Tree
Bahraini016-Apr-10 0:44
memberBahraini016-Apr-10 0: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 me
ritesh suhane1-Mar-10 20:20
memberritesh suhane1-Mar-10 20: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 tree
hacking_mike27-Aug-09 2:24
memberhacking_mike27-Aug-09 2:24 
Is there an (ajax?) way to dynamicly add a node to the tree?
AnswerRe: Howto dynamicly add a node to the tree
hacking_mike28-Aug-09 5:48
memberhacking_mike28-Aug-09 5:48 
Please help!!!!
GeneralPlease Help
luo_fen_fang21-May-09 20:16
memberluo_fen_fang21-May-09 20: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.
hymns27-Apr-09 6:24
memberhymns27-Apr-09 6:24 
I've problem when the data bigger. Tree will corrupted. Can you fixed for this problem?

Example: htree example
Generalthanks very much
21cn_zy24-Jun-08 17:38
member21cn_zy24-Jun-08 17:38 
thanks very much
GeneralGreat work, but look this
zenhaust27-Apr-08 13:47
memberzenhaust27-Apr-08 13:47 
Hi boys,

look this horizontal tree.

Horizontal tree object javascript

It's a great work too.
GeneralVertical Menu limit
Boon8230-Dec-07 19:33
memberBoon8230-Dec-07 19: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 limit
nina_lyy15-May-08 18:22
membernina_lyy15-May-08 18:22 
I have the same problem. Please advise.
GeneralRe: Vertical Menu limit
girishoak4-Jan-09 19:44
membergirishoak4-Jan-09 19:44 
Even I have the same problem. Please advise.Has anybody got solution for this?
GeneralRe: Vertical Menu limit
superb13-May-11 0:14
membersuperb13-May-11 0: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 work
adi_99924-Sep-07 2:33
memberadi_99924-Sep-07 2:33 
superb work man..

adi_999

Questionfunctioning of the code
seralan27-Jul-07 5:53
memberseralan27-Jul-07 5: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: [email protected]Rose | [Rose]
AnswerRe: functioning of the code
adi_9994-Oct-07 22:25
memberadi_9994-Oct-07 22: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 Problem
shelal16-Aug-06 23:45
membershelal16-Aug-06 23: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 Problem
haridip14-Jun-09 20:29
memberharidip14-Jun-09 20: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 "[email protected]".

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
[email protected]
GeneralMy Example [modified*3]
Bassam Abdul-Baki7-Aug-06 10:45
memberBassam Abdul-Baki7-Aug-06 10: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 Example
Bassam Abdul-Baki10-Aug-06 10:47
memberBassam Abdul-Baki10-Aug-06 10: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
GeneralOpen all/close all isn't working
Shai Bar-Lev16-Jul-06 11:30
memberShai Bar-Lev16-Jul-06 11:30 
Confused | :confused: The methods openAll() and closeAll() are not working.

Shai
GeneralRe: Open all/close all isn't working
andrewholgate23-Aug-06 1:02
memberandrewholgate23-Aug-06 1:02 
The method openAll() and closeAll() do work but perhaps not the way you want them too.

You will notice in Geir Landrö's example1.html (included in the download) clicking on "open all" or "close all" will open/close all of the nodes EXCEPT for the root node. Test it yourself.

So, if the root node is closed and you click on "open all", the hidden nodes will all be opened. The difference is that you will only see the open nodes once you open the root node.

Personally, I don't know why it was done like this but to modify it is simple:


// Open or close all nodes
dTree.prototype.oAll = function(status) {
for (var n=0; n if (this.aNodes[n]._hc) {
this.nodeStatus(status, n, this.aNodes[n]._ls);
this.aNodes[n]._io = status;
}
}
if (this.config.useCookies) this.updateCookie();
};



This new line of code will open all nodes, even the root.

Hope this helps,
Andrew
GeneralGreat work
freakuency14-Jul-06 5:25
memberfreakuency14-Jul-06 5:25 
Great post.Maybe we can come out with load on demand version?
GeneralGood Job
norm .net13-Jul-06 5:11
membernorm .net13-Jul-06 5:11 
5!

We made the buttons on the screen look so good you'll want to lick them. Steve Jobs
QuestionExcelant Work
JulianPo6-Jul-06 9:56
memberJulianPo6-Jul-06 9:56 
Any thoughts of populating the tree using XML ?

Be happy
GeneralIntrested Article
Tittle Joseph5-Jul-06 6:01
memberTittle Joseph5-Jul-06 6:01 
Hi,

I must say that your article is intrested to read and i'm seeing its usage in various other ways, even though it is your first article but makes people realize on your programming skill, moreover screenshot attach was also impressive.

I've few suggestion, try providing complete code in the example itself, or atleast what all is require, e.g. what is dNode? very rare people go for downloading the project unless they require it, most of them just want to go through and wants to see the level of programming involved.

Overall good work and keep posting such good articles. Smile | :)

---------
Tittle
GeneralPerfect 5!
Bassam Abdul-Baki4-Jul-06 17:41
memberBassam Abdul-Baki4-Jul-06 17:41 
Great job.


"Religion is assurance in numbers." - Bassam Abdul-Baki

Web - Blog - RSS - Math - LinkedIn
GeneralThank you
Mahmoud Tahoon4-Jul-06 22:42
memberMahmoud Tahoon4-Jul-06 22:42 
Thank you Mr.Bassam for your comment, it's my first Article actually, and I didn't expect this appreciation thank you for all who commented about my article..

TAHOON
JokeNice one...
Leonhardt Wille3-Jul-06 23:21
memberLeonhardt Wille3-Jul-06 23:21 
Great work! I'll get back to it when building a sitemap for my website.
If you find a little time, please apply some formatting and syntax highlighting to your article. You could also shorten some of your tapeworm-like sentences to improve readability Big Grin | :-D
GeneralNice work
Ashley van Gerven3-Jul-06 10:49
memberAshley van Gerven3-Jul-06 10:49 
Well done - this could be extremely useful for some applications.

Small suggestion - when you click a + or - Internet Explorer draws focus dots around the graphic... IMO a cosmetic improvement would be to remove focus from the link so you don't see this.

And maybe the node icon could be clickable - i.e. to select that node.

cheers

"Nothing ever changes by staying the same." - David Brent (BBC's The Office)
~ ScrollingGrid: A cross-browser 2-way-scrolling freeze-header control for the ASP.NET DataGrid
GeneralSource Link &amp; Image; Formatting
fwsouthern2-Jul-06 15:10
memberfwsouthern2-Jul-06 15:10 
Please fix your links & formatting .....

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

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