Jump to content

Script to display array as a tree


Staggan

Recommended Posts

Hello

 

I have an array that I would like to display as a family tree... and am looking for an example script that will allow me to do this.

 

I want to be able to create X number of generations and fill the boxes with data from my array....

 

So, if I want 5 generations I want to generate a tree with 63 elements or boxes

 

Any help would be appreciated

 

Thanks

 

Link to comment
Share on other sites

Here is a small script that will create a table in the general format of a family tree based upon the number of generations given. But, I would need to know the format of your input array to know how to populate the contents.

 

<?php

$generations = 5;

$total_columns = pow(2, $generations);
$familyTree = '';

for($gen = 0; $gen <= $generations; $gen++)
{
    $gen_family_count = pow(2, $gen);

    $colspan = $total_columns / $gen_family_count;

    $familyTree .= "<tr>\n";
    for($i=0; $i<$gen_family_count; $i++)
    {
        $familyTree .= "<td colspan='{$colspan}'>{$i}</td>\n";
    }
    $familyTree .= "<tr>\n";
}

?>
<html>
<head>
  <style>
    td { text-align: center; }
  </style>
</head>
<body>

<table border='1'>
    <?php echo $familyTree; ?>
</table>

</body>
</html>

Link to comment
Share on other sites

Hello

 

My array is formatted as follows:

 

0 first level

2, 1 second level

6, 5, 4, 3 third level

 

and so on, populating from right to left

 

Here is a complete example of the array:

 



Array
(
    [0] => Kegluneq Aaliyah
    [1] => Arctictreks Dark As Night
    [2] => Arctictrek Silver Spirit
    [3] => KEBUCK SCHRIMSHANDER
    [4] => ARCTICTREKS CHERISH FOREVER
    [7] => Pat Gagnon
    [8] => Coquette La Rouge D'Ericlam
    [15] => Ewok D'Ericlam
    [16] => Heidi D'Ericlam
    [31] => David Le Noir D'Ericlam
    [32] => B-Wouack De Patcie
    [33] => Comanche D'Ericlam
    [34] => Finskan D'Ericlam
    [17] => Himmuk D'Ericlam
    [18] => Inouska D'Ericlam
    [35] => Comanche D'Ericlam
    [36] => Finskan D'Ericlam
    [37] => Diable Le Rouge D'Ericlam
    [38] => Frosty D'Ericlam
    [9] => Storm Kloud's Chosen to Win
    [10] => Arctictrek's Indiana
    [19] => Storm Kloud's Keep the Win
    [20] => Storm Kloud's Hharmony
    [39] => Storm Kloud's Oomiak
    [40] => Storm Kloud Ddawn In The North
    [41] => Storm Kloud's Better Than Ever
    [42] => Princess Nikkita Sno-Kloud
    [21] => Jacbar Alaskan Black Night
    [22] => Rameslyn Cherokee Squaw
    [43] => Highnoons Kaskinampo of Jacbar
    [44] => Malnorska's Gypsy Lady
    [45] => Fire 'N Ice In Conclusion
    [46] => Highnoons Loucheuse
    [5] => Shepherdsway Touch of Gold
    [6] => Arctictreks Legend of a Lady
    [11] => Outriggers Red Wolf
    [12] => Eastern Hill Coldfoot Coco
    [23] => Keikewabic's P'Tis Guy
    [24] => Keikewabic's Chitina
    [47] => Keikewabic's P'Tis N'Ours
    [48] => Keikewabic's Mitchie
    [49] => Keikewabic's P'Tis N'Ours
    [50] => Keikewabic & Burley's Merlin
    [25] => Yukon (N5)
    [26] => Ivalos Ayla
    [51] => A-Mikko
    [52] => B Ika Tanana
    [53] => Ivalos Froststar
    [54] => Chinooks Ivalo
    [13] => Shepherdsway Phantom Scout
    [14] => Arctictrek's Indiana
    [27] => Storm Kloud's Chosen to Win
    [28] => Shepherdsway Black Oasis
    [55] => Storm Kloud's Keep the Win
    [56] => Storm Kloud's Hharmony
    [57] => Fire 'N Ice In Conclusion
    [58] => Highnoons Ottawa
    [29] => Jacbar Alaskan Black Night
    [30] => Rameslyn Cherokee Squaw
    [59] => Highnoons Kaskinampo of Jacbar
    [60] => Malnorska's Gypsy Lady
    [61] => Fire 'N Ice In Conclusion
    [62] => Highnoons Loucheuse
)

 

I already know the number of generations because I set that at the beginning

 

Thanks

 

Link to comment
Share on other sites

OK, so, I have it working.... thank you... but some more advice if you could...

 

here is the changed code:

 


$generations = $numLevelsToSearch;
$elements = 0 ;

$total_columns = pow(2, $generations);

$familyTree = '';

for($gen = 0; $gen <= $generations; $gen++){    

	$gen_family_count = pow(2, $gen);    
	$colspan = $total_columns / $gen_family_count;    
	$familyTree .= "<tr>\n";    

	for($i=0; $i<$gen_family_count; $i++){        
	$elements +=1;
	$familyTree .= "<td colspan='{$colspan}'>{$familyTreeArray[$elements]}</td>\n";    
	}    

	$familyTree .= "<tr>\n";}
	echo $elements;
?>


	<html><head>  <style>    td { text-align: center; }  </style></head><body><table border='1'>    <?php echo $familyTree; ?></table></body></html>

<?  


 

How can I increase the spacing and is it possible to also do this horizontally?

 

Thanks

 

 

Link to comment
Share on other sites

It really depends.

 

foreach will loop through the arrays in whatever order they're already in

for will loop through the keys in numerical order.

 

<?php

$family = range(0,62);
$familySize = count( $family );

// This will determine how many columns will be in our biggest branch
// http://en.wikipedia.org/wiki/Power_of_two#Algorithm_to_convert_any_number_into_nearest_power_of_two_number
$colspan = pow(2,ceil(log($familySize/2,2)));
$x = 1; $y = 1;
echo '<table border="1">';
foreach( $family as $member ) {

if( $x == 1 ) echo '<tr>';

echo '<td colspan="'.$colspan.'">'.$member.'</td>';

if( $x == pow(2,$y-1) ) {
	echo '</tr>';
	$colspan /= 2;
	$y++; $x = 1;
} else $x++;

}
echo '</table>';

?>

 

Keep in mind, the code won't create blank cells if the data doesn't 'fit' perfectly into the tree.

Link to comment
Share on other sites

Of course, you're going to have to do different calculations though. Here's a helpful graph

 

0  1  3  7  15 31
               32
            16 33
               34
         8  17 35
               36
            18 37
               38
      4  9  19 39
               40
            20 41
               42
         10 21 43
               44
            22 45
               46
   2  5  11 23 47
               48
            24 49
               50
         12 25 51
               52
            26 53
               54
      6  13 27 55
               56
            28 57
               58
         14 29 59
               60
            30 61
               62

 

You need to turn that into a table, using rowspan.

Link to comment
Share on other sites

Not getting very far, heh.

 

I understand my first rowspan should be = to the number of rows I'll need.

 

Which for a 3 generation pedigree is 8 rows... so my first row span should be 8 rows with a single value

 

my second should be 2 entries, each spanning 4 rows

 

my third should be 4 entries each spanning 2 rows

 

and my last 8 entries each spannnig a single row...

 

But I am not sure how to build this table, let alone populate it yet....

 

I am sure I am being stupid but not sure why... everything I have tried so far just gives me some wierd layout....

 

 

 

 

Link to comment
Share on other sites

Ok, here you go. I'm not even going to try and explain the logic

<?php

$generations = 3;

//Create temp array to store results
$genTableArray = array();
for($genCol = 0; $genCol <= $generations; $genCol++)
{
    $genRowCount = pow(2, $genCol);
    $rowspan = pow(2, $generations) / $genRowCount;

    for($familyGenCount=0; $familyGenCount<$genRowCount; $familyGenCount++)
    {
        $personIndex = pow(2, $genCol) + $familyGenCount - 1;
        $rowIndex = $rowspan * $familyGenCount;
        $genTableArray[$rowIndex][] = "<td rowspan='{$rowspan}'>$personIndex - {$familyTreeArray[$personIndex]}</td>\n";
    }
}

//Output the array into a table
ksort($genTableArray);
$familyTreeHTML = '';
foreach($genTableArray as $rowData)
{
    $familyTreeHTML .= "<tr>\n" . implode("\n", $rowData) . "</tr>\n";
}

?>
<html>
<head>
  <style>
    td { text-align: center; }
  </style>
</head>
<body>

<table border='1'>
    <?php echo $familyTreeHTML; ?>
</table>

</body>
</html>

 

I tried to write it to create the table directly, but couldn't figure out the formulas to determine which records to output on each row. So, I just processed the records similar to the original scripts but then dynamically populate an array.

Link to comment
Share on other sites

OK, here is the code with more comments

$generations = 5;

//Create temp array to store results
$genTableArray = array();
//Run through each column based upon the number of generations.
//The column count is generation + 1
for($genCol = 0; $genCol <= $generations; $genCol++)
{
    //Detemine the number of rows/records in the colum (1, 2, 4, 8, 16, ...)
    $genRowCount = pow(2, $genCol);
    //Detemine the rowspan for each record/row in this column
    //This will be the (total # rows / record in this row)
    //The total # of rows is based upon the number of generations to the power of 2
    $rowspan = pow(2, $generations) / $genRowCount;

    //Run a loop for the number of records in this column
    for($familyGenCount=0; $familyGenCount<$genRowCount; $familyGenCount++)
    {
        //Calculate the person index to use based upon the column / row
        //First column has index 0, second column has 1/2, third column has 3/4/5/6, etc.
        //The formula is needed due to the size being dynamic
        $personIndex = pow(2, $genCol) + $familyGenCount - 1;
        //Determine the row index for this record. This is dynamic based upon the 
        //total number of columns and the column/record beign displayed. For example,
        //if there are 3 generation there will be a total of 8 rows. Column 2 will have two records
        //So record 1 will go in the first row and record 2 will go into the 4th row
        $rowIndex = $rowspan * $familyGenCount;
        //Add the recod to the appropriate (row) in the array using the rowspan. The key of the array is the row index
        $genTableArray[$rowIndex][] = "<td rowspan='{$rowspan}'>$personIndex - {$familyTreeArray[$personIndex]}</td>\n";
    }
}

//Output the array into a table
//Since records weren't added to rows in order (0, 1, 2, ...) need to sort
//the array by keys to get int he correct order
ksort($genTableArray);
$familyTreeHTML = '';
//Loop through each row in order and implode the values into an output variable
foreach($genTableArray as $rowData)
{
    $familyTreeHTML .= "<tr>\n" . implode("\n", $rowData) . "</tr>\n";
}

 

Also, so you can understand the final process, here is what the temp array looks like before the final processing

Array
(
    [0] => Array
        (
            [0] => <td rowspan='8'>0 - Kegluneq Aaliyah</td>
            [1] => <td rowspan='4'>1 - Arctictreks Dark As Night</td>
            [2] => <td rowspan='2'>3 - KEBUCK SCHRIMSHANDER</td>
            [3] => <td rowspan='1'>7 - Pat Gagnon</td>
        )

    [1] => Array
        (
            [0] => <td rowspan='1'>8 - Coquette La Rouge D'Ericlam</td>
        )

    [2] => Array
        (
            [0] => <td rowspan='2'>4 - ARCTICTREKS CHERISH FOREVER</td>
            [1] => <td rowspan='1'>9 - Storm Kloud's Chosen to Win</td>
        )

    [3] => Array
        (
            [0] => <td rowspan='1'>10 - Arctictrek's Indiana</td>
        )

    [4] => Array
        (
            [0] => <td rowspan='4'>2 - Arctictrek Silver Spirit</td>
            [1] => <td rowspan='2'>5 - Shepherdsway Touch of Gold</td>
            [2] => <td rowspan='1'>11 - Outriggers Red Wolf</td>
        )

    [5] => Array
        (
            [0] => <td rowspan='1'>12 - Eastern Hill Coldfoot Coco</td>
        )

    [6] => Array
        (
            [0] => <td rowspan='2'>6 - Arctictreks Legend of a Lady</td>
            [1] => <td rowspan='1'>13 - Shepherdsway Phantom Scout</td>
        )

    [7] => Array
        (
            [0] => <td rowspan='1'>14 - Arctictrek's Indiana</td>
        )
)

Link to comment
Share on other sites

Thanks.... it will help me to understand it much more easily.

 

I am probably taking advantage, but am I able to add an onclick into the population of the table?

 

For example, if I generated the table, and then wanted to click on one of the dogs to bring up a new table in a new page with that dog as the root... is that possible?

 

Can I call a function on click to post to a new page?

 

Thanks

 

 

Link to comment
Share on other sites

<style type="text/css">
<!--
div.tree {
   text-align: center;
   float: right;
}
div.clr {
   clear: both;
}
//-->
</script>

echo '<div>';

sort($tree, SORT_NUMERIC);
$i = 1;
$n = count($tree)-1;
for($lvl = 0; $lvl < $n; ++$lvl)
{
   $decendant = isset($tree[$lvl]) ? stripslashes(htmlentities($tree[$lvl], ENT_QUOTES, 'UTF-8')) : 'Unknown';
   echo '<div class="tree" style="width: '. (100/pow(2, $i-1)) .'%;">'. $decendant .'</div>';
   if ( (pow(2, $i-1) % $lvl) == 0 )
   {
      echo '<div class="clr"></div>';
      $i++;
   }
}
echo '</div>';

That work?

Link to comment
Share on other sites

Can I call a function on click to post to a new page?

 

There is only one line in that code that produces the actual output

$genTableArray[$rowIndex][] = "<td rowspan='{$rowspan}'>$personIndex - {$familyTreeArray[$personIndex]}</td>\n"

 

Put whatever other content you want in that. In this case, either put an onclick inside the TD tag or change teh content in the TD tags to a hyperlink. At the very least though, you would need to pass a value so the next page knows what dog to create the results on next. I guess you could use the name, but you should be passing an id value. But, your array doesn't contain an id, so . . .

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.