JSFiddle - React, Tailwind, and code Playground

by Chetan Hanumantha

HTML

<script src="http://d3js.org/d3.v3.min.js"></script>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css">

CSS

svg {
    background-color: #FFF;
    cursor: default;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    -o-user-select: none;
    user-select: none;
}
svg:not(.active):not(.ctrl) {
    cursor: crosshair;
}
path.link {
    fill: none;
    stroke: #000;
    stroke-width: 4px;
    cursor: default;
}
svg:not(.active):not(.ctrl) path.link {
    cursor: pointer;
}
path.link.selected {
    stroke-dasharray: 10, 2;
}
path.link.dragline {
    pointer-events: none;
}
path.link.hidden {
    stroke-width: 0;
}
circle.node {
    stroke-width: 1.5px;
    cursor: pointer;
}
circle.node.reflexive {
    stroke: #000 !important;
    stroke-width: 2.5px;
}
text {
    font: 12px sans-serif;
    pointer-events: none;
}
text.id {
    text-anchor: middle;
    font-weight: bold;
}
.svg-icon {
    font-size: 16px;
    color: white;
    text-anchor: middle;
    dominant-baseline: central;
}

JavaScript

// set up SVG for D3
var width = 300,
    height = 300,
    colors = d3.scale.category20c();

var svg = d3.select('body')
    .append('svg')
    .attr('width', width)
    .attr('height', height);

// set up initial nodes and links
//  - nodes are known by 'id', not by index in array.
//  - reflexive edges are indicated on the node (as a bold black circle).
//  - links are always source < target; edge directions are set by 'left' and 'right'.
var nodes = [{
    id: 0,
    reflexive: false
}, {
    id: 1,
    reflexive: true
}, {
    id: 2,
    reflexive: false
}],
    lastNodeId = 2,
    links = [{
        source: nodes[0],
        target: nodes[1],
        left: false,
        right: true
    }, {
        source: nodes[1],
        target: nodes[2],
        left: false,
        right: true
    }];

// init D3 force layout
var force = d3.layout.force()
    .nodes(nodes)
    .links(links)
    .size([width, height])
    .linkDistance(150)
    .charge(-500)
    .on('tick', tick);

// define arrow markers for graph links
svg.append('svg:defs').append('svg:marker')
    .attr('id', 'end-arrow')
    .attr('viewBox', '0 -5 10 10')
    .attr('refX', 6)
    .attr('markerWidth', 3)
    .attr('markerHeight', 3)
    .attr('orient', 'auto')
    .append('svg:path')
    .attr('d', 'M0,-5L10,0L0,5')
    .attr('fill', '#000');

svg.append('svg:defs').append('svg:marker')
    .attr('id', 'start-arrow')
    .attr('viewBox', '0 -5 10 10')
    .attr('refX', 4)
    .attr('markerWidth', 3)
    .attr('markerHeight', 3)
    .attr('orient', 'auto')
    .append('svg:path')
    .attr('d', 'M10,-5L0,0L10,5')
    .attr('fill', '#000');

// line displayed when dragging new nodes
var drag_line = svg.append('svg:path')
    .attr('class', 'link dragline hidden')
    .attr('d', 'M0,0L0,0');

// handles to link and node element groups
var path = svg.append('svg:g').selectAll('path'),
    circle = svg.append('svg:g').selectAll('g');

// mouse event vars
var selected_node = null,
    selected_link =...