Drupal Technical
[SOLVED] How to draw a collapsible tree diagram using D3JS in Drupal 7 with Javascript?
In one of my project, I want to display a hierarchical structure of an array by using D3 JS, which should be collapsible. Lets checkout how we can implement, D3 JS in Drupal 7 with collapsible concept. Do you want the implementation like this, get a quote and make use of our expertise.
First I download the D3 JS from http://d3js.org/
and save it in [my-js] folder (sites/all/libraries/my-js) as 'd3.js'. So I use the following code for this tree diagram :
- First I have created 2 menus by implementing hook_menu(), first one for the page details and the other for ajax request:
// Menu1. $items['data_hierarchy'] = array( 'title' => 'Page title', 'description' => 'Handling the structure', 'page callback' => array('data_hierarchy'), 'file' => 'includes/data_hierarchy.inc', 'access arguments' => array('PERMISSION DETAILS'), ); // Menu2. $items['ajax/data_hierarchy'] = array( 'title' => '', 'description' => 'Handling ajax request of structure', 'page callback' => array('data_hierarchy_ajax'), 'file' => 'includes/data_hierarchy.inc', 'access arguments' => array('PERMISSION DETAILS'), );
- I have implemented hook_theme() for its TPL page,
// theme for structure. $theme['data_hierarchy'] = array( 'variables' => array('vars' => NULL), 'template' => 'templates/data_hierarchy', );
-
Then I have created its pagecallbacks,
/** * Pagecallback for structure. * @return $output. */ function data_hierarchy() { $output_data = array( '#theme' => 'data_hierarchy', '#vars' => '', '#attached' => array( 'js' => array( drupal_add_js(libraries_get_path('LIBRARY NAME') . '/--PATH--/d3.js', 'external'), drupal_get_path('module', 'MODULE NAME') . '/js/data_hierarchy.js', ), 'css' => array( drupal_get_path('module', 'MODULE NAME') . '/css/data_hierarchy.css', ), ) ); return $output_data; } /** * Pagecallback for handling ajax request of structure. * @return json_output. */ function data_hierarchy_ajax() { $sample_array_data = array( array("name" => "Management", "parent" => "null", "children" => array( array( "name" => "Dept/Unit1", "parent" => "Management", "children" => array( array( "name" => "Group", "parent" => "Dept/Unit1", "children" => array( array( "name" => "Group1", "parent" => "Group", "children" => array( array( "name" => "Employee1", "parent" => "Group1", ), array( "name" => "Employee2", "parent" => "Group1", ), array( "name" => "Employee..n", "parent" => "Group1", ), ) ), array( "name" => "Group2", "parent" => "Group", ), array( "name" => "Group..n", "parent" => "Group", ), ) ), array( "name" => "Team", "parent" => "Dept/Unit1", "children" => array( array( "name" => "Team1", "parent" => "Team", "children" => array( array( "name" => "Employee1", "parent" => "Team1", ), array( "name" => "Employee2", "parent" => "Team1", ), array( "name" => "Employee..n", "parent" => "Team1", ), ) ), array( "name" => "Team2", "parent" => "Team", ), array( "name" => "Team..n", "parent" => "Team", ), ) ) ) ), array( "name" => "Dept/Unit2", "parent" => "Management" ), array( "name" => "Dept/Unit..n", "parent" => "Management" ) ) ) ); drupal_json_output($sample_array_data); }
- I have stored the following css for the structure in 'MODULE_NAME/css/data_hierarchy.css',
.node { cursor: pointer; } .node circle { fill: #fff; stroke: steelblue; stroke-width: 3px; } .node text { font: 12px sans-serif; } .link { fill: none; stroke: #ccc; stroke-width: 2px; } #data-hierarchy { background-color: #FFFFFF; overflow: auto; } #data-hierarchy h4{ padding-left: 1%; }
- I have stored the following Javascript code in the file 'MODULE_NAME/js/data_hierarchy.js' for reading the JSON data and drawing the tree like structure:
(function ($) { Drupal.behaviors.my_data_hierarchy = { attach:function(context, settings) { var base_url = window.location.origin; var treeData = []; var margin = {top: 20, right: 120, bottom: 20, left: 120}, width = 960 - margin.right - margin.left, height = 500 - margin.top - margin.bottom; var i = 0, duration = 750, root; var tree = d3.layout.tree() .size([height, width]); var diagonal = d3.svg.diagonal() .projection(function(d) { return [d.y, d.x]; }); var svg = d3.select("#data-hierarchy").append("svg") .attr("width", width + margin.right + margin.left) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // Load json data for generating the structured display. jQuery.getJSON(base_url+'/ajax/data-hierarchy/', function(data) { if (data != '') { // Generate the tree diagram. treeData = data; root = treeData[0]; root.x0 = height / 2; root.y0 = 0; root.children.forEach(collapse); update(root); d3.select('#data-hierarchy').style("height", "500px"); } else { $('#data-hierarchy').html("<h4>No hierarchy details found.</h4>"); } }); function collapse(d) { if (d.children) { d._children = d.children; d._children.forEach(collapse); d.children = null; } } function update(source) { // Compute the new tree layout. var nodes = tree.nodes(root).reverse(), links = tree.links(nodes); // Normalize for fixed-depth. nodes.forEach(function(d) { d.y = d.depth * 180; }); // Update the nodes… var node = svg.selectAll("g.node") .data(nodes, function(d) { return d.id || (d.id = ++i); }); // Enter any new nodes at the parent's previous position. var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) .on("click", click); nodeEnter.append("circle") .attr("r", 1e-6) .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); nodeEnter.append("text") .attr("x", function(d) { return d.children || d._children ? -13 : 13; }) .attr("dy", ".35em") .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) .text(function(d) { return d.name; }) .style("fill-opacity", 1e-6); // Transition nodes to their new position. var nodeUpdate = node.transition() .duration(duration) .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); nodeUpdate.select("circle") .attr("r", 10) .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); nodeUpdate.select("text") .style("fill-opacity", 1); // Transition exiting nodes to the parent's new position. var nodeExit = node.exit().transition() .duration(duration) .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) .remove(); nodeExit.select("circle") .attr("r", 1e-6); nodeExit.select("text") .style("fill-opacity", 1e-6); // Update the links… var link = svg.selectAll("path.link") .data(links, function(d) { return d.target.id; }); // Enter any new links at the parent's previous position. link.enter().insert("path", "g") .attr("class", "link") .attr("d", function(d) { var o = {x: source.x0, y: source.y0}; return diagonal({source: o, target: o}); }); // Transition links to their new position. link.transition() .duration(duration) .attr("d", diagonal); // Transition exiting nodes to the parent's new position. link.exit().transition() .duration(duration) .attr("d", function(d) { var o = {x: source.x, y: source.y}; return diagonal({source: o, target: o}); }) .remove(); // Stash the old positions for transition. nodes.forEach(function(d) { d.x0 = d.x; d.y0 = d.y; }); } // Toggle children on click. function click(d) { if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } update(d); } } } })(jQuery);
- Then I have created the TPL page with the code :
<div id="data-hierarchy"></div>
Do you need any technical support, feel free to contact us. Happy coding :)