|
|
|
@ -37,6 +37,8 @@ |
|
|
|
y?: number; |
|
|
|
y?: number; |
|
|
|
fx?: number | null; |
|
|
|
fx?: number | null; |
|
|
|
fy?: number | null; |
|
|
|
fy?: number | null; |
|
|
|
|
|
|
|
vx?: number; |
|
|
|
|
|
|
|
vy?: number; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
interface NetworkLink extends d3.SimulationLinkDatum<NetworkNode> { |
|
|
|
interface NetworkLink extends d3.SimulationLinkDatum<NetworkNode> { |
|
|
|
@ -48,55 +50,45 @@ |
|
|
|
function createEventMap(events: NDKEvent[]): Map<string, NDKEvent> { |
|
|
|
function createEventMap(events: NDKEvent[]): Map<string, NDKEvent> { |
|
|
|
return new Map(events.map((event) => [event.id, event])); |
|
|
|
return new Map(events.map((event) => [event.id, event])); |
|
|
|
} |
|
|
|
} |
|
|
|
function applyGlobalLogGravity( |
|
|
|
function updateNodeVelocity(node: NetworkNode, deltaVx: number, deltaVy: number) { |
|
|
|
node: NetworkNode, |
|
|
|
if (typeof node.vx === 'number' && typeof node.vy === 'number') { |
|
|
|
centerX: number, |
|
|
|
node.vx = node.vx - deltaVx; |
|
|
|
centerY: number, |
|
|
|
node.vy = node.vy - deltaVy; |
|
|
|
alpha: number, |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
const globalGravityStrength = 0.05; |
|
|
|
|
|
|
|
const dx = node.x! - centerX; |
|
|
|
|
|
|
|
const dy = node.y! - centerY; |
|
|
|
|
|
|
|
const distance = Math.sqrt(dx * dx + dy * dy); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (distance === 0) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const force = Math.log(distance + 1) * globalGravityStrength * alpha; |
|
|
|
|
|
|
|
node.vx! -= (dx / distance) * force; |
|
|
|
|
|
|
|
node.vy! -= (dy / distance) * force; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function applyConnectedGravity( |
|
|
|
function applyGlobalLogGravity(node: NetworkNode, centerX: number, centerY: number, alpha: number) { |
|
|
|
node: NetworkNode, |
|
|
|
const dx = (node.x ?? 0) - centerX; |
|
|
|
links: NetworkLink[], |
|
|
|
const dy = (node.y ?? 0) - centerY; |
|
|
|
alpha: number, |
|
|
|
const distance = Math.sqrt(dx * dx + dy * dy); |
|
|
|
) { |
|
|
|
|
|
|
|
const connectedGravityStrength = 0.3; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const connectedNodes = links |
|
|
|
if (distance === 0) return; |
|
|
|
.filter( |
|
|
|
|
|
|
|
(link) => link.source.id === node.id || link.target.id === node.id, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.map((link) => (link.source.id === node.id ? link.target : link.source)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (connectedNodes.length === 0) return; |
|
|
|
const force = Math.log(distance + 1) * 0.05 * alpha; |
|
|
|
|
|
|
|
updateNodeVelocity(node, (dx / distance) * force, (dy / distance) * force); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const cogX = d3.mean(connectedNodes, (node) => node.x); |
|
|
|
function applyConnectedGravity(node: NetworkNode, links: NetworkLink[], alpha: number) { |
|
|
|
const cogY = d3.mean(connectedNodes, (node) => node.y); |
|
|
|
const connectedNodes = links |
|
|
|
|
|
|
|
.filter(link => link.source.id === node.id || link.target.id === node.id) |
|
|
|
|
|
|
|
.map(link => link.source.id === node.id ? link.target : link.source); |
|
|
|
|
|
|
|
|
|
|
|
if (cogX === undefined || cogY === undefined) return; |
|
|
|
if (connectedNodes.length === 0) return; |
|
|
|
|
|
|
|
|
|
|
|
const dx = node.x! - cogX; |
|
|
|
const cogX = d3.mean(connectedNodes, n => n.x); |
|
|
|
const dy = node.y! - cogY; |
|
|
|
const cogY = d3.mean(connectedNodes, n => n.y); |
|
|
|
const distance = Math.sqrt(dx * dx + dy * dy); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (distance === 0) return; |
|
|
|
if (cogX === undefined || cogY === undefined) return; |
|
|
|
|
|
|
|
|
|
|
|
const force = distance * connectedGravityStrength * alpha; |
|
|
|
const dx = (node.x ?? 0) - cogX; |
|
|
|
node.vx! -= (dx / distance) * force; |
|
|
|
const dy = (node.y ?? 0) - cogY; |
|
|
|
node.vy! -= (dy / distance) * force; |
|
|
|
const distance = Math.sqrt(dx * dx + dy * dy); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (distance === 0) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const force = distance * 0.3 * alpha; |
|
|
|
|
|
|
|
updateNodeVelocity(node, (dx / distance) * force, (dy / distance) * force); |
|
|
|
|
|
|
|
} |
|
|
|
function getNode( |
|
|
|
function getNode( |
|
|
|
id: string, |
|
|
|
id: string, |
|
|
|
nodeMap: Map<string, NetworkNode>, |
|
|
|
nodeMap: Map<string, NetworkNode>, |
|
|
|
|