From 08693affc38faf70b446e32ec5df1e07b07150c1 Mon Sep 17 00:00:00 2001 From: shats Date: Tue, 17 Feb 2026 17:19:43 +0700 Subject: [PATCH] refactor(NetworkMapUnifi): enhance curve point calculations for improved edge rendering and layout aesthetics --- frontend/src/NetworkMapUnifi.jsx | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/frontend/src/NetworkMapUnifi.jsx b/frontend/src/NetworkMapUnifi.jsx index 0b4b1f4..95177e9 100644 --- a/frontend/src/NetworkMapUnifi.jsx +++ b/frontend/src/NetworkMapUnifi.jsx @@ -182,8 +182,10 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa }).filter((e) => e.p1 && e.p2); }, [connections, positions, pingMap]); - // Вычисляем старт/финиш и контрольную точку так, чтобы рёбра выходили - // с «боков» карточек и красиво изгибались (как в UniFi). + // Вычисляем старт/финиш и контрольную точку так, чтобы: + // - рёбра выходили из карточек строго под 90° (горизонтально/вертикально), + // - рядом с узлами был короткий прямой участок, + // - далее шла плавная дуга (как в UniFi). const computeCurvePoints = useCallback((e) => { const { p1, p2 } = e; const dx = p2.x - p1.x; @@ -210,30 +212,40 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa ey = p2.y - sign * (NODE_HEIGHT / 2); } - const mx = (sx + ex) / 2; - const my = (sy + ey) / 2; const ddx = ex - sx; const ddy = ey - sy; const len = Math.hypot(ddx, ddy) || 1; + const ux = ddx / len; + const uy = ddy / len; + const stub = 22; // длина прямого участка перед узлами + + // Точки начала/конца дуги (после прямых участков) + const csx = sx + ux * stub; + const csy = sy + uy * stub; + const cex = ex - ux * stub; + const cey = ey - uy * stub; + + const mx = (csx + cex) / 2; + const my = (csy + cey) / 2; const baseOffset = 40; const perpX = (-ddy / len) * baseOffset; const perpY = (ddx / len) * baseOffset; const cpx = mx + perpX; const cpy = my + perpY; - return { sx, sy, ex, ey, cpx, cpy }; + return { sx, sy, ex, ey, csx, csy, cex, cey, cpx, cpy }; }, []); const pathD = useCallback((e) => { - const { sx, sy, ex, ey, cpx, cpy } = computeCurvePoints(e); - return `M ${sx} ${sy} Q ${cpx} ${cpy} ${ex} ${ey}`; + const { sx, sy, ex, ey, csx, csy, cex, cey, cpx, cpy } = computeCurvePoints(e); + return `M ${sx} ${sy} L ${csx} ${csy} Q ${cpx} ${cpy} ${cex} ${cey} L ${ex} ${ey}`; }, [computeCurvePoints]); const labelPoint = useCallback((e) => { - const { sx, sy, ex, ey, cpx, cpy } = computeCurvePoints(e); + const { csx, csy, cex, cey, cpx, cpy } = computeCurvePoints(e); const t = 0.5; - const lx = (1 - t) * (1 - t) * sx + 2 * (1 - t) * t * cpx + t * t * ex; - const ly = (1 - t) * (1 - t) * sy + 2 * (1 - t) * t * cpy + t * t * ey; + const lx = (1 - t) * (1 - t) * csx + 2 * (1 - t) * t * cpx + t * t * cex; + const ly = (1 - t) * (1 - t) * csy + 2 * (1 - t) * t * cpy + t * t * cey; return { x: lx, y: ly }; }, [computeCurvePoints]);