diff --git a/VERSION.properties b/VERSION.properties index c2ecf84..30b0b99 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.138 +client.version=1.2.139 server.version=1.2.127 diff --git a/shine-UI/Dev_Docs/features/interactive-network-graph.md b/shine-UI/Dev_Docs/features/interactive-network-graph.md index 686fd10..972a472 100644 --- a/shine-UI/Dev_Docs/features/interactive-network-graph.md +++ b/shine-UI/Dev_Docs/features/interactive-network-graph.md @@ -91,6 +91,5 @@ ## Ограничения / на будущее - Многоуровневая глубина (друзья друзей мельче, 3-й уровень — точки), кластеры, «общие связи» упираются в API (отдаёт только прямые связи) — требуют доработки сервера. -- `lerpX/lerpY` в движке больше не используются для отрисовки — кандидат на чистку. - Превью в простое троттлит `requestAnimationFrame` (физика не идёт между вызовами) — для замеров прокачивать кадры; в активном табе всё работает на 60 FPS. diff --git a/shine-UI/js/pages/network/force-graph.js b/shine-UI/js/pages/network/force-graph.js index 3adf2d5..7d3dc05 100644 --- a/shine-UI/js/pages/network/force-graph.js +++ b/shine-UI/js/pages/network/force-graph.js @@ -31,7 +31,6 @@ const FRICTION_BOOST = 0.94; // «гелевая» вязкость в пер const BOOST_FRAMES = 42; // длительность затухающего boost'а вязкости (~700мс @60fps) const SLEEP_V = 0.03; // порог суммарной |vx|+|vy| для жёсткой заморозки графа const INTRO_FACTOR = 0.22; // стартовый радиус пера (доля от целевого) — узлы «вылетают» из центра -const EDGE_LERP = 0.25; // догон концов линии за узлом за кадр (эффект натянутой резинки) const PAN_FRICTION = 0.93; // трение инерционного скролла карты const TWEEN_MS = 560; // длительность анимации центрирования (фильтр/фолбэк) const BLOOM_MS = 900; // длительность разлёта узлов из центра (физика выключена → ноль тряски) @@ -59,30 +58,6 @@ function easeOutCubic(t) { return 1 - x * x * x; } -// Решатель кубической кривой Безье (CSS cubic-bezier): прогресс x → значение y. -function cubicBezier(x1, y1, x2, y2) { - const cx = 3 * x1; - const bx = 3 * (x2 - x1) - cx; - const ax = 1 - cx - bx; - const cy = 3 * y1; - const by = 3 * (y2 - y1) - cy; - const ay = 1 - cy - by; - const sampleX = (t) => ((ax * t + bx) * t + cx) * t; - const sampleY = (t) => ((ay * t + by) * t + cy) * t; - const dX = (t) => (3 * ax * t + 2 * bx) * t + cx; - return (x) => { - let t = x; - for (let i = 0; i < 6; i += 1) { - const d = dX(t); - if (Math.abs(d) < 1e-6) break; - t -= (sampleX(t) - x) / d; - } - return sampleY(Math.max(0, Math.min(1, t))); - }; -} -// Премиальная «вязкая» кривая для разлёта узлов (быстрый старт → очень мягкая посадка). -const EASE_BLOOM = cubicBezier(0.16, 1, 0.3, 1); - function relationColor(relationType) { return RELATION_COLORS[relationType] || RELATION_COLORS.contact; } @@ -233,8 +208,6 @@ export function createForceGraph({ stage, model, onCenterTap, onNodeTap, onNodeL ty, x: tx * INTRO_FACTOR, y: ty * INTRO_FACTOR, - lerpX: tx * INTRO_FACTOR, - lerpY: ty * INTRO_FACTOR, vx: 0, vy: 0, scale, @@ -517,14 +490,6 @@ export function createForceGraph({ stage, model, onCenterTap, onNodeTap, onNodeL return totalV; } - // Концы линий догоняют узлы с запаздыванием (эффект резинки): lerp-позиция тянется за реальной. - function advanceLerp() { - for (const n of nodes) { - n.lerpX += (n.x - n.lerpX) * EDGE_LERP; - n.lerpY += (n.y - n.lerpY) * EDGE_LERP; - } - } - // Плавное приближение масштаба/прозрачности к целям + рост линии («прорастание»). function advanceVisual() { for (const n of nodes) { @@ -613,7 +578,6 @@ export function createForceGraph({ stage, model, onCenterTap, onNodeTap, onNodeL const ao = a.opacity ?? 1; const bo = b.opacity ?? 1; n.opacity = ao + (bo - ao) * t; - n.lerpX = n.x; n.lerpY = n.y; if (b.grow) n.edgeGrow = raw; // линия «вытекает» по прогрессу своего узла } const camT = ease(Math.min(1, elapsed / dur)); @@ -693,15 +657,13 @@ export function createForceGraph({ stage, model, onCenterTap, onNodeTap, onNodeL } // Жёсткая заморозка: гасим скорости, округляем координаты до целых пикселей, - // подтягиваем lerp и НЕ перезапускаем цикл — граф замирает намертво (без «треска»). + // НЕ перезапускаем цикл — граф замирает намертво (без «треска»). function freezeGraph() { for (const n of nodes) { n.vx = 0; n.vy = 0; n.x = Math.round(n.x); n.y = Math.round(n.y); - n.lerpX = n.x; - n.lerpY = n.y; n.scale = n.targetScale; n.opacity = n.targetOpacity; } @@ -748,11 +710,9 @@ export function createForceGraph({ stage, model, onCenterTap, onNodeTap, onNodeL advanceVisual(); // bloom/смена роли вне твина — через целевые scale/opacity } - advanceLerp(); renderAll(); - const lerpSettling = nodes.some((n) => Math.abs(n.x - n.lerpX) + Math.abs(n.y - n.lerpY) > 0.5); - if (tween || dragging || panActive || boost > 0 || totalV > SLEEP_V || lerpSettling || visualSettling()) { + if (tween || dragging || panActive || boost > 0 || totalV > SLEEP_V || visualSettling()) { schedule(); } else { freezeGraph(); // система успокоилась — замираем @@ -910,7 +870,6 @@ export function createForceGraph({ stage, model, onCenterTap, onNodeTap, onNodeL const r = dot.getBoundingClientRect(); n.x = (r.left + r.width / 2) - sr.left - centerX - camX; n.y = (r.top + r.height / 2) - sr.top - centerY - camY; - n.lerpX = n.x; n.lerpY = n.y; // живая прозрачность из CSS-перехода — чтобы лучи гасли/проявлялись вместе с аватаркой const o = parseFloat(getComputedStyle(n.el).opacity); if (Number.isFinite(o)) n.opacity = o; @@ -926,7 +885,7 @@ export function createForceGraph({ stage, model, onCenterTap, onNodeTap, onNodeL for (const n of nodes) { n.el.style.transition = ''; const fo = (typeof n.bfo === 'number') ? n.bfo : 1; // финальная прозрачность (0 — скрыт фильтром) - n.x = n.bfx; n.y = n.bfy; n.lerpX = n.x; n.lerpY = n.y; + n.x = n.bfx; n.y = n.bfy; n.scale = n.bfs; n.targetScale = n.bfs; n.opacity = fo; n.targetOpacity = fo; n.vx = 0; n.vy = 0; n.edgeGrow = 1; } @@ -1001,7 +960,7 @@ export function createForceGraph({ stage, model, onCenterTap, onNodeTap, onNodeL // финал запоминаем для покоя; стартовое состояние держим в n.x/n.y (для первой отрисовки лучей) node.bfx = finalX; node.bfy = finalY; node.bfs = finalScale; node.bfo = 1; - node.x = fx; node.y = fy; node.lerpX = fx; node.lerpY = fy; + node.x = fx; node.y = fy; node.scale = finalScale; node.opacity = 1; node.targetScale = finalScale; node.targetOpacity = 1; node.hidden = false; // НОВЫЙ узел (разлетается из центра) — помечаем для эффекта прорастания линии (edgeGrow=0);