Связи: чистка мёртвого кода в движке (lerp, неиспользуемые easing)
- Убран механизм lerpX/lerpY: координаты для отрисовки берутся из n.x/n.y, lerp нигде не читался кроме условия заморозки (lerpSettling). Удалены поля, advanceLerp(), EDGE_LERP и lerpSettling — граф засыпает чуть раньше (без визуальных изменений; проверено: frozen=true). - Удалены неиспользуемые cubicBezier() и EASE_BLOOM (easing теперь делает CSS); easeOutCubic оставлен (нужен в stepTween для фолбэк-центрирования). - Документация фичи актуализирована (убрана заметка про lerp как кандидата на чистку). - Бамп client.version → 1.2.139. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dc96033cb1
commit
e6e96c4b0d
@ -1,2 +1,2 @@
|
||||
client.version=1.2.138
|
||||
client.version=1.2.139
|
||||
server.version=1.2.127
|
||||
|
||||
@ -91,6 +91,5 @@
|
||||
## Ограничения / на будущее
|
||||
- Многоуровневая глубина (друзья друзей мельче, 3-й уровень — точки), кластеры, «общие связи»
|
||||
упираются в API (отдаёт только прямые связи) — требуют доработки сервера.
|
||||
- `lerpX/lerpY` в движке больше не используются для отрисовки — кандидат на чистку.
|
||||
- Превью в простое троттлит `requestAnimationFrame` (физика не идёт между вызовами) — для замеров
|
||||
прокачивать кадры; в активном табе всё работает на 60 FPS.
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user