SHA256
Связи: финальный вид сияющих связей — плазма (поле+трубка+ядро, screen-blend) + цвет связи у обычных
Промежуточные итерации линий схлопнуты в один коммит. Убран мёртвый фильтр fg-plasma-turb. Лаборатория (/network-view/lab) и автотесты сохранены. Версия 1.2.158. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -109,8 +109,13 @@ function ensureShineFilter() {
|
||||
svg.setAttribute('width', '0');
|
||||
svg.setAttribute('height', '0');
|
||||
svg.style.position = 'absolute';
|
||||
svg.innerHTML = '<defs><filter id="fg-shine-glow" x="-120%" y="-120%" width="340%" height="340%" '
|
||||
+ 'color-interpolation-filters="sRGB"><feGaussianBlur stdDeviation="3.4"/></filter></defs>';
|
||||
// + SVG-фильтры размытия для плазменных линий (feGaussianBlur надёжнее CSS-filter на <path> в WebView).
|
||||
// Широкий регион фильтра (userSpaceOnUse-подобный запас в %), чтобы размытие не срезалось по bbox пути.
|
||||
svg.innerHTML = '<defs>'
|
||||
+ '<filter id="fg-shine-glow" x="-120%" y="-120%" width="340%" height="340%" color-interpolation-filters="sRGB"><feGaussianBlur stdDeviation="3.4"/></filter>'
|
||||
+ '<filter id="fg-plasma-blur6" x="-100%" y="-200%" width="300%" height="500%" color-interpolation-filters="sRGB"><feGaussianBlur stdDeviation="6"/></filter>'
|
||||
+ '<filter id="fg-plasma-blur2" x="-60%" y="-120%" width="220%" height="340%" color-interpolation-filters="sRGB"><feGaussianBlur stdDeviation="2"/></filter>'
|
||||
+ '</defs>';
|
||||
document.body.appendChild(svg);
|
||||
}
|
||||
|
||||
@@ -773,27 +778,33 @@ export function createForceGraph({ stage, model, onCenterTap, onNodeTap, onNodeL
|
||||
// 2-й уровень: матовая паутинка, проявляется по мере раскрытия родителя (локальный bloom)
|
||||
if (pe > 0.02) parts.push(`<path d="${d}" fill="none" stroke="rgba(175, 200, 235, 0.9)" stroke-width="0.8" stroke-linecap="round" opacity="${(0.14 * pe * sp).toFixed(2)}" />`);
|
||||
} else if (shine || n.track || onPath) {
|
||||
// glow (размытый, приглушённый) + core (тонкий, чёткий). Используется для сияющих, «трека
|
||||
// прохождения» (n.track) И нити-крошки пути погружения (onPath) — путь назад к Ивану горит ярко.
|
||||
const cOpVal = nodeOpacity * sp;
|
||||
const gOp = (0.4 * cOpVal).toFixed(2);
|
||||
const cOpAttr = cOpVal < 0.995 ? ` opacity="${cOpVal.toFixed(2)}"` : '';
|
||||
parts.push(`<path class="fg-edge-glow" d="${d}"${dashAttr} opacity="${gOp}" />`);
|
||||
parts.push(`<path class="fg-edge-core" d="${d}"${dashAttr}${cOpAttr} />`);
|
||||
// СИЯЮЩАЯ связь — плазменный композитинг: ОДИН центральный S-путь (cubic) + ТРИ наложенных слоя
|
||||
// с ОДИНАКОВЫМ d (объём из толщины+blur, не из геометрии). Слои: широкое поле / трубка / ядро.
|
||||
const pnx = -uy;
|
||||
const pny = ux; // перпендикуляр к хорде
|
||||
const amp = Math.min(13, 5 + segLen0 * 0.05); // амплитуда S — спокойная изящная волна (∝ длине)
|
||||
const bowX = desX - mx;
|
||||
const bowY = desY - my; // вектор изящной дуги + пан-стретч — сохраняем
|
||||
// единственная S-кривая: контрольная точка на 1/3 смещена +amp, на 2/3 — −amp (плавная волна)
|
||||
const c1x = x1 + (x2 - x1) / 3 + bowX + pnx * amp; const c1y = y1 + (y2 - y1) / 3 + bowY + pny * amp;
|
||||
const c2x = x1 + 2 * (x2 - x1) / 3 + bowX - pnx * amp; const c2y = y1 + 2 * (y2 - y1) / 3 + bowY - pny * amp;
|
||||
const dS = `M${x1.toFixed(1)} ${y1.toFixed(1)} C${c1x.toFixed(1)} ${c1y.toFixed(1)} ${c2x.toFixed(1)} ${c2y.toFixed(1)} ${x2.toFixed(1)} ${y2.toFixed(1)}`;
|
||||
const base = nodeOpacity * sp; // затемнение от spotlight/глубины
|
||||
// 3 слоя на ОДНОМ пути dS. Видимый НЕОН: яркое ядро + чёткий голубой ореол (поле+трубка в режиме
|
||||
// screen — свет складывается аддитивно с фоном). Прозрачности подняты, чтобы не было «белого каната».
|
||||
parts.push(`<path class="fg-plasma-flare" d="${dS}"${dashAttr} opacity="${(0.42 * base).toFixed(3)}" />`);
|
||||
parts.push(`<path class="fg-plasma-tube" d="${dS}"${dashAttr} opacity="${(0.85 * base).toFixed(3)}" />`);
|
||||
parts.push(`<path class="fg-plasma-core" d="${dS}"${dashAttr} opacity="${(1 * base).toFixed(3)}" />`);
|
||||
} else {
|
||||
// обычная: тонкая дуга, градиент 0.42 (центр) → 0.07 (аватарка) — глубокий уход в прозрачность,
|
||||
// чтобы матовые связи не спорили с сияющими.
|
||||
const gid = `fg-grad-${gi}`;
|
||||
gi += 1;
|
||||
defs.push(
|
||||
`<linearGradient id="${gid}" gradientUnits="userSpaceOnUse" x1="${x1.toFixed(1)}" y1="${y1.toFixed(1)}" x2="${x2.toFixed(1)}" y2="${y2.toFixed(1)}">`
|
||||
+ `<stop offset="0" stop-color="${FOCUS_NEON}" stop-opacity="0.42"/>`
|
||||
+ `<stop offset="1" stop-color="${relationColor(n.relationType)}" stop-opacity="0.07"/></linearGradient>`
|
||||
);
|
||||
const sw = (1.0 + n.strength * 0.2).toFixed(2); // 1.0–1.2px
|
||||
// ОБЫЧНАЯ связь — мягкий светящийся жгут В ЦВЕТЕ СВЯЗИ (семья тёплый / друзья синий /
|
||||
// бизнес фиолет): тоньше и тише сияющих. Без SVG-blur (дёшево): широкая подложка + тонкое ядро.
|
||||
const col = relationColor(n.relationType);
|
||||
const opVal = nodeOpacity * sp;
|
||||
const op = opVal < 0.995 ? ` opacity="${opVal.toFixed(2)}"` : '';
|
||||
parts.push(`<path d="${d}" fill="none" stroke="url(#${gid})" stroke-width="${sw}" stroke-linecap="round"${op}${dashAttr} />`);
|
||||
const haloOp = (0.22 * opVal).toFixed(2);
|
||||
const coreOp = (0.7 * opVal).toFixed(2);
|
||||
const sw = (2.6 + n.strength * 1.4).toFixed(2); // мягкая подложка-«свечение» в цвете связи
|
||||
parts.push(`<path d="${d}" fill="none" stroke="${col}" stroke-width="${sw}" stroke-linecap="round" opacity="${haloOp}"${dashAttr} />`);
|
||||
parts.push(`<path d="${d}" fill="none" stroke="${col}" stroke-width="1.2" stroke-linecap="round" opacity="${coreOp}"${dashAttr} />`);
|
||||
}
|
||||
}
|
||||
edgesSvg.innerHTML = `<defs>${defs.join('')}</defs>${parts.join('')}`;
|
||||
|
||||
Reference in New Issue
Block a user