<!DOCTYPE html> <html> <head> <style> svg { width: 600px; height: auto; } </style> </head> <body> <h1>Welcome, {{username}}</h1> <svg id="svg" width="400" height="400"> <circle class="c" id="0" cx="12.5%" cy="12.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="1" cx="37.5%" cy="12.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="2" cx="62.5%" cy="12.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="3" cx="87.5%" cy="12.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="4" cx="12.5%" cy="37.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="5" cx="37.5%" cy="37.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="6" cx="62.5%" cy="37.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="7" cx="87.5%" cy="37.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="8" cx="12.5%" cy="62.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="9" cx="37.5%" cy="62.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="a" cx="62.5%" cy="62.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="b" cx="87.5%" cy="62.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="c" cx="12.5%" cy="87.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="d" cx="37.5%" cy="87.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="e" cx="62.5%" cy="87.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> <circle class="c" id="f" cx="87.5%" cy="87.5%" r="10%" stroke="grey" stroke-width="2%" fill="white" /> </svg> <script> HTMLCollection.prototype.forEach = Array.prototype.forEach; HTMLCollection.prototype.slice = Array.prototype.slice; mouseDown = false; currentStroke = null; strokeId = 0; doneMap = {}; enteredKey = ''; svg = document.getElementById('svg'); drawLine = (fromX, fromY, toX, toY) => { var line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); var id = 'l-' + (strokeId++); var idAttr = document.createAttribute('id'); var classAttr = document.createAttribute('class'); var x1attr = document.createAttribute('x1'); var y1attr = document.createAttribute('y1'); var x2attr = document.createAttribute('x2'); var y2attr = document.createAttribute('y2'); var styleAttr = document.createAttribute('style'); idAttr.value = id; classAttr.value = 'l'; x1attr.value = fromX; y1attr.value = fromY; x2attr.value = toX; y2attr.value = toY; styleAttr.value = 'stroke: grey; stroke-width: 5%; stroke-linecap: round'; line.setAttributeNode(idAttr); line.setAttributeNode(classAttr); line.setAttributeNode(x1attr); line.setAttributeNode(y1attr); line.setAttributeNode(x2attr); line.setAttributeNode(y2attr); line.setAttributeNode(styleAttr); svg.appendChild(line); return id; }; svg.onmousedown = (ev) => { var svgrect = svg.getBoundingClientRect(); var minId = ''; var minDist = Infinity; var minx = 0; var miny = 0; doneMap = {}; document.getElementsByClassName('c').forEach((circle) => { var x = parseFloat(circle.getAttribute('cx'))/100.0 * svgrect.width; var y = parseFloat(circle.getAttribute('cy'))/100.0 * svgrect.height; var dist = Math.pow(ev.offsetX - x, 2) + Math.pow(ev.offsetY - y, 2); if (dist < minDist) { minDist = dist; minId = circle.id; minx = x; miny = y; } }); var minNode = svg.getElementById(minId); currentStroke = drawLine(minx, miny, ev.offsetX, ev.offsetY); doneMap[minId] = 1; enteredKey += minId; }; svg.onmouseup = (ev) => { currentStroke = null; doneMap = {}; console.log(enteredKey); enteredKey = ''; svg.getElementsByClassName('l').slice().reverse().forEach((line) => { svg.removeChild(line); }); }; svg.onmousemove = (ev) => { if (currentStroke != null) { var svgrect = svg.getBoundingClientRect(); var minId = ''; var minDist = Infinity; var minx = 0; var miny = 0; document.getElementsByClassName('c').forEach((circle) => { var x = parseFloat(circle.getAttribute('cx'))/100.0 * svgrect.width; var y = parseFloat(circle.getAttribute('cy'))/100.0 * svgrect.height; var dist = Math.pow(ev.offsetX - x, 2) + Math.pow(ev.offsetY - y, 2); if (dist < minDist) { minDist = dist; minId = circle.id; minx = x; miny = y; } }); if (minDist < 2000 && !(minId in doneMap)) { var line = svg.getElementById(currentStroke); line.setAttribute('x2', minx); line.setAttribute('y2', miny); currentStroke = drawLine(minx, miny, ev.offsetX, ev.offsetY); doneMap[minId] = 1; enteredKey += minId; } var line = svg.getElementById(currentStroke); line.setAttribute('x2', ev.offsetX); line.setAttribute('y2', ev.offsetY); } }; </script> </body> </html>