This topic is locked

Guide 9 - Draw Organization Chart

2/26/2021 1:24:36 PM
PHPRunner Tips and Tricks
fhumanes author


In this case, the request of a PHPRunner colleague was to be able to represent the Organization Chart of a company.
His initial problem was the use of a JavaScript library that had this function, but from my point of view, the complex thing is to "create" the hierarchical structure that must be given to these libraries so that they represent the aforementioned Organization Chart.
The library we have selected is OrgChart which, as you can see, has many functionalities and provides many examples that makes its use much easier.
Objetive
I have set this set of requirements:

  • The definition of the hierarchy of the organization should be very easy to define. It is only necessary to define the immediate boss of each of the people. For the example, there can only be one person who does not have an immediate boss.
  • It is wanted that in the representation of each one of the people there is additional information, in particular, that the photo of each one can be represented. This can be extended to almost anything.



DEMO: https://fhumanes.com/orgchart/
Technical Solution
I have used PHPRunner 10.4, but I could have used any 10.X version, as any of them would be just as valid.
I have done the integration of the OrgChart JavaScript library using a "LIST" page, from a view of the same table as "USER" and I have eliminated the presentation of all the fields and the paging information.


To this design I added a "Snippet" which is where I have put the code for the presentation of the graphic. This I have written in 2 files.
In the "hierarchy.php" file, the most important for me, is where we retrieve the information of all the database users and create an array with all of them.
This Array, we pass it to the "convertToHierarchy" function and convert it into another array that represents the hierarchy of the structure. This function is essential for the processing of hierarchical data. More information at: https://gist.github.com/ubermaniac/8834601
Once we have the hierarchy in the array, we must create the data structure that the JavaScript library requires. This is quite simple if we use recursive code to generate the information.



<?php

// Create ARRAY with the data Hierarchy

function convertToHierarchy($results, $idField='user_id', $parentIdField='Boss', $childrenField='') {

$hierarchy = array(); // -- Stores the final data

$itemReferences = array(); // -- temporary array, storing references to all items in a single-dimention

foreach ( $results as $item ) {

$id = $item[$idField];

$parentId = $item[$parentIdField];

if (isset($itemReferences[$parentId])) { // parent exists

$itemReferences[$parentId][$childrenField][$id] = $item; // assign item to parent

$itemReferences[$id] =& $itemReferences[$parentId][$childrenField][$id]; // reference parent's item in single-dimentional array

} elseif (!$parentId || !isset($hierarchy[$parentId])) { // -- parent Id empty or does not exist. Add it to the root

$hierarchy[$id] = $item;

$itemReferences[$id] =& $hierarchy[$id];

}

}

unset($results, $item, $id, $parentId);

// -- Run through the root one more time. If any child got added before it's parent, fix it.

foreach ( $hierarchy as $id => &$item ) {

$parentId = $item[$parentIdField];

if ( isset($itemReferences[$parentId] ) ) { // -- parent DOES exist

$itemReferences[$parentId][$childrenField][$id] = $item; // -- assign it to the parent's list of children

unset($hierarchy[$id]); // -- remove it from the root of the hierarchy

}

}

unset($itemReferences, $id, $item, $parentId);

return $hierarchy;

} //
function identation($level) {

$identation ='';

for ($i = 1;$i < $level; $i++) {

$identation .= "\t";

}

return $identation;

}

// Print data of record

function printRow($level, $row) {

global $datasource;

$datasource .= identation($level)."{ 'id': '".$row['id_user']."', 'name': '".addslashes($row['name'])."', 'title': '".addslashes($row['category'])."', 'picture': '".addslashes($row['picture'])."'";

};

function printHierarchy ($level, $Hierarchy) {

global $datasource;
do {

$key = key($Hierarchy);

$value = current($Hierarchy);

printRow($level+1, $value);

if ( is_array($value[children])){

$datasource .= ",\n".identation($level+1)." 'children': [ \n";

printHierarchy ($level+1, $value[children]); // Recursive

$datasource .= "\n".identation($level+1)." ]";

}

$datasource .= "},\n";

} while (next($Hierarchy));

$datasource = substr($datasource, 0, -2); // Delete last ","

}
global $conn;

// Create auxiliary Sorting tables

$results = array();

$sql = "SELECT id_orgchart_user id_user, ifnull(boss_id,'') id_parent , name, category, picture FROM orgchart_user";

$resql = DB::Query($sql);

/* get associative array */

while ($row = $resql->fetchAssoc()) {

$fileArray = my_json_decode($row["picture"]);

$picture = $fileArray[0]["name"];

if ($picture == NULL) $picture = 'files/no_existe.png';

$results[] = ['id_user' =>$row['id_user'],'id_parent' =>$row['id_parent'],'name' =>$row['name'], 'category' =>$row['category'],'picture' =>$picture];

// $results[] = $row;

}

$Hierarchy = convertToHierarchy($results,'id_user','id_parent','children'); // Create hierarchy from data
unset($results); // Delete variable

$level = 0;
$datasource = '';

global $datasource;
if ( count($Hierarchy) <> 0 ) {

printHierarchy ($level, $Hierarchy);

}

?>


Once we have the structure information, the only thing is to use the mentioned JavaScript library and this is done in the file "OrgChart.php".



<?php

include __DIR__.'/hierarchy.php';
$html = <<<EOT

<link rel="stylesheet" href="lib_orgchart/css/jquery.orgchart.css">

<style type="text/css">

#chart-container {

position: relative;

height: 520px;

border: 1px solid #aaa;

margin: 0.5rem;

overflow: auto;

text-align: center;

}

.orgchart { background: #fff; }

.orgchart .second-menu-icon {

transition: opacity .5s;

opacity: 0;

right: -5px;

top: -5px;

z-index: 2;

position: absolute;

}

.orgchart .second-menu-icon::before { background-color: rgba(68, 157, 68, 0.5); }

.orgchart .second-menu-icon:hover::before { background-color: #449d44; }

.orgchart .node:hover .second-menu-icon { opacity: 1; }

.orgchart .node .second-menu {

display: none;

position: absolute;

top: 0;

right: -70px;

border-radius: 35px;

box-shadow: 0 0 10px 1px #999;

background-color: #fff;

z-index: 1;

}

.orgchart .node .second-menu .avatar {

width: 60px;

height: 60px;

border-radius: 30px;

float: left;

margin: 5px;

}

</style>
<div id="chart-container"></div>
<script type="text/javascript" src="lib_orgchart/js/jquery.orgchart.js"></script>

<script type="text/javascript">

\$(function() {

console.log( "ready!" );
var datascource = $datasource;
\$('#chart-container').orgchart({

'data' : datascource,

'nodeId': 'id',

'visibleLevel': 2,

'nodeContent': 'title',

'toggleSiblingsResp': true,

'pan': true,

'zoom': true,

'zoominLimit': 7,

'zoomoutLimit': 0.5,

'chartClass': '',

'exportButton': false,

'exportButtonName': 'Export',

'exportFilename': 'OrgChart',

'exportFileextension': 'png',

'parentNodeSymbol': 'oci-leader',

'createNode': function(\$node, data) {

var secondMenuIcon = \$('<i>', {

'class': 'oci oci-info-circle second-menu-icon',

click: function() {

$(this).siblings('.second-menu').toggle();

}

});

var secondMenu = '<div class="second-menu"><img class="avatar" src="'+ data.picture + '"></div>';

\$node.append(secondMenuIcon).append(secondMenu);

}

});
});

</script>
EOT;

echo $html;


As I have indicated, there are many presentation possibilities and I hope that this separation of the steps and the example itself will make it easier for you to adjust this example to your needs.
For any questions or queries, please let me know in my email fernandohumanes@gmail.com
I leave the project on my portal, so you can reproduce it on your computers.
I also leave you the table I use and the directory "files" where the images are.