JSFiddle - React, Tailwind, and code Playground

HTML

<div id="wrap">
    <div id="inner-canvas">
        <div class="block me">me</div>
    </div>
</div>

<form action="" method="POST">
    <select id="add">
        <option value="parents">add parents</option>
        <option value="father">add father</option>
        <option value="mother">add mother</option>
        <option value="child">add child</option>
    </select>
    <input type="submit" value="go">
</form>

CSS

body { background: darkgray; }

.block {
    width: 100px;
    background:#fff;
    height: 90px;
    border: 1px solid #ddd;
    text-align: center;
    line-height: 90px;
    position: absolute;
}

#inner-canvas {
    width:5000px;
    height: 5000px;
    position: absolute;
}

#wrap {
    width: 100%;
    height: 100%;
    position: absolute;
    overflow: hidden;
}

.active { border: 3px solid #000; }

form { position: absolute; top:0; left: 0; }

JavaScript

(function() {
    
    $(function() {
    
        var genCounter = 0,
            blockWidth = 100,
            blockHeight = 90,
            currentNode = null,
            canvas = $('#inner-canvas'),
            RELATIONSHIPS = {
                'PARTNER' : 1
            }

        $.fn.center = function() {
            var width = canvas.width(), height = canvas.height();

            var offset = $(this).offset();

            $(this).css({
                top: ((width-blockWidth)/2),
                left: ( (height-blockHeight)/2 )
            })
            
            return this;
        }
        
        $.fn.scrollIntoView = function() {
            $('.block').removeClass('active')
            $(this).addClass('active')
            
        	currentNode = this;
            
            $('#wrap').animate({
                scrollTop: $(this).offset().top - $(canvas).offset().top - $('#wrap').height() / 2 + 60,
                scrollLeft: $(this).offset().left - $(canvas).offset().left - $('#wrap').width() / 2 + 60
            }, 500)
            
            return this;
        }
        
        $(canvas).on('click', '.block', function() {
            $(this).scrollIntoView();
        });

        $('.block.me').center().scrollIntoView();
        
        $('form').on('submit', function(e) { 
            e.preventDefault();
            
            addNode( $('#add').val() );
        });
        
        // get the current nodes offset to use as a base for the next node
        function getCurrentNodeOffset() {
            var nodeOffset = $(currentNode).offset(), parentOffset = $(canvas).offset();
            var offset = {
                top: nodeOffset.top - parentOffset.top,
                left: nodeOffset.left - parentOffset.left
            };
            return offset;
        }
        
        function generateBlock( caption, offset ) {
            var div = $('<div/>').addClass('block').css({
                top:offset.top,
           ...