Creating Employee Hierarchy Data Model using D3 (Part-3)

Yudhajit Adhikary
7 min readDec 20, 2020

--

Photo by Lukas Blazek on Unsplash

So it’s the continuity of my second article.

1st Article:

2nd Article:

So We will be continuing our discussion on D3 . We will be designing employee hierarchy data model using D3. So we will be create the employee tree of our awesome company Company Hierarchy :) . So there will be an add button if we click on that a modal will popup . The modal will be containing three fields employee name , report to which employee and department of the employee. And now by these data we are creating a beautiful employee hierarchy tree design. So let’s start coding , We will start with index.html.

So index.html will be having the entire Dom structure of our application. First we are defining the head of our application , having materialize icon cdn link, materialize css cdn link and our local css file style.css. Our application will be having header having our company name and subtitle of our application, The Number One Company :) .Now we will be having a button having add icon , we are using material icon for icon. So we want to open a modal on click of the button. In order to implement that we are wrapping our icon with anchor tag with href= “#modal”. So we are sending that href as id of our modal. We will be using the materialize css property to implement that , we will be looking into it when we will be going through our javascript file. So our modal will be having a header Add a New Employee , and a form having input fields for Employee Name , Reporting Employee and department and a button to submit the form. Lastly there will be our canvas div where we will be injecting our employee hierarchy tree. Then we are adding config of our firestore, some little changes we have added , like added <script src=”https://www.gstatic.com/firebasejs/8.1.1/firebase-firestore.js"></script>

as we are using the firestore for data storage and

const db=firebase.firestore();

created a firestore instance for data storage. db will be representing our database. And lastly we are adding cdn link for materialized css, d3 and our javascript files index.js and graph.js. Now we will be looking index.js file.

So index.js will be implementing the form submission and that modal functionality which we mentioned in our index.html.

const modal = document.querySelector(‘.modal’);

M.Modal.init(modal);

We are creating the reference of our modal .We are using materialize css , for the implementation. M is the instance of materialize css ,M is a object having Modal which is function to perform modal functionality. We are initiating the function with the reference of our div having id = ‘modal’. By passing that id as href in our button we are asking to initiate the modal function to show the div having ‘modal’ as a modal whenever user clicks on the add icon.

Now we are taking the reference of form, input field having id name, input field having id parent, and input field having id department. We are adding submit eventListener to form , on submit event we want to store data to our employee collection so we are adding name , parent and department to our employee collection .

var instance = M.Modal.getInstance(modal);

instance.close();

form.reset();

Then we want to close our modal while form is submitted for that we are taking the instance of our modal and calling close () function on it. Lastly we are resetting our form input field. Now we be looking into the graph.js file.

So our graph.js file will be handling the formation of data hierarchy tree. dims is storing the height and width of the data tree.

const svg = d3.select(‘.canvas’)

.append(‘svg’)

.attr(‘width’, dims.width + 100)

.attr(‘height’, dims.height + 100);

We are injecting svg into the div having classname ‘canvas’ and passing attribute width and height into it.

const graph = svg.append(‘g’)

.attr(‘transform’, ‘translate(50, 50)’);

we are creating a group called graph and adding transform.

const stratify = d3.stratify()

.id(d => d.name)

.parentId(d => d.parent);

startify() is a function which transform our data into a format which will be suitable for creating data tree, the stratify variable will be having each of the record with parent and child object and also the x and y position of each node that we will be displaying into our tree.

const tree = d3.tree()

.size([dims.width, dims.height]);

Now we are creating our tree .d3.tree() is used to create tree and passed a size parameter having the width and height we want to pass to our component.

const colour=d3.scaleOrdinal([‘#f4511e’,’#e91e63',’#e53935',’#9c27b0'])

we want to show different color of nodes for different departments, for that we are creating the ordinal scale. We will be having four department , so we have added four colors into our ordinal Scale.

Inside update function we will be creating our data hierarchy tree

graph.selectAll(‘.node’).remove();

graph.selectAll(‘.link’).remove();

So whenever data updates the position of each node should change right , so we will first remove all the existing node and link components once the data gets updated.

colour.domain(data.map(item=>item.department));

then we will update the domain of the ordinal scale , as we discussed earlier we will be having different color of node for different department.

const rootNode = stratify(data);

const treeData = tree(rootNode).descendants();

Now we are updating the root Node data , rootNode will be having the stratified value and treeData will be having value which is required for the creation of the data nodes. descendant() function will take the rootNode value and will store nodes properties inside an array.

const nodes = graph.selectAll(‘.node’)

.data(treeData);

then we selecting all the node element into our graph group and passing our treeData as data into it.

const link = graph.selectAll(‘.link’)

.data(tree(rootNode).links());

Now we are selecting all the link and creating the link means the lines which will connect each of our nodes. We are passing tree(rootNode).links() as data. links() function actually will convert our rootNode data and will create an array of object which will contain object having source and destination node, which be used for create the connecting links.

link.enter()

.append(‘path’)

.transition().duration(300)

.attr(‘class’, ‘link’)

.attr(‘fill’, ‘none’)

.attr(‘stroke’, ‘#aaa’)

.attr(‘stroke-width’, 2)

.attr(‘d’, d3.linkVertical()

.x(d => d.x)

.y(d => d.y )

);

we are defining the entry point of our link , we are appending path , adding few styling parameters, passing d as d3.linkVertical, since we want our linking lines should be vertical. Then we are passing data.x and data. y as the x and y parameter of our link.

const enterNodes = nodes.enter()

.append(‘g’)

.attr(‘class’, ‘node’)

.attr(‘transform’, d => `translate(${d.x}, ${d.y})`);

Now we are defining the entry point of our nodes, adding classname of ‘node and transform .

enterNodes.append(‘rect’)

.attr(‘fill’,d=>colour(d.data.department))

.attr(‘stroke’, ‘#555’)

.attr(‘stroke-width’, 2)

.attr(‘width’, d => d.data.name.length * 20)

.attr(‘height’, 50)

.attr(‘transform’,d=>{

var x=d.data.name.length*10

return `translate(${-x},-25)`

});

So we want our nodes to be rectangle for that we are appending rect into our enterNodes group. Then we are filling color to the node body according to our defined ordinal scale, some css parameters.

enterNodes.append(‘text’)

.attr(‘text-anchor’, ‘middle’)

.attr(‘fill’, ‘white’)

.text(d => d.data.name);

Now we are appending text into our enterNodes , aligning the text to middle, filling text color as white and passing data.name as the text .

Now let’s define the function which is responsible for adding, updating and removing data. So our collection name is employees, whenever a document inside a collection gets changed .onSnapshot() function gets triggered , which return a response . Response. docChanges() contains the array of changed document , now we are immutably storing the each changed document by de-structuring in doc variable. change.type contains whether the change is added , modified or removed type and according to that by applying switch case we are handling the update functionality of our database. In case of ‘added’ we are pushing the new doc, ‘modified’ we are we are finding the index of existing document which matches with our changed document id and updating the data of that particular index and for ‘removed’ we are filter out the document which matches with the removed document id. and Lastly we are calling the update function for updating our database.

It’s just a simple implementation of creating data tree using D3.There are several and more complex visualization we can create using D3.We can actually go through the official documentation of D3 . It’s really nice and helpful for those who want to explore more about D3.I will be attaching my github code link as the reference of this article and the official documentation link of D3. Please keep in mind if you want to run the code please replace the config part of the firestore with your own credentials if you are not much comfortable with firestore please check official documentation of Firestore (https://firebase.google.com/docs/web/setup)

CODE:

DOCUMENTS:

HAPPY CODING :)

--

--

Yudhajit Adhikary

Web developer by profession,Photographer,Blog Writer,Singer,Pianist,Seeker of Solution