@andespindola/brainlink 0.1.0-beta.74 → 0.1.0-beta.76
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.
- package/README.md +1 -1
- package/dist/application/frontend/client-js.js +85 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -594,7 +594,7 @@ The graph UI shows:
|
|
|
594
594
|
- double-click on canvas zooms in at cursor position
|
|
595
595
|
- floating graph totals (notes, links, tags) below the Brainlink title
|
|
596
596
|
- large-graph rendering safeguards (edge draw caps, lower redraw rate, zoom-aware interaction)
|
|
597
|
-
- massive-graph LOD progression: very low zoom uses spatial overview
|
|
597
|
+
- massive-graph LOD progression: very low zoom uses spatial overview sampling plus hub-neighborhood edge previews to preserve whole-vault shape and orientation, then progressively reveals nodes and edges as zoom increases
|
|
598
598
|
|
|
599
599
|
The server indexes before starting by default. Use `--no-index` to skip that step:
|
|
600
600
|
|
|
@@ -1110,6 +1110,64 @@ const enrichSampleWithNeighbors = (nodes) => {
|
|
|
1110
1110
|
}
|
|
1111
1111
|
}
|
|
1112
1112
|
|
|
1113
|
+
const includeHubPreviewNeighborhood = (nodes, limit) => {
|
|
1114
|
+
const hub = state.primaryHub
|
|
1115
|
+
if (!hub) {
|
|
1116
|
+
return nodes
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
const maxNodes = Math.max(1, Math.min(renderNodeBudget, limit))
|
|
1120
|
+
const merged = [...nodes]
|
|
1121
|
+
const ids = new Set(merged.map((node) => node.id))
|
|
1122
|
+
|
|
1123
|
+
if (!ids.has(hub.id)) {
|
|
1124
|
+
if (merged.length < maxNodes) {
|
|
1125
|
+
merged.push(hub)
|
|
1126
|
+
ids.add(hub.id)
|
|
1127
|
+
} else {
|
|
1128
|
+
const replaceIndex = merged.findIndex((node) => node.id !== hub.id)
|
|
1129
|
+
if (replaceIndex >= 0) {
|
|
1130
|
+
ids.delete(merged[replaceIndex].id)
|
|
1131
|
+
merged[replaceIndex] = hub
|
|
1132
|
+
ids.add(hub.id)
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
const hubEdges = [...(state.visibleEdgeByNode.get(hub.id) ?? [])]
|
|
1138
|
+
.filter((edge) => edge.target && (edge.source === hub.id || edge.target === hub.id))
|
|
1139
|
+
.sort((left, right) => {
|
|
1140
|
+
const byWeight = edgeWeight(right) - edgeWeight(left)
|
|
1141
|
+
if (byWeight !== 0) return byWeight
|
|
1142
|
+
|
|
1143
|
+
const leftOtherId = left.source === hub.id ? left.target : left.source
|
|
1144
|
+
const rightOtherId = right.source === hub.id ? right.target : right.source
|
|
1145
|
+
const leftDegree = state.nodeDegrees.get(leftOtherId ?? '') ?? 0
|
|
1146
|
+
const rightDegree = state.nodeDegrees.get(rightOtherId ?? '') ?? 0
|
|
1147
|
+
if (leftDegree !== rightDegree) return rightDegree - leftDegree
|
|
1148
|
+
|
|
1149
|
+
return edgeIdentityKey(left).localeCompare(edgeIdentityKey(right))
|
|
1150
|
+
})
|
|
1151
|
+
|
|
1152
|
+
for (let index = 0; index < hubEdges.length && merged.length < maxNodes; index += 1) {
|
|
1153
|
+
const edge = hubEdges[index]
|
|
1154
|
+
const otherId = edge.source === hub.id ? edge.target : edge.source
|
|
1155
|
+
if (!otherId || ids.has(otherId)) {
|
|
1156
|
+
continue
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
const otherNode = state.nodeById.get(otherId)
|
|
1160
|
+
if (!otherNode) {
|
|
1161
|
+
continue
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
ids.add(otherId)
|
|
1165
|
+
merged.push(otherNode)
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
return merged
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1113
1171
|
const ensureHubNodesInRenderedSet = (nodes) => {
|
|
1114
1172
|
if (nodes.length === 0) {
|
|
1115
1173
|
return nodes
|
|
@@ -1758,6 +1816,18 @@ const clusterViewportNodes = viewportNodes => {
|
|
|
1758
1816
|
}))
|
|
1759
1817
|
}
|
|
1760
1818
|
|
|
1819
|
+
const representativeNodesFromClusters = (clusters, limit) => {
|
|
1820
|
+
const representatives = clusters
|
|
1821
|
+
.map((cluster) => cluster.representative)
|
|
1822
|
+
.filter((node) => Boolean(node))
|
|
1823
|
+
const merged = mergeUniqueNodes(
|
|
1824
|
+
representatives,
|
|
1825
|
+
state.renderNodes ?? [],
|
|
1826
|
+
Math.max(1, limit)
|
|
1827
|
+
)
|
|
1828
|
+
return ensureHubNodesInRenderedSet(merged)
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1761
1831
|
const computeRenderVisibility = () => {
|
|
1762
1832
|
if (!hasValidTransform()) {
|
|
1763
1833
|
fitView({ useFiltered: true })
|
|
@@ -1816,8 +1886,11 @@ const computeRenderVisibility = () => {
|
|
|
1816
1886
|
.sort((left, right) => right.count - left.count)
|
|
1817
1887
|
.slice(0, Math.min(renderNodeBudget, clusterBudgetForScale(state.transform.scale)))
|
|
1818
1888
|
if (overviewClusters.length > 0) {
|
|
1819
|
-
state.renderClusters =
|
|
1820
|
-
state.renderNodes =
|
|
1889
|
+
state.renderClusters = []
|
|
1890
|
+
state.renderNodes = representativeNodesFromClusters(
|
|
1891
|
+
overviewClusters,
|
|
1892
|
+
Math.min(renderNodeBudget, clusterBudgetForScale(state.transform.scale))
|
|
1893
|
+
)
|
|
1821
1894
|
state.renderEdges = []
|
|
1822
1895
|
return
|
|
1823
1896
|
}
|
|
@@ -1848,9 +1921,15 @@ const computeRenderVisibility = () => {
|
|
|
1848
1921
|
sampledRaw,
|
|
1849
1922
|
Math.min(sampleLimit, renderNodeBudget)
|
|
1850
1923
|
)
|
|
1851
|
-
const sampledIds = new Set(sampled.map((node) => node.id))
|
|
1852
|
-
let sampledEdges = state.transform.scale >= 0.035 ? collectVisibleEdgesForNodes(sampledIds) : []
|
|
1853
1924
|
let sampledNodes = ensureHubNodesInRenderedSet(sampled)
|
|
1925
|
+
if (state.transform.scale < 0.035) {
|
|
1926
|
+
sampledNodes = includeHubPreviewNeighborhood(
|
|
1927
|
+
sampledNodes,
|
|
1928
|
+
Math.min(renderNodeBudget, sampleLimit + 160)
|
|
1929
|
+
)
|
|
1930
|
+
}
|
|
1931
|
+
const sampledIds = new Set(sampledNodes.map((node) => node.id))
|
|
1932
|
+
let sampledEdges = collectVisibleEdgesForNodes(sampledIds)
|
|
1854
1933
|
|
|
1855
1934
|
if (state.transform.scale >= 0.035 && sampledEdges.length === 0) {
|
|
1856
1935
|
const enriched = enrichSampleWithNeighbors(sampledNodes)
|
|
@@ -1877,8 +1956,8 @@ const computeRenderVisibility = () => {
|
|
|
1877
1956
|
const viewportNodes = viewportNodesFromSpatialIndex(viewport)
|
|
1878
1957
|
const clusters = clusterViewportNodes(viewportNodes)
|
|
1879
1958
|
if (clusters.length > 0) {
|
|
1880
|
-
state.renderClusters =
|
|
1881
|
-
state.renderNodes = clusters.
|
|
1959
|
+
state.renderClusters = []
|
|
1960
|
+
state.renderNodes = representativeNodesFromClusters(clusters, Math.min(renderNodeBudget, 900))
|
|
1882
1961
|
state.renderEdges = []
|
|
1883
1962
|
return
|
|
1884
1963
|
}
|
package/package.json
CHANGED