JSFiddle - React, Tailwind, and code Playground

by Lazaro Contreras

HTML

<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
        <polyline class="a" points="0,0"
            style="fill:none;stroke:#63ff7d;stroke-width:4" />
        <polyline class="b" points="0,0"
            style="fill:none;stroke:#6bb5ff;stroke-width:4" />
        <polyline class="c" points="0,0"
            style="fill:none;stroke:#ff637d;stroke-width:4" />
        <circle class="c i" cx="0" cy="0" r="4" fill="#ff637d" />
        <circle class="c o" cx="0" cy="0" r="4" fill="#ff637d" />
        <circle class="b i" cx="0" cy="0" r="4" fill="#ff637d" />
        <circle class="b o" cx="0" cy="0" r="4" fill="#6bb5ff" />
        <circle class="a i" cx="0" cy="0" r="4" fill="#6bb5ff" />
        <circle class="a o" cx="0" cy="0" r="4" fill="#6bb5ff" />
    </svg>

    <node class="c" node-out="b" node-in="na"></node>
    <node class="b" node-out="a" node-in="c"></node>
    <node class="a" node-out="na" node-in="b"></node>

CSS

.static {
    cursor: not-allowed;
  }
.draggable {
    cursor: move;
  }
  svg{
    position:absolute;
    width: 100%;
    height: 100%;
  }
  node{
    position:absolute;
    background: white;
    width: 100px;
    height: 100px;
    border: solid gray 1px;
    border-radius: 5px;
  }

JavaScript

window.onload = function () {

    var nodes;

    var nodes = document.querySelectorAll('node');

    var element, mouseY, mouseX;

    nodes.forEach(function (e) {
        e.addEventListener('mousedown', startMove);
        e.addEventListener('onchange', nodeUpdate);
        nodeUpdate(e);
    });

    window.addEventListener('mouseup', function () {
        window.removeEventListener('mousemove', move);
    });

    function startMove(e) {
        element = e.currentTarget;
        mouseY = e.pageY - element.offsetTop;
        mouseX = e.pageX - element.offsetLeft;
        window.addEventListener('mousemove', move);
    }
    function nodeUpdate(e) {
        element = e;
        if(!localStorage.getItem(element.className + 'x') && !localStorage.getItem(element.className + 'y')){
            localStorage.setItem(element.className + 'x',0);
            localStorage.setItem(element.className + 'y',0);
        }
        element.style.top = localStorage.getItem(element.className + 'y') + "px";
        element.style.left = localStorage.getItem(element.className + 'x') + "px";
        mouseY = element.offsetTop;
        mouseX = element.offsetLeft;
        move(e);
    }

    function move(e) {
        element.style.position = 'absolute';
        element.style.top = e.pageY - mouseY + 'px';
        element.style.left = e.pageX - mouseX + 'px';
        localStorage.setItem(element.className + 'x',element.offsetLeft);
        localStorage.setItem(element.className + 'y',element.offsetTop);
        var no = document.querySelector("node." + element.getAttribute("node-out"));
        if(no) no.setAttribute("node-in", element.className);
        var ni = document.querySelector("node." + element.getAttribute("node-in"));
        if (ni)
            var lo = document.querySelector("polyline." + ni.className);
        if (no)
            var li = document.querySelector("polyline." + element.className);
        var ci = document.querySelector("circle." + element.className +...