Even though there are a number of steps, only one part of the code needs to be altered to visualize an instance of my BST. This is the the call to d3.hierarchy.

root = d3.hierarchy(treeData, function(d){
return d.children;
});

The function d3.hierarchy(data, children) takes in two parameters.

An object that represents the root node of a dataset

A children accessor function

d3.hierarchy starts with the root and invokes the accessor function for each node. The accessor function must return an array of children or null if there are no children. The hierarchy function gives each node the properties: data, depth, height, parent, children, and value.

hierarchy returns the root node.

The first part of the hierarchy call that needs to be changed is the data. Instead of passing the original hardcoded data set, pass a BST instance’s root node.

This code will run, but the visualization will only have a single node, the root. To solve this issue change the children accessor function so that it puts d.left and d.right into the children array for each node or datum.

While this approach correctly assigns children to each node, it does not maintain whether a child is a left or right child. If a node has no siblings it will be displayed directly beneath its parent.

Instead of explicitly changing the coordinates of these nodes, I create a dummy node for each node without a sibling. If an only child is a right child, I insert the dummy node before it. If the only child is a left child, I insert the dummy node after it. This ensures that the children are correctly positioned in relation to their parent.

This works great, but the dummy nodes need to be hidden. To hide the dummy nodes I add the class “hidden” to all nodes with a NAN value. Depending on value’s type in your BST, you may need to change the isNAN condition.

Notes:

After completing my initial BST implementation, I consulted Algolist for some ideas on how to clean up my code. I particularly like how they have an insertion method in the BST and Node class. This allows for insertion to be called directly on a node or tree instance. This was cleaner than my method of passing the value to be inserted and a root node to insert().