@andespindola/brainlink 0.1.0-beta.66 → 0.1.0-beta.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -64,7 +64,8 @@ const state = {
|
|
|
64
64
|
filterWorker: null,
|
|
65
65
|
filterReady: false,
|
|
66
66
|
lastHoverHitAt: 0,
|
|
67
|
-
lastManualZoomAt: 0
|
|
67
|
+
lastManualZoomAt: 0,
|
|
68
|
+
lastZoomFocus: { x: 0, y: 0, at: 0 }
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
const byId = id => document.getElementById(id)
|
|
@@ -653,17 +654,11 @@ const selectLayeredNodesForScale = (sourceNodes, targetCount) => {
|
|
|
653
654
|
return merged.length > 0 ? merged : sourceNodes
|
|
654
655
|
}
|
|
655
656
|
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
return null
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
const rect = canvas.getBoundingClientRect()
|
|
662
|
-
const screenX = state.cursor.x - rect.left
|
|
663
|
-
const screenY = state.cursor.y - rect.top
|
|
657
|
+
const viewportCenterWorldPoint = () => {
|
|
658
|
+
const viewport = worldViewportBounds()
|
|
664
659
|
return {
|
|
665
|
-
x: (
|
|
666
|
-
y: (
|
|
660
|
+
x: (viewport.minX + viewport.maxX) / 2,
|
|
661
|
+
y: (viewport.minY + viewport.maxY) / 2
|
|
667
662
|
}
|
|
668
663
|
}
|
|
669
664
|
|
|
@@ -689,13 +684,49 @@ const mergeUniqueNodes = (leftNodes, rightNodes, limit) => {
|
|
|
689
684
|
return merged
|
|
690
685
|
}
|
|
691
686
|
|
|
687
|
+
const selectStableSampleNodes = (sourceNodes, limit) => {
|
|
688
|
+
if (sourceNodes.length <= limit) {
|
|
689
|
+
return sourceNodes
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const now = performance.now()
|
|
693
|
+
const recentZoomFocus =
|
|
694
|
+
now - state.lastZoomFocus.at <= 1500
|
|
695
|
+
? { x: state.lastZoomFocus.x, y: state.lastZoomFocus.y }
|
|
696
|
+
: null
|
|
697
|
+
const anchor = recentZoomFocus ?? viewportCenterWorldPoint()
|
|
698
|
+
const previousIds = new Set(state.renderNodes.map((node) => node.id))
|
|
699
|
+
|
|
700
|
+
return [...sourceNodes]
|
|
701
|
+
.sort((left, right) => {
|
|
702
|
+
const leftWasVisible = previousIds.has(left.id) ? 1 : 0
|
|
703
|
+
const rightWasVisible = previousIds.has(right.id) ? 1 : 0
|
|
704
|
+
if (leftWasVisible !== rightWasVisible) return rightWasVisible - leftWasVisible
|
|
705
|
+
|
|
706
|
+
const leftDistance = Math.hypot(left.x - anchor.x, left.y - anchor.y)
|
|
707
|
+
const rightDistance = Math.hypot(right.x - anchor.x, right.y - anchor.y)
|
|
708
|
+
if (leftDistance !== rightDistance) return leftDistance - rightDistance
|
|
709
|
+
|
|
710
|
+
const leftDegree = state.nodeDegrees.get(left.id) ?? 0
|
|
711
|
+
const rightDegree = state.nodeDegrees.get(right.id) ?? 0
|
|
712
|
+
if (leftDegree !== rightDegree) return rightDegree - leftDegree
|
|
713
|
+
|
|
714
|
+
return left.id.localeCompare(right.id)
|
|
715
|
+
})
|
|
716
|
+
.slice(0, limit)
|
|
717
|
+
}
|
|
718
|
+
|
|
692
719
|
const selectAccessBridgeNodes = (sourceNodes, limit) => {
|
|
693
720
|
if (limit <= 0 || sourceNodes.length === 0) {
|
|
694
721
|
return []
|
|
695
722
|
}
|
|
696
723
|
|
|
697
|
-
const
|
|
698
|
-
const
|
|
724
|
+
const now = performance.now()
|
|
725
|
+
const recentZoomFocus =
|
|
726
|
+
now - state.lastZoomFocus.at <= 1200
|
|
727
|
+
? { x: state.lastZoomFocus.x, y: state.lastZoomFocus.y }
|
|
728
|
+
: null
|
|
729
|
+
const anchor = recentZoomFocus ?? viewportCenterWorldPoint()
|
|
699
730
|
return [...sourceNodes]
|
|
700
731
|
.sort((left, right) => {
|
|
701
732
|
const leftDistance = Math.hypot(left.x - anchor.x, left.y - anchor.y)
|
|
@@ -1239,9 +1270,17 @@ const focusPrimaryHub = () => {
|
|
|
1239
1270
|
markRenderDirty()
|
|
1240
1271
|
}
|
|
1241
1272
|
|
|
1273
|
+
const layoutDensityScaleForNodeCount = (nodeCount) => {
|
|
1274
|
+
if (nodeCount > 50000) return 0.56
|
|
1275
|
+
if (nodeCount > 20000) return 0.64
|
|
1276
|
+
if (nodeCount > 6000) return 0.76
|
|
1277
|
+
return 1
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1242
1280
|
const createLayout = graph => {
|
|
1243
1281
|
const nodeRows = Array.isArray(graph.nodes) ? graph.nodes : []
|
|
1244
1282
|
const edgeRows = Array.isArray(graph.edges) ? graph.edges : []
|
|
1283
|
+
const densityScale = layoutDensityScaleForNodeCount(nodeRows.length)
|
|
1245
1284
|
const nodes = nodeRows.map(node => {
|
|
1246
1285
|
if (Array.isArray(node)) {
|
|
1247
1286
|
const [id, title, x, y, group, segment] = node
|
|
@@ -1252,8 +1291,8 @@ const createLayout = graph => {
|
|
|
1252
1291
|
tags: [],
|
|
1253
1292
|
group: typeof group === 'string' ? group : 'root',
|
|
1254
1293
|
segment: typeof segment === 'string' ? segment : 'root',
|
|
1255
|
-
x: Number.isFinite(x) ? x : 0,
|
|
1256
|
-
y: Number.isFinite(y) ? y : 0,
|
|
1294
|
+
x: Number.isFinite(x) ? x * densityScale : 0,
|
|
1295
|
+
y: Number.isFinite(y) ? y * densityScale : 0,
|
|
1257
1296
|
vx: 0,
|
|
1258
1297
|
vy: 0
|
|
1259
1298
|
}
|
|
@@ -1263,8 +1302,8 @@ const createLayout = graph => {
|
|
|
1263
1302
|
...node,
|
|
1264
1303
|
path: typeof node.path === 'string' ? node.path : '',
|
|
1265
1304
|
tags: Array.isArray(node.tags) ? node.tags : [],
|
|
1266
|
-
x: Number.isFinite(node.x) ? node.x : 0,
|
|
1267
|
-
y: Number.isFinite(node.y) ? node.y : 0,
|
|
1305
|
+
x: Number.isFinite(node.x) ? node.x * densityScale : 0,
|
|
1306
|
+
y: Number.isFinite(node.y) ? node.y * densityScale : 0,
|
|
1268
1307
|
vx: Number.isFinite(node.vx) ? node.vx : 0,
|
|
1269
1308
|
vy: Number.isFinite(node.vy) ? node.vy : 0
|
|
1270
1309
|
}
|
|
@@ -1734,9 +1773,10 @@ const computeRenderVisibility = () => {
|
|
|
1734
1773
|
selectAccessBridgeNodes(sourceNodes, bridgeLimit),
|
|
1735
1774
|
Math.min(renderNodeBudget, sampleLimit + bridgeLimit)
|
|
1736
1775
|
)
|
|
1737
|
-
const sampled =
|
|
1738
|
-
|
|
1739
|
-
|
|
1776
|
+
const sampled = selectStableSampleNodes(
|
|
1777
|
+
bridgedNodes,
|
|
1778
|
+
Math.min(sampleLimit, renderNodeBudget)
|
|
1779
|
+
)
|
|
1740
1780
|
const sampledIds = new Set(sampled.map((node) => node.id))
|
|
1741
1781
|
let sampledEdges = state.transform.scale >= 0.035 ? collectVisibleEdgesForNodes(sampledIds) : []
|
|
1742
1782
|
let sampledNodes = ensureHubNodesInRenderedSet(sampled)
|
|
@@ -2106,6 +2146,11 @@ const zoomAtPoint = (screenX, screenY, factor, source = 'generic') => {
|
|
|
2106
2146
|
}
|
|
2107
2147
|
const worldX = (screenX - state.transform.x) / state.transform.scale
|
|
2108
2148
|
const worldY = (screenY - state.transform.y) / state.transform.scale
|
|
2149
|
+
state.lastZoomFocus = {
|
|
2150
|
+
x: worldX,
|
|
2151
|
+
y: worldY,
|
|
2152
|
+
at: performance.now()
|
|
2153
|
+
}
|
|
2109
2154
|
state.transform.scale = clampScale(nextScale)
|
|
2110
2155
|
state.transform.x = clampTransformCoordinate(screenX - worldX * nextScale)
|
|
2111
2156
|
state.transform.y = clampTransformCoordinate(screenY - worldY * nextScale)
|
|
@@ -2122,7 +2167,7 @@ const wheelZoomFactor = event => {
|
|
|
2122
2167
|
return 1
|
|
2123
2168
|
}
|
|
2124
2169
|
|
|
2125
|
-
const baseStep = Math.max(0.
|
|
2170
|
+
const baseStep = Math.max(0.012, Math.min(0.11, absoluteDelta / 980))
|
|
2126
2171
|
const adjustedStep = baseStep * (isModifierZoom ? 1.24 : 1)
|
|
2127
2172
|
|
|
2128
2173
|
return event.deltaY < 0 ? 1 + adjustedStep : 1 / (1 + adjustedStep)
|
package/package.json
CHANGED