JSFiddle - React, Tailwind, and code Playground

by Serhii Matrunchyk

HTML

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>D3 Drawing</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.1/d3.min.js" integrity="sha512-COTaPOlz12cG4fSfcBsxZsjauBAyldqp+8FQUM/dZHm+ts/jR4AFoJhCqxy8K10Jrf3pojfsbq7fAPTb1XaVkg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
  <h3>Draw a polygon :D</h3>

CSS

svg {
    border: 1px solid;
}

path {
    fill: lightsalmon;
    stroke: salmon;
    stroke-width: 5px;
}

circle.handler {
  fill: transparent;
}

svg:not(.is-drawing) circle.handler:hover {
  fill: #f2cb63;
  cursor: move;
}

circle.indicator {
  pointer-events: none;
  fill: #0254ff;
}

circle.indicator.initial-vertex:hover {
  fill: red;
}

line.edge {
  pointer-events: none;
}

polygon:hover {
  opacity: 0.8;
  stroke: black;
  stroke-width: 1.2px;
  cursor: move;
}

polyline {
  pointer-events: none;
}

JavaScript

let dragging = false;
let drawing = false;
let snapping = false;
let startPoint = [];

/* const rect = document.body;
rect.height -= 15;
const margin = { top: 25, right: 0, bottom: 55, left: 65 };
const width = rect.width - margin.left - margin.right;
const height = rect.height - margin.top - margin.bottom; */

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

let points = [];
let group = null;
let idx = 0;

const dragger = d3.drag()
  .on('drag', handleDrag)
  .on('end', function(d) {
    dragging = false;
  });

document.body.addEventListener('keydown', function(event) {
  if (!group) return;

  d3.select(group).node().remove();
  group = null;
  points = [];
  drawing = false;
  dragging = false;
});

svg.on('mouseup', function(event) {
  console.log('asdasd');

  if (dragging) return;
  

  if (!group) {
    group = svg.append('g')
      .attr('class', 'polygon-group')
      .attr('polygon-index', idx++);
  }  

  drawing = true;
  startPoint = [event.x - 10, event.y - 60];
  svg.classed('is-drawing', drawing);
  
  const initialNode = group.select('.initial-vertex');

  if (d3.select(event.target).classed('initial-vertex')) {
    // Close polygon
    group.append('polygon')
      .attr('points', points)
      .style('fill', '#d9d9d9')
      .lower();
      
    group.selectAll('polyline').remove();
    group.selectAll('line').remove();

    drawing = false;
    points = [];
    group = null;
    svg.classed('is-drawing', drawing);
    
    return;
  }

  points.push(startPoint);
  group.select('polyline').remove();

  const polyline = group
    .append('polyline')
    .attr('points', points)
    .style('fill', 'none')
    .attr('stroke', '#000');

  group.selectAll('circle.indicator')
    .data(points)
    .enter()
    .append('circle')
    .attr('class', 'indicator')
    .attr('cx', d => d[0])
    .attr('cy', d => d[1])
    .attr('r', 4)
    .attr('stroke', '#000')
    .classed('initial-vertex', (d, index) =>...