@andespindola/brainlink 0.1.0-beta.61 → 0.1.0-beta.62
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.
|
@@ -23,6 +23,8 @@ const meshEdgeScaleThreshold = 0.09
|
|
|
23
23
|
const meshEdgeMinBudget = 140
|
|
24
24
|
const meshEdgeMaxBudget = 1400
|
|
25
25
|
const layeredCoreScaleThreshold = 0.55
|
|
26
|
+
const dragNeighborhoodMaxAffected = 180
|
|
27
|
+
const dragSettleRounds = 3
|
|
26
28
|
const state = {
|
|
27
29
|
graph: { nodes: [], edges: [] },
|
|
28
30
|
nodes: [],
|
|
@@ -1354,6 +1356,104 @@ const worldPoint = event => {
|
|
|
1354
1356
|
}
|
|
1355
1357
|
}
|
|
1356
1358
|
|
|
1359
|
+
const connectedNodeIdsFor = (nodeId) => {
|
|
1360
|
+
const edges = state.visibleEdgeByNode.get(nodeId) ?? []
|
|
1361
|
+
const ids = new Set()
|
|
1362
|
+
|
|
1363
|
+
for (let index = 0; index < edges.length; index += 1) {
|
|
1364
|
+
const edge = edges[index]
|
|
1365
|
+
if (!edge.target) continue
|
|
1366
|
+
if (edge.source === nodeId) {
|
|
1367
|
+
ids.add(edge.target)
|
|
1368
|
+
} else if (edge.target === nodeId) {
|
|
1369
|
+
ids.add(edge.source)
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
return ids
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
const applyDragNeighborhoodAdjustment = (dragNode, deltaX, deltaY) => {
|
|
1377
|
+
if (!dragNode) return
|
|
1378
|
+
if (!Number.isFinite(deltaX) || !Number.isFinite(deltaY)) return
|
|
1379
|
+
if (Math.abs(deltaX) + Math.abs(deltaY) <= 0.001) return
|
|
1380
|
+
|
|
1381
|
+
const scale = Math.max(state.transform.scale, 0.0001)
|
|
1382
|
+
const influenceRadius = Math.max(220, Math.min(920, 440 / scale))
|
|
1383
|
+
const influenceRadiusSquared = influenceRadius * influenceRadius
|
|
1384
|
+
const connectedIds = connectedNodeIdsFor(dragNode.id)
|
|
1385
|
+
const candidates = state.renderNodes.length > 0 ? state.renderNodes : state.visibleNodes
|
|
1386
|
+
let adjusted = 0
|
|
1387
|
+
|
|
1388
|
+
for (let index = 0; index < candidates.length && adjusted < dragNeighborhoodMaxAffected; index += 1) {
|
|
1389
|
+
const node = candidates[index]
|
|
1390
|
+
if (node.id === dragNode.id) continue
|
|
1391
|
+
|
|
1392
|
+
const isConnected = connectedIds.has(node.id)
|
|
1393
|
+
const dx = node.x - dragNode.x
|
|
1394
|
+
const dy = node.y - dragNode.y
|
|
1395
|
+
const distanceSquared = dx * dx + dy * dy
|
|
1396
|
+
const withinRadius = distanceSquared <= influenceRadiusSquared
|
|
1397
|
+
if (!isConnected && !withinRadius) continue
|
|
1398
|
+
|
|
1399
|
+
const distance = Math.max(Math.sqrt(distanceSquared), 0.0001)
|
|
1400
|
+
const proximity = withinRadius ? 1 - (distance / influenceRadius) : 0
|
|
1401
|
+
const coupledStrength = isConnected ? 0.28 : 0.12
|
|
1402
|
+
const influence = Math.min(0.46, coupledStrength + proximity * 0.34)
|
|
1403
|
+
node.x += deltaX * influence
|
|
1404
|
+
node.y += deltaY * influence
|
|
1405
|
+
node.vx = (Number.isFinite(node.vx) ? node.vx : 0) + deltaX * influence * 0.06
|
|
1406
|
+
node.vy = (Number.isFinite(node.vy) ? node.vy : 0) + deltaY * influence * 0.06
|
|
1407
|
+
adjusted += 1
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
const settleNeighborhoodAroundNode = (dragNode) => {
|
|
1412
|
+
if (!dragNode) return
|
|
1413
|
+
|
|
1414
|
+
const scale = Math.max(state.transform.scale, 0.0001)
|
|
1415
|
+
const settleRadius = Math.max(240, Math.min(980, 520 / scale))
|
|
1416
|
+
const settleRadiusSquared = settleRadius * settleRadius
|
|
1417
|
+
const connectedIds = connectedNodeIdsFor(dragNode.id)
|
|
1418
|
+
const candidates = (state.renderNodes.length > 0 ? state.renderNodes : state.visibleNodes)
|
|
1419
|
+
.filter((node) => {
|
|
1420
|
+
if (node.id === dragNode.id) return true
|
|
1421
|
+
const dx = node.x - dragNode.x
|
|
1422
|
+
const dy = node.y - dragNode.y
|
|
1423
|
+
const distanceSquared = dx * dx + dy * dy
|
|
1424
|
+
return connectedIds.has(node.id) || distanceSquared <= settleRadiusSquared
|
|
1425
|
+
})
|
|
1426
|
+
.slice(0, dragNeighborhoodMaxAffected)
|
|
1427
|
+
|
|
1428
|
+
if (candidates.length <= 1) return
|
|
1429
|
+
|
|
1430
|
+
for (let round = 0; round < dragSettleRounds; round += 1) {
|
|
1431
|
+
for (let leftIndex = 0; leftIndex < candidates.length; leftIndex += 1) {
|
|
1432
|
+
const left = candidates[leftIndex]
|
|
1433
|
+
for (let rightIndex = leftIndex + 1; rightIndex < candidates.length; rightIndex += 1) {
|
|
1434
|
+
const right = candidates[rightIndex]
|
|
1435
|
+
const dx = right.x - left.x
|
|
1436
|
+
const dy = right.y - left.y
|
|
1437
|
+
const distance = Math.max(Math.hypot(dx, dy), 0.001)
|
|
1438
|
+
const minDistance = baseNodeRadius(left) + baseNodeRadius(right) + 10
|
|
1439
|
+
if (distance >= minDistance) continue
|
|
1440
|
+
|
|
1441
|
+
const push = (minDistance - distance) * 0.36
|
|
1442
|
+
const ux = dx / distance
|
|
1443
|
+
const uy = dy / distance
|
|
1444
|
+
if (left.id !== dragNode.id) {
|
|
1445
|
+
left.x -= ux * push
|
|
1446
|
+
left.y -= uy * push
|
|
1447
|
+
}
|
|
1448
|
+
if (right.id !== dragNode.id) {
|
|
1449
|
+
right.x += ux * push
|
|
1450
|
+
right.y += uy * push
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1357
1457
|
const hitNode = point => {
|
|
1358
1458
|
computeRenderVisibility()
|
|
1359
1459
|
if (state.renderClusters.length > 0) {
|
|
@@ -2030,8 +2130,12 @@ const bindEvents = () => {
|
|
|
2030
2130
|
state.pointer.y = event.clientY
|
|
2031
2131
|
state.pointer.moved = state.pointer.moved || Math.abs(dx) + Math.abs(dy) > 3
|
|
2032
2132
|
if (state.pointer.dragNode) {
|
|
2033
|
-
state.pointer.dragNode
|
|
2034
|
-
|
|
2133
|
+
const dragNode = state.pointer.dragNode
|
|
2134
|
+
const previousX = dragNode.x
|
|
2135
|
+
const previousY = dragNode.y
|
|
2136
|
+
dragNode.x = point.x
|
|
2137
|
+
dragNode.y = point.y
|
|
2138
|
+
applyDragNeighborhoodAdjustment(dragNode, dragNode.x - previousX, dragNode.y - previousY)
|
|
2035
2139
|
markRenderDirty()
|
|
2036
2140
|
return
|
|
2037
2141
|
}
|
|
@@ -2043,8 +2147,13 @@ const bindEvents = () => {
|
|
|
2043
2147
|
markRenderDirty()
|
|
2044
2148
|
})
|
|
2045
2149
|
canvas.addEventListener('pointerup', event => {
|
|
2046
|
-
|
|
2047
|
-
if (
|
|
2150
|
+
const draggedNode = state.pointer.dragNode
|
|
2151
|
+
if (draggedNode && state.pointer.moved) {
|
|
2152
|
+
settleNeighborhoodAroundNode(draggedNode)
|
|
2153
|
+
markRenderDirty()
|
|
2154
|
+
}
|
|
2155
|
+
if (draggedNode && !state.pointer.moved) selectNode(draggedNode, { openContent: true })
|
|
2156
|
+
if (!draggedNode && !state.pointer.moved) selectNode(state.hovered, { openContent: true })
|
|
2048
2157
|
state.pointer = { x: 0, y: 0, down: false, dragNode: null, moved: false }
|
|
2049
2158
|
canvas.releasePointerCapture(event.pointerId)
|
|
2050
2159
|
})
|
package/package.json
CHANGED