JSFiddle - React, Tailwind, and code Playground

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SVG Editor</title>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
</head>
<body>
    <h1>SVG Editor</h1>
    <button id="saveBtn">Save SVG</button>
    <button id="rotateBtn" class="hidden">Rotate Selected Sofa</button>
    <br><br>
    <svg id="svgCanvas">
	<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Создано Microsoft Visio, экспорт SVG Итерация 2 - изменил svg руками, сохранил его как visio.svg Страница-1 -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
		xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="8.26772in" height="11.6929in"
		viewBox="0 0 595.276 841.889" xml:space="preserve" color-interpolation-filters="sRGB" class="st23">
	<v:documentProperties v:langID="1049">
		<v:userDefs>
			<v:ud v:nameU="VisAecDocument" v:val="VT0(1):26"/>
			<v:ud v:nameU="VisAecVersion" v:val="VT0(15):26"/>
			<v:ud v:nameU="Ifc__CustomPropsLevel" v:val="VT0(0):26"/>
			<v:ud v:nameU="msvNoAutoConnect" v:val="VT0(1):26"/>
		</v:userDefs>
	</v:documentProperties>

	<style type="text/css">
	<![CDATA[
		.st1 {fill:#789440;stroke:#923931;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.25}
		.st2 {fill:#789440;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.749999}
		.st3 {fill:#789440}
		.st4 {stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
		.st5 {fill:#b95f3a;stroke:#000000;stroke-linecap:butt;stroke-width:0.75}
		.st6 {fill:#310e00;stroke:none;stroke-linecap:butt;stroke-width:0.75}
		.st7 {fill:#157224;stroke:none;stroke-linecap:butt;stroke-width:0.75}
		.st8...

CSS

body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        svg {
            border: 1px solid #ccc;
            width: 100%;
            height: 100vh;
        }
        .draggable-group {
            cursor: move;
        }
        .dragging {
            stroke: red;
            stroke-width: 2px;
        }
        .selected {
            stroke: blue;
            stroke-width: 2px;
        }
        .hidden {
            display: none;
        }
        .normalTable, .sofaTable {
            transform-origin: center center;
        }

JavaScript

class Merger {
            constructor(svgCanvas, proximityThreshold = 50) {
                this.svgCanvas = svgCanvas;
                this.groups = [];
                this.proximityThreshold = proximityThreshold;
                this.init();
            }

            init() {
                this.updateDraggableGroups();
                this.addSelectableFeature();
            }

            updateDraggableGroups() {
                const groups = d3.select(this.svgCanvas).selectAll('.draggable-group').call(d3.drag()
                    .on('start', (event, d) => this.startDrag(event, d))
                    .on('drag', (event, d) => this.drag(event, d))
                    .on('end', (event, d) => this.endDrag(event, d)));
                
                this.groups = groups.nodes();
                console.log('Updated groups:', this.groups);
            }           

            getRotationFromTransform(element) {
                const transform = d3.select(element).attr('transform');
                const rotateMatch = transform ? transform.match(/rotate\(([^)]+)\)/) : null;
                return rotateMatch ? parseFloat(rotateMatch[1]) : 0;
            }


            addSelectableFeature() {
                d3.select(this.svgCanvas).selectAll('.sofa').on('click', (event, d) => {
                    d3.selectAll('.selected').classed('selected', false);
                    d3.select(event.target.closest('.sofa')).classed('selected', true);
                    document.getElementById('rotateBtn').classList.remove('hidden');
                });
            }

            rotateSelectedSofa() {
                const selectedElement = d3.select('.selected');
                if (!selectedElement.empty()) {
                    const transform = selectedElement.attr("transform");
                    const rotateMatch = transform ? transform.match(/rotate\(([^)]+)\)/) : null;
                    const currentRotation = rotateMatch ?...