Browse Source

Fix person anchors to remain fixed after dragging

- Person anchors now maintain their fixed position after being dragged
- Exclude person anchors from gravity forces (like tag anchors)
- Update both regular and star force simulations to handle person anchors
- Ensure person anchors are draggable but stay anchored at their new position

This ensures person nodes behave as true anchors in the visualization,
maintaining their position in the graph even after user interaction.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
master
limina1 9 months ago
parent
commit
d69f126fde
  1. 13
      docs/event-types-panel-redesign.org
  2. 36
      src/lib/navigator/EventNetwork/utils/forceSimulation.ts
  3. 4
      src/lib/navigator/EventNetwork/utils/starForceSimulation.ts

13
docs/event-types-panel-redesign.org

@ -90,3 +90,16 @@ const contentEvents = await $ndkInstance.fetchEvents({
3. **UX**: Smooth, instant toggle without freezing 3. **UX**: Smooth, instant toggle without freezing
4. **Maintainability**: Clear separation of concerns 4. **Maintainability**: Clear separation of concerns
5. **Scalability**: Handles large numbers of nodes efficiently 5. **Scalability**: Handles large numbers of nodes efficiently
* Additional Improvements
** Profile Fetching Optimization
- When follow list limit is 0, only fetch profiles from event authors
- Excludes follow list pubkeys from profile fetching when not needed
- Reduces unnecessary network requests
** Person Node Visual Distinction
- Green diamonds (#10B981) for authors of displayed events
- Kind 3 color for people from follow lists
- Visual clarity on social graph relationships
- Legend updates to match graph coloring

36
src/lib/navigator/EventNetwork/utils/forceSimulation.ts

@ -102,8 +102,8 @@ export function applyGlobalLogGravity(
centerY: number, centerY: number,
alpha: number, alpha: number,
) { ) {
// Tag anchors should not be affected by gravity // Tag anchors and person anchors should not be affected by gravity
if (node.isTagAnchor) return; if (node.isTagAnchor || node.isPersonAnchor) return;
const dx = (node.x ?? 0) - centerX; const dx = (node.x ?? 0) - centerX;
const dy = (node.y ?? 0) - centerY; const dy = (node.y ?? 0) - centerY;
@ -130,14 +130,14 @@ export function applyConnectedGravity(
links: NetworkLink[], links: NetworkLink[],
alpha: number, alpha: number,
) { ) {
// Tag anchors should not be affected by connected gravity // Tag anchors and person anchors should not be affected by connected gravity
if (node.isTagAnchor) return; if (node.isTagAnchor || node.isPersonAnchor) return;
// Find all nodes connected to this node (excluding tag anchors) // Find all nodes connected to this node (excluding tag anchors and person anchors)
const connectedNodes = links const connectedNodes = links
.filter(link => link.source.id === node.id || link.target.id === node.id) .filter(link => link.source.id === node.id || link.target.id === node.id)
.map(link => link.source.id === node.id ? link.target : link.source) .map(link => link.source.id === node.id ? link.target : link.source)
.filter(n => !n.isTagAnchor); .filter(n => !n.isTagAnchor && !n.isPersonAnchor);
if (connectedNodes.length === 0) return; if (connectedNodes.length === 0) return;
@ -175,8 +175,13 @@ export function setupDragHandlers(
return d3 return d3
.drag() .drag()
.on("start", (event: D3DragEvent<SVGGElement, NetworkNode, NetworkNode>, d: NetworkNode) => { .on("start", (event: D3DragEvent<SVGGElement, NetworkNode, NetworkNode>, d: NetworkNode) => {
// Tag anchors should never be draggable // Tag anchors and person anchors retain their anchor behavior
if (d.isTagAnchor) return; if (d.isTagAnchor || d.isPersonAnchor) {
// Still allow dragging but maintain anchor status
d.fx = d.x;
d.fy = d.y;
return;
}
// Warm up simulation if it's cooled down // Warm up simulation if it's cooled down
if (!event.active) { if (!event.active) {
@ -187,24 +192,29 @@ export function setupDragHandlers(
d.fy = d.y; d.fy = d.y;
}) })
.on("drag", (event: D3DragEvent<SVGGElement, NetworkNode, NetworkNode>, d: NetworkNode) => { .on("drag", (event: D3DragEvent<SVGGElement, NetworkNode, NetworkNode>, d: NetworkNode) => {
// Tag anchors should never be draggable // Update position for all nodes including anchors
if (d.isTagAnchor) return;
// Update fixed position to mouse position // Update fixed position to mouse position
d.fx = event.x; d.fx = event.x;
d.fy = event.y; d.fy = event.y;
}) })
.on("end", (event: D3DragEvent<SVGGElement, NetworkNode, NetworkNode>, d: NetworkNode) => { .on("end", (event: D3DragEvent<SVGGElement, NetworkNode, NetworkNode>, d: NetworkNode) => {
// Tag anchors should never be draggable
if (d.isTagAnchor) return;
// Cool down simulation when drag ends // Cool down simulation when drag ends
if (!event.active) { if (!event.active) {
simulation.alphaTarget(0); simulation.alphaTarget(0);
} }
// Release fixed position
// Person anchors should remain fixed after dragging
if (d.isPersonAnchor) {
// Keep the new position fixed
d.fx = d.x;
d.fy = d.y;
} else {
// Release fixed position for other nodes
d.fx = null; d.fx = null;
d.fy = null; d.fy = null;
}
}); });
} }

4
src/lib/navigator/EventNetwork/utils/starForceSimulation.ts

@ -247,8 +247,8 @@ export function createStarDragHandler(
function dragended(event: any, d: NetworkNode) { function dragended(event: any, d: NetworkNode) {
if (!event.active) simulation.alphaTarget(0); if (!event.active) simulation.alphaTarget(0);
// Tag anchors and star centers stay fixed after dragging // Tag anchors, person anchors, and star centers stay fixed after dragging
if (d.isTagAnchor || d.kind === 30040) { if (d.isTagAnchor || d.isPersonAnchor || d.kind === 30040) {
d.fx = event.x; d.fx = event.x;
d.fy = event.y; d.fy = event.y;
} else { } else {

Loading…
Cancel
Save