JSFiddle - React, Tailwind, and code Playground

by Shishir Morshed

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.4/d3.js"></script>
<button id="add-child" disabled="disabled">Add Child</button> 
<button id="remove" disabled="disabled">Remove</button>

CSS

* {
  margin: 0;
  padding: 0;
}

JavaScript

// ### DATA MODEL START

var data = {
  name: '1',
  attributes: [],
  children: [{
    name: '2',
    children: []
  }]
};

// ### DATA MODEL END

// Set the dimensions and margins of the diagram
var margin = {
    top: 20,
    right: 90,
    bottom: 30,
    left: 90
  },
  width = 960 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;

// append the svg object to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select("body").
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 + ")");

var i = 0,
  duration = 750,
  root;

// declares a tree layout and assigns the size
var treemap = d3.tree().size([height, width]);

// Assigns parent, children, height, depth
root = d3.hierarchy(data, function(d) {
  return d.children;
});
root.x0 = height / 2;
root.y0 = 0;

update(root);

var selected = null;

function update(source) {

  // Assigns the x and y position for the nodes
  var treeData = treemap(root);

  // Compute the new tree layout.
  var nodes = treeData.descendants(),
    links = treeData.descendants().slice(1);

  // Normalize for fixed-depth.
  nodes.forEach(function(d) {
    d.y = d.depth * 180
  });

  // ### LINKS

  // Update the links...
  var link = svg.selectAll('line.link').
  data(links, function(d) {
    return d.id;
  });

  // Enter any new links at the parent's previous position.
  var linkEnter = link.enter().
  append('line').
  attr("class", "link").
  attr("stroke-width", 2).
  attr("stroke", 'black').
  attr('x1', function(d) {
    return source.y0;
  }).
  attr('y1', function(d) {
    return source.x0;
  }).
  attr('x2', function(d) {
    return source.y0;
  }).
  attr('y2', function(d) {
    return source.x0;
  });

  var linkUpdate = linkEnter.merge(link);

  linkUpdate.transition().
 ...