Keep neighbor lines when either endpoint is in view

Both the server bbox filter (getAllNodeNeighbors) and the client filter
(AllNeighborLines) required BOTH endpoints inside the viewport, so any line
with one end off-screen vanished when zooming in. Switch both to "either
endpoint in view": the server returns an edge if source OR target falls in the
bbox, and the client keeps it if either endpoint is a visible node. Each edge
carries both endpoints' coordinates, so the off-screen end still draws.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Vanderpot
2026-06-19 21:29:31 -04:00
parent 6bc58d6fdc
commit 69da222008
2 changed files with 14 additions and 16 deletions
+4 -4
View File
@@ -431,12 +431,12 @@ function AllNeighborLines({
// Create a set of visible node IDs for quick lookup
const visibleNodeIds = new Set(nodes.map(node => node.node_id));
// Filter connections to only show lines between nodes that are visible on the map
// and meet the minimum packet count threshold. Confidence filtering happens server-side
// Keep a line if EITHER endpoint is visible on the map, so connections that leave the viewport
// (one node on-screen, the other off-screen) stay drawn. Each edge carries both endpoints'
// coordinates, so the off-screen end renders fine. Confidence filtering happens server-side
// (the confidence selector drives a refetch), so no client-side confidence filter here.
const visibleConnections = connections.filter(connection =>
visibleNodeIds.has(connection.source_node) &&
visibleNodeIds.has(connection.target_node) &&
(visibleNodeIds.has(connection.source_node) || visibleNodeIds.has(connection.target_node)) &&
connection.packet_count >= minPacketCount
);
+10 -12
View File
@@ -332,21 +332,19 @@ export async function getAllNodeNeighbors(lastSeen: string | null = null, minLat
visibleNodeSqlClause("target_name"),
];
// Bounding box: both endpoints must be within view (matches the old visible_nodes behavior)
if (minLat !== null && minLat !== undefined && minLat !== "") {
whereConditions.push("source_latitude >= {minLat:Float64} AND target_latitude >= {minLat:Float64}");
// Bounding box: keep an edge if EITHER endpoint is within view, so connections that leave the
// viewport (one node on-screen, the other off-screen) stay visible. Both endpoints' coordinates
// are denormalized on the edge, so the off-screen end still draws.
const bbox = [minLat, maxLat, minLng, maxLng];
const hasBbox = bbox.every(v => v !== null && v !== undefined && v !== "");
if (hasBbox) {
whereConditions.push(`(
(source_latitude BETWEEN {minLat:Float64} AND {maxLat:Float64} AND source_longitude BETWEEN {minLng:Float64} AND {maxLng:Float64})
OR (target_latitude BETWEEN {minLat:Float64} AND {maxLat:Float64} AND target_longitude BETWEEN {minLng:Float64} AND {maxLng:Float64})
)`);
params.minLat = Number(minLat);
}
if (maxLat !== null && maxLat !== undefined && maxLat !== "") {
whereConditions.push("source_latitude <= {maxLat:Float64} AND target_latitude <= {maxLat:Float64}");
params.maxLat = Number(maxLat);
}
if (minLng !== null && minLng !== undefined && minLng !== "") {
whereConditions.push("source_longitude >= {minLng:Float64} AND target_longitude >= {minLng:Float64}");
params.minLng = Number(minLng);
}
if (maxLng !== null && maxLng !== undefined && maxLng !== "") {
whereConditions.push("source_longitude <= {maxLng:Float64} AND target_longitude <= {maxLng:Float64}");
params.maxLng = Number(maxLng);
}
if (lastSeen !== null && lastSeen !== undefined && lastSeen !== "") {