JSFiddle - React, Tailwind, and code Playground

by eprouver

HTML

<div id="display"></div>

CSS

.node {
    fill: #007fff;
    stroke: #000;
    cursor: crosshair;
}
.node_selected {
    fill: #ff7f0e;
    stroke: #ff7f0e;
}
.drag_line {
    stroke: #999;
    stroke-width: 5;
    pointer-events: none;
}
.drag_line_hidden {
    stroke: #999;
    stroke-width: 0;
    pointer-events: none;
}
.link {
    stroke: #999;
    stroke-width: 5;
    cursor: crosshair;
}
.link_selected {
    stroke: #ff7f0e;
}

JavaScript

var width = 300,
    height = 500,
    fill = d3.scale.category20();

// mouse event vars
var selected_node = null,
    selected_link = null,
    mousedown_link = null,
    mousedown_node = null,
    mouseup_node = null;

d3.selectAll('svg').remove();
// init svg
var outer = d3.select("#display")
    .append("svg:svg")
    .attr("width", width)
    .attr("height", height)
    .attr("pointer-events", "all");

var vis = outer.append('svg:g')
    .on("mousemove", mousemove)
    .on("mouseup", mouseup);

vis.append('svg:rect')
    .attr('width', width)
    .attr('height', height)
    .attr('fill', 'white');

// init force layout
var force = d3.layout.force()
    .size([width, height])
    .nodes([{}, {}, {}]) // initialize with a single node
.linkDistance(100)
    .charge(-500)
    .on("tick", tick);


// line displayed when dragging new nodes
var drag_line = vis.append("line")
    .attr("class", "drag_line")
    .attr("x1", 0)
    .attr("y1", 0)
    .attr("x2", 0)
    .attr("y2", 0);

// get layout properties
var nodes = force.nodes(),
    links = force.links(),
    node = vis.selectAll(".node"),
    link = vis.selectAll(".link");

// add keyboard callback
d3.select(window)
    .on("keydown", keydown);

redraw();

function mousemove() {
    if (!mousedown_node) return;

    // update drag line
    drag_line.attr("x1", mousedown_node.x)
        .attr("y1", mousedown_node.y)
        .attr("x2", d3.mouse(this)[0])
        .attr("y2", d3.mouse(this)[1]);

}

function mouseup() {
    if (mousedown_node) {
        // hide drag line
        drag_line.attr("class", "drag_line_hidden")

        redraw();
    }
    // clear mouse event vars
    resetMouseVars();
}

function resetMouseVars() {
    mousedown_node = null;
    mouseup_node = null;
    mousedown_link = null;
}

function tick() {
    link.attr("x1", function (d) {
        return d.source.x;
    })
        .attr("y1", function (d) {
        return d.source.y;
    })
        .attr("x2", function (d) {
        return...