@andespindola/brainlink 0.1.0-beta.63 → 0.1.0-beta.65
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.
|
@@ -570,16 +570,17 @@ const nodeBudgetForScale = (scale) => {
|
|
|
570
570
|
return renderNodeBudget
|
|
571
571
|
}
|
|
572
572
|
|
|
573
|
-
const
|
|
573
|
+
const layerFocusForScale = (scale) => {
|
|
574
574
|
const normalized = Math.max(0, Math.min(1, (scale - 0.06) / 0.94))
|
|
575
|
-
const
|
|
576
|
-
const
|
|
577
|
-
const
|
|
575
|
+
const shellCenter = Math.max(0.08, 0.96 - normalized * 0.86)
|
|
576
|
+
const shellWidth = Math.max(0.16, 0.34 - normalized * 0.2)
|
|
577
|
+
const coreRadius = Math.max(0.06, 0.1 + normalized * 0.22)
|
|
578
|
+
const coreRatio = Math.max(0.2, Math.min(0.72, 0.24 + normalized * 0.48))
|
|
578
579
|
|
|
579
|
-
return {
|
|
580
|
+
return { shellCenter, shellWidth, coreRadius, coreRatio }
|
|
580
581
|
}
|
|
581
582
|
|
|
582
|
-
const selectLayeredNodesForScale = (sourceNodes) => {
|
|
583
|
+
const selectLayeredNodesForScale = (sourceNodes, targetCount) => {
|
|
583
584
|
const hub = state.primaryHub
|
|
584
585
|
if (!hub || sourceNodes.length <= 1200 || state.visibleNodes.length <= massiveGraphNodeThreshold) {
|
|
585
586
|
return sourceNodes
|
|
@@ -598,39 +599,58 @@ const selectLayeredNodesForScale = (sourceNodes) => {
|
|
|
598
599
|
return sourceNodes
|
|
599
600
|
}
|
|
600
601
|
|
|
601
|
-
const
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}
|
|
602
|
+
const focus = layerFocusForScale(state.transform.scale)
|
|
603
|
+
const normalizedRows = distances.map((item) => ({
|
|
604
|
+
...item,
|
|
605
|
+
normalized: item.distance / maxDistance
|
|
606
|
+
}))
|
|
607
|
+
const desired = Math.max(220, Math.min(sourceNodes.length, targetCount * 2))
|
|
608
|
+
const coreTarget = Math.max(36, Math.min(desired - 8, Math.floor(desired * focus.coreRatio)))
|
|
609
|
+
const shellTarget = Math.max(12, desired - coreTarget)
|
|
610
|
+
const shellHalf = focus.shellWidth / 2
|
|
611
611
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
612
|
+
const coreNodes = normalizedRows
|
|
613
|
+
.filter((item) => item.normalized <= focus.coreRadius)
|
|
614
|
+
.sort((left, right) => {
|
|
615
|
+
const leftScore = state.nodeDegrees.get(left.node.id) ?? 0
|
|
616
|
+
const rightScore = state.nodeDegrees.get(right.node.id) ?? 0
|
|
617
|
+
if (leftScore !== rightScore) return rightScore - leftScore
|
|
618
|
+
return left.node.id.localeCompare(right.node.id)
|
|
619
|
+
})
|
|
620
|
+
.slice(0, coreTarget)
|
|
621
|
+
.map((item) => item.node)
|
|
615
622
|
|
|
616
|
-
const
|
|
617
|
-
const fallback = [...distances]
|
|
623
|
+
const shellNodes = normalizedRows
|
|
618
624
|
.sort((left, right) => {
|
|
619
|
-
const
|
|
620
|
-
const
|
|
621
|
-
const
|
|
622
|
-
const
|
|
625
|
+
const leftDelta = Math.abs(left.normalized - focus.shellCenter)
|
|
626
|
+
const rightDelta = Math.abs(right.normalized - focus.shellCenter)
|
|
627
|
+
const leftInside = leftDelta <= shellHalf ? 0 : 1
|
|
628
|
+
const rightInside = rightDelta <= shellHalf ? 0 : 1
|
|
629
|
+
if (leftInside !== rightInside) return leftInside - rightInside
|
|
623
630
|
if (leftDelta !== rightDelta) return leftDelta - rightDelta
|
|
631
|
+
const leftScore = state.nodeDegrees.get(left.node.id) ?? 0
|
|
632
|
+
const rightScore = state.nodeDegrees.get(right.node.id) ?? 0
|
|
633
|
+
if (leftScore !== rightScore) return rightScore - leftScore
|
|
624
634
|
return left.node.id.localeCompare(right.node.id)
|
|
625
635
|
})
|
|
626
|
-
.slice(0,
|
|
636
|
+
.slice(0, shellTarget)
|
|
627
637
|
.map((item) => item.node)
|
|
628
638
|
|
|
629
|
-
|
|
630
|
-
|
|
639
|
+
const merged = []
|
|
640
|
+
const ids = new Set()
|
|
641
|
+
const pushUnique = (node) => {
|
|
642
|
+
if (!node || ids.has(node.id)) return
|
|
643
|
+
ids.add(node.id)
|
|
644
|
+
merged.push(node)
|
|
631
645
|
}
|
|
632
646
|
|
|
633
|
-
|
|
647
|
+
if (state.transform.scale >= layeredCoreScaleThreshold) {
|
|
648
|
+
pushUnique(hub)
|
|
649
|
+
}
|
|
650
|
+
for (let index = 0; index < coreNodes.length; index += 1) pushUnique(coreNodes[index])
|
|
651
|
+
for (let index = 0; index < shellNodes.length; index += 1) pushUnique(shellNodes[index])
|
|
652
|
+
|
|
653
|
+
return merged.length > 0 ? merged : sourceNodes
|
|
634
654
|
}
|
|
635
655
|
|
|
636
656
|
const edgeIdentityKey = edge => {
|
|
@@ -1650,8 +1670,8 @@ const computeRenderVisibility = () => {
|
|
|
1650
1670
|
if (state.visibleNodes.length > massiveGraphNodeThreshold) {
|
|
1651
1671
|
const viewportNodes = viewportNodesFromSpatialIndex(viewport)
|
|
1652
1672
|
const sourceNodes = viewportNodes.length > 0 ? viewportNodes : state.visibleNodes
|
|
1653
|
-
const layeredNodes = selectLayeredNodesForScale(sourceNodes)
|
|
1654
1673
|
const sampleLimit = nodeBudgetForScale(state.transform.scale)
|
|
1674
|
+
const layeredNodes = selectLayeredNodesForScale(sourceNodes, sampleLimit)
|
|
1655
1675
|
const sampled = layeredNodes.length > sampleLimit
|
|
1656
1676
|
? sampleVisibleNodes(Math.min(sampleLimit, renderNodeBudget), layeredNodes)
|
|
1657
1677
|
: layeredNodes.slice(0, Math.min(layeredNodes.length, renderNodeBudget))
|
|
@@ -2113,6 +2133,13 @@ const bindEvents = () => {
|
|
|
2113
2133
|
})
|
|
2114
2134
|
canvas.addEventListener('wheel', handleWheelZoom, { passive: false })
|
|
2115
2135
|
canvas.addEventListener('dblclick', event => {
|
|
2136
|
+
const point = worldPoint(event)
|
|
2137
|
+
const node = hitNode(point)
|
|
2138
|
+
if (node) {
|
|
2139
|
+
selectNode(node, { openContent: true })
|
|
2140
|
+
return
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2116
2143
|
const rect = canvas.getBoundingClientRect()
|
|
2117
2144
|
const cursorX = event.clientX - rect.left
|
|
2118
2145
|
const cursorY = event.clientY - rect.top
|
|
@@ -2172,8 +2199,8 @@ const bindEvents = () => {
|
|
|
2172
2199
|
settleNeighborhoodAroundNode(draggedNode)
|
|
2173
2200
|
markRenderDirty()
|
|
2174
2201
|
}
|
|
2175
|
-
if (draggedNode && !state.pointer.moved) selectNode(draggedNode, { openContent:
|
|
2176
|
-
if (!draggedNode && !state.pointer.moved) selectNode(state.hovered, { openContent:
|
|
2202
|
+
if (draggedNode && !state.pointer.moved) selectNode(draggedNode, { openContent: false })
|
|
2203
|
+
if (!draggedNode && !state.pointer.moved) selectNode(state.hovered, { openContent: false })
|
|
2177
2204
|
state.pointer = { x: 0, y: 0, down: false, dragNode: null, moved: false }
|
|
2178
2205
|
canvas.releasePointerCapture(event.pointerId)
|
|
2179
2206
|
})
|
package/package.json
CHANGED