diff --git a/frontend/src/GraphView.jsx b/frontend/src/GraphView.jsx
index 5aef783..ac3e8fb 100644
--- a/frontend/src/GraphView.jsx
+++ b/frontend/src/GraphView.jsx
@@ -1,6 +1,11 @@
-import React from 'react';
+import React, { useState, useRef } from 'react';
function GraphView({ servers, connections }) {
+ const [nodePositions, setNodePositions] = useState({});
+ const [draggedNode, setDraggedNode] = useState(null);
+ const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
+ const svgRef = useRef(null);
+
if (servers.length === 0) {
return (
@@ -12,21 +17,99 @@ function GraphView({ servers, connections }) {
);
}
- // Простое позиционирование узлов в сетке
- const getNodePosition = (index, total) => {
+ // Инициализация позиций узлов при первом рендере
+ const getInitialNodePosition = (index, total) => {
+ if (nodePositions[servers[index]?.ip]) {
+ return nodePositions[servers[index].ip];
+ }
+
const cols = Math.ceil(Math.sqrt(total));
const row = Math.floor(index / cols);
const col = index % cols;
- const spacing = 150;
+ const spacing = 180;
return {
- x: 100 + col * spacing,
- y: 100 + row * spacing
+ x: 120 + col * spacing,
+ y: 120 + row * spacing
};
};
+ // Обработчик начала перетаскивания
+ const handleMouseDown = (e, serverIp) => {
+ const svg = svgRef.current;
+ const pt = svg.createSVGPoint();
+ pt.x = e.clientX;
+ pt.y = e.clientY;
+ const svgP = pt.matrixTransform(svg.getScreenCTM().inverse());
+
+ const currentPos = nodePositions[serverIp] || getInitialNodePosition(
+ servers.findIndex(s => s.ip === serverIp),
+ servers.length
+ );
+
+ setDragOffset({
+ x: svgP.x - currentPos.x,
+ y: svgP.y - currentPos.y
+ });
+ setDraggedNode(serverIp);
+ };
+
+ // Обработчик перетаскивания
+ const handleMouseMove = (e) => {
+ if (!draggedNode) return;
+
+ const svg = svgRef.current;
+ const pt = svg.createSVGPoint();
+ pt.x = e.clientX;
+ pt.y = e.clientY;
+ const svgP = pt.matrixTransform(svg.getScreenCTM().inverse());
+
+ setNodePositions(prev => ({
+ ...prev,
+ [draggedNode]: {
+ x: svgP.x - dragOffset.x,
+ y: svgP.y - dragOffset.y
+ }
+ }));
+ };
+
+ // Обработчик окончания перетаскивания
+ const handleMouseUp = () => {
+ setDraggedNode(null);
+ };
+
+ // Получение позиции узла
+ const getNodePosition = (serverIp) => {
+ return nodePositions[serverIp] || getInitialNodePosition(
+ servers.findIndex(s => s.ip === serverIp),
+ servers.length
+ );
+ };
+
+ // Цвета для разных стран
+ const getCountryColor = (country) => {
+ const colors = {
+ 'RU': '#dc2626', // красный
+ 'US': '#2563eb', // синий
+ 'DE': '#059669', // зеленый
+ 'SE': '#7c3aed', // фиолетовый
+ 'NL': '#ea580c', // оранжевый
+ 'SG': '#0891b2' // голубой
+ };
+ return colors[country] || '#6b7280';
+ };
+
return (
-