Two Way Tree - D3

A Tree that starts in the middle, having parents and children.

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-hierarchy/1.1.5/d3-hierarchy.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<h1 align="center">2-Way Tree</h1>

<div id="categoryHierarchy"></div>

CSS

body {
  overflow: hidden;
  margin: 0;
  font-size: 14px;
  font-family: "Helvetica Neue", Helvetica;
}

#chart,
#header,
#footer {
  position: absolute;
  top: 0;
}

#header,
#footer {
  z-index: 1;
  display: block;
  font-size: 36px;
  font-weight: 300;
  text-shadow: 0 1px 0 #fff;
}

#header.inverted,
#footer.inverted {
  color: #fff;
  text-shadow: 0 1px 4px #000;
}

#header {
  top: 80px;
  left: 140px;
  width: 1000px;
}

#footer {
  top: 680px;
  right: 140px;
  text-align: right;
}

svg {
  background: black;
}

rect {
  fill: none;
  pointer-events: all;
}

pre {
  font-size: 18px;
}

line {
  stroke: #000;
  stroke-width: 1.5px;
}

.string,
.regexp {
  color: #f39;
}

.keyword {
  color: #00c;
}

.comment {
  color: #777;
  font-style: oblique;
}

.number {
  color: #369;
}

.class,
.special {
  color: #1181B8;
}

a:link,
a:visited {
  color: #000;
  text-decoration: none;
}

a:hover {
  color: #666;
}

.hint {
  position: absolute;
  right: 0;
  width: 1280px;
  font-size: 12px;
  color: #999;
}

.node circle {
  cursor: pointer;
  fill: #fff;
  stroke: steelblue;
  stroke-width: 1px;
}

.node text {
  font-size: 11px;
}

path.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 1px;
}

JavaScript

// From https://bl.ocks.org/kanesee/5d6c48bffd4ea31201fb
const CollapsibleTree = function(elt) {

  let m = [20, 120, 20, 120],
    w = 800 - m[1] - m[3],
    h = 500 - m[0] - m[2],
    i = 0,
    combinedNodes, hiddenNodes = [],
    combinedLinks, hiddenLinks = []

  const diagonal = d3
    .linkVertical()
    .x(d => d.x)
    .y(d => d.y)

  const vis = d3
    .select(elt)
    .append("svg:svg")
    .attr("width", w + m[1] + m[3])
    .attr("height", h + m[0] + m[2])
    .append("svg:g")


  //specify what to do when zoom event listener is triggered 
  const zoom_actions = () => {
    vis.attr("transform", d3.event.transform)
  }

  //create zoom handler 
  const zoom_handler = d3.zoom()
    .on("zoom", zoom_actions)

  //add zoom behaviour to the svg element 
  //same as svg.call(zoom_handler); 
  zoom_handler(vis)

  const that = {
    init: function(url) {
      const that = this;
      root = {
        "name": "Airlines",
        "parents": [{
            "name": "Aviation",
            "isparent": true
          },
          {
            "name": "Transparent_companies",
            "isparent": true,
            //This pisses me off, gotta get rid of it, should be called "parents"
            //look into stratify()
            "children": [{
              "name": "test parent depth",
              "isparent": true
            }]
          },
          {
            "name": "Transport_operators",
            "isparent": true
          }
        ],
        "children": [{
            "name": "Airline_alliances",
            "isparent": false
          },
          {
            "name": "Airlines_by_continent",
            "isparent": false
          },
          {
            "name": "Airlines_by_type",
            "isparent": false,
            "children": [{
              "name": "Test depth",
              "isparent": false
            }]
          },
          {
            "name": "Defunct_airlines",
            "isparent": false
          }
        ]
  ...