Make second brain graph viewport circular

This commit is contained in:
2026-06-05 09:25:13 +02:00
parent f6edf7cdf2
commit 5ebb87db41
2 changed files with 43 additions and 22 deletions

View File

@@ -168,7 +168,7 @@ body {
margin: 8px auto 0; margin: 8px auto 0;
background:#02040a; background:#02040a;
border:1px solid #172033; border:1px solid #172033;
border-radius: 8px; border-radius: 50%;
box-shadow: 0 0 28px rgba(34,211,238,0.08), inset 0 0 42px rgba(124,58,237,0.08); box-shadow: 0 0 28px rgba(34,211,238,0.08), inset 0 0 42px rgba(124,58,237,0.08);
touch-action: none; touch-action: none;
} }

View File

@@ -435,9 +435,11 @@ function _graphCtx() { return _graphCanvas().getContext('2d'); }
function _graphResizeCanvas() { function _graphResizeCanvas() {
const canvas = _graphCanvas(); const canvas = _graphCanvas();
if (!canvas) return; if (!canvas) return;
const w = canvas.parentElement.clientWidth - 24; const availableW = Math.max(320, canvas.parentElement.clientWidth - 24);
canvas.width = Math.max(320, w); const availableH = Math.max(360, (window.innerHeight || 900) - 250);
canvas.height = Math.max(560, Math.min(980, (window.innerHeight || 900) - 250)); const size = Math.max(320, Math.min(availableW, availableH, 920));
canvas.width = size;
canvas.height = size;
} }
function _graphResetData() { function _graphResetData() {
@@ -494,10 +496,10 @@ function _graphSourceCenter(source) {
} }
const i = graphState.sourceIndex.get(key); const i = graphState.sourceIndex.get(key);
const angle = i * 2.399963; const angle = i * 2.399963;
const ring = i < 1 ? 0 : 260 + Math.sqrt(i) * 95; const ring = i < 1 ? 0 : 210 + Math.sqrt(i) * 80;
return { return {
x: Math.cos(angle) * ring, x: Math.cos(angle) * ring,
y: Math.sin(angle) * ring * 0.82, y: Math.sin(angle) * ring,
}; };
} }
@@ -507,12 +509,12 @@ function _graphPlaceNode(n) {
} }
if (n.kind === 'tag') { if (n.kind === 'tag') {
const angle = _graphHashUnit(n.id) * Math.PI * 2; const angle = _graphHashUnit(n.id) * Math.PI * 2;
const ring = 520 + (_graphHashUnit(n.id + ':r') * 420); const ring = 470 + (_graphHashUnit(n.id + ':r') * 260);
return {x: Math.cos(angle) * ring, y: Math.sin(angle) * ring}; return {x: Math.cos(angle) * ring, y: Math.sin(angle) * ring};
} }
if (n.kind === 'host') { if (n.kind === 'host') {
const angle = _graphHashUnit(n.id) * Math.PI * 2; const angle = _graphHashUnit(n.id) * Math.PI * 2;
const ring = 760 + (_graphHashUnit(n.id + ':r') * 260); const ring = 640 + (_graphHashUnit(n.id + ':r') * 220);
return {x: Math.cos(angle) * ring, y: Math.sin(angle) * ring}; return {x: Math.cos(angle) * ring, y: Math.sin(angle) * ring};
} }
@@ -523,11 +525,11 @@ function _graphPlaceNode(n) {
graphState.sourceCounts.set(source, local); graphState.sourceCounts.set(source, local);
const center = _graphSourceCenter(source); const center = _graphSourceCenter(source);
const angle = local * 2.399963 + _graphHashUnit(n.id) * 0.7; const angle = local * 2.399963 + _graphHashUnit(n.id) * 0.7;
const radius = 18 + Math.sqrt(local) * 9 + _graphHashUnit(n.id + ':r') * 38; const radius = 18 + Math.sqrt(local) * 7.5 + _graphHashUnit(n.id + ':r') * 28;
const squash = 0.72 + _graphHashUnit(source) * 0.46; const squash = 0.94 + (_graphHashUnit(source) - 0.5) * 0.16;
return { return {
x: center.x + Math.cos(angle) * radius * squash, x: center.x + Math.cos(angle) * radius * squash,
y: center.y + Math.sin(angle) * radius * (1.55 - squash), y: center.y + Math.sin(angle) * radius / squash,
}; };
} }
@@ -1141,7 +1143,14 @@ function _graphDraw() {
const hint = document.getElementById('graphHint'); const hint = document.getElementById('graphHint');
ctx.clearRect(0,0,canvas.width,canvas.height); ctx.clearRect(0,0,canvas.width,canvas.height);
const bg = ctx.createRadialGradient(canvas.width * 0.52, canvas.height * 0.48, 10, canvas.width * 0.5, canvas.height * 0.5, Math.max(canvas.width, canvas.height) * 0.72); const cx = canvas.width / 2;
const cy = canvas.height / 2;
const viewR = Math.min(canvas.width, canvas.height) / 2 - 3;
ctx.save();
ctx.beginPath();
ctx.arc(cx, cy, viewR, 0, Math.PI * 2);
ctx.clip();
const bg = ctx.createRadialGradient(canvas.width * 0.52, canvas.height * 0.48, 10, cx, cy, viewR);
bg.addColorStop(0, '#121a2b'); bg.addColorStop(0, '#121a2b');
bg.addColorStop(0.55, '#070b16'); bg.addColorStop(0.55, '#070b16');
bg.addColorStop(1, '#02040a'); bg.addColorStop(1, '#02040a');
@@ -1235,6 +1244,14 @@ function _graphDraw() {
} }
} }
ctx.restore();
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.arc(cx, cy, viewR, 0, Math.PI * 2);
ctx.strokeStyle = 'rgba(34, 211, 238, 0.18)';
ctx.lineWidth = 1.2;
ctx.stroke();
ctx.restore(); ctx.restore();
const loaded = graphState.totalEngrams ? ` | engrams=${graphState.loadedEngrams}/${graphState.totalEngrams}` : ''; const loaded = graphState.totalEngrams ? ` | engrams=${graphState.loadedEngrams}/${graphState.totalEngrams}` : '';
hint.textContent = `nodes=${graphState.nodes.length} edges=${graphState.edges.length}${loaded}` + (term ? ` | match=${matches}` : ''); hint.textContent = `nodes=${graphState.nodes.length} edges=${graphState.edges.length}${loaded}` + (term ? ` | match=${matches}` : '');
@@ -1272,19 +1289,23 @@ function resetGraphView() {
function fitGraphView(opts = {}) { function fitGraphView(opts = {}) {
const canvas = _graphCanvas(); const canvas = _graphCanvas();
if (!graphState.sim.length) return; if (!graphState.sim.length) return;
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; let sumX = 0, sumY = 0;
for (const n of graphState.sim) { for (const n of graphState.sim) {
minX = Math.min(minX, n.x); minY = Math.min(minY, n.y); sumX += n.x;
maxX = Math.max(maxX, n.x); maxY = Math.max(maxY, n.y); sumY += n.y;
}
const centerX = sumX / graphState.sim.length;
const centerY = sumY / graphState.sim.length;
let radius = 1;
for (const n of graphState.sim) {
const dx = n.x - centerX;
const dy = n.y - centerY;
radius = Math.max(radius, Math.sqrt(dx * dx + dy * dy));
} }
const w = Math.max(1, maxX - minX);
const h = Math.max(1, maxY - minY);
const pad = graphState.sim.length > 20000 ? 96 : 54; const pad = graphState.sim.length > 20000 ? 96 : 54;
const zx = (canvas.width - pad) / w; graphState.zoom = Math.max(0.04, Math.min(2.5, (Math.min(canvas.width, canvas.height) - pad) / (radius * 2)));
const zy = (canvas.height - pad) / h; graphState.panX = canvas.width / 2 - centerX * graphState.zoom;
graphState.zoom = Math.max(0.04, Math.min(2.5, Math.min(zx, zy))); graphState.panY = canvas.height / 2 - centerY * graphState.zoom;
graphState.panX = canvas.width / 2 - ((minX + maxX) / 2) * graphState.zoom;
graphState.panY = canvas.height / 2 - ((minY + maxY) / 2) * graphState.zoom;
if (!opts.silent) _graphDraw(); if (!opts.silent) _graphDraw();
} }