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

@@ -435,9 +435,11 @@ function _graphCtx() { return _graphCanvas().getContext('2d'); }
function _graphResizeCanvas() {
const canvas = _graphCanvas();
if (!canvas) return;
const w = canvas.parentElement.clientWidth - 24;
canvas.width = Math.max(320, w);
canvas.height = Math.max(560, Math.min(980, (window.innerHeight || 900) - 250));
const availableW = Math.max(320, canvas.parentElement.clientWidth - 24);
const availableH = Math.max(360, (window.innerHeight || 900) - 250);
const size = Math.max(320, Math.min(availableW, availableH, 920));
canvas.width = size;
canvas.height = size;
}
function _graphResetData() {
@@ -494,10 +496,10 @@ function _graphSourceCenter(source) {
}
const i = graphState.sourceIndex.get(key);
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 {
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') {
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};
}
if (n.kind === 'host') {
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};
}
@@ -523,11 +525,11 @@ function _graphPlaceNode(n) {
graphState.sourceCounts.set(source, local);
const center = _graphSourceCenter(source);
const angle = local * 2.399963 + _graphHashUnit(n.id) * 0.7;
const radius = 18 + Math.sqrt(local) * 9 + _graphHashUnit(n.id + ':r') * 38;
const squash = 0.72 + _graphHashUnit(source) * 0.46;
const radius = 18 + Math.sqrt(local) * 7.5 + _graphHashUnit(n.id + ':r') * 28;
const squash = 0.94 + (_graphHashUnit(source) - 0.5) * 0.16;
return {
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');
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.55, '#070b16');
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();
const loaded = graphState.totalEngrams ? ` | engrams=${graphState.loadedEngrams}/${graphState.totalEngrams}` : '';
hint.textContent = `nodes=${graphState.nodes.length} edges=${graphState.edges.length}${loaded}` + (term ? ` | match=${matches}` : '');
@@ -1272,19 +1289,23 @@ function resetGraphView() {
function fitGraphView(opts = {}) {
const canvas = _graphCanvas();
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) {
minX = Math.min(minX, n.x); minY = Math.min(minY, n.y);
maxX = Math.max(maxX, n.x); maxY = Math.max(maxY, n.y);
sumX += n.x;
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 zx = (canvas.width - pad) / w;
const zy = (canvas.height - pad) / h;
graphState.zoom = Math.max(0.04, Math.min(2.5, Math.min(zx, zy)));
graphState.panX = canvas.width / 2 - ((minX + maxX) / 2) * graphState.zoom;
graphState.panY = canvas.height / 2 - ((minY + maxY) / 2) * graphState.zoom;
graphState.zoom = Math.max(0.04, Math.min(2.5, (Math.min(canvas.width, canvas.height) - pad) / (radius * 2)));
graphState.panX = canvas.width / 2 - centerX * graphState.zoom;
graphState.panY = canvas.height / 2 - centerY * graphState.zoom;
if (!opts.silent) _graphDraw();
}