Remove all delays from historical packet loading for maximum speed

Server-side optimizations:
- Remove all Process.send_after delays - use immediate send()
- High zoom (10+): Load everything in single batch (up to 500 packets)
- Low zoom: Load all batches immediately without delays
- Remove debug logging for performance

Client-side optimizations:
- Remove chunking delays and requestAnimationFrame
- Process all packets immediately without setTimeout
- Remove 10-packet chunk limit - process everything at once

Result: Historical packets now load as fast as possible
without artificial delays or chunking bottlenecks.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Graham McIntire 2025-07-09 09:33:21 -05:00
parent a9414823f1
commit 57fe2b0182
No known key found for this signature in database
2 changed files with 61 additions and 94 deletions

View file

@ -685,64 +685,42 @@ let MapAPRSMap = {
// Handle progressive loading of historical packets (batch processing)
self.handleEvent("add_historical_packets_batch", (data: { packets: MarkerData[], batch: number, is_final: boolean }) => {
if (data.packets && Array.isArray(data.packets)) {
// Use requestAnimationFrame to ensure smooth rendering
requestAnimationFrame(() => {
// Process packets in smaller chunks to prevent UI blocking
const chunkSize = 10;
let currentIndex = 0;
const processChunk = () => {
const chunk = data.packets.slice(currentIndex, currentIndex + chunkSize);
// Group packets by callsign to process them in chronological order for proper trail drawing
const packetsByCallsign = new Map<string, MarkerData[]>();
// Process all packets immediately for maximum speed
const packetsByCallsign = new Map<string, MarkerData[]>();
chunk.forEach((packet) => {
const callsign = packet.callsign_group || packet.callsign || packet.id;
if (!packetsByCallsign.has(callsign)) {
packetsByCallsign.set(callsign, []);
}
packetsByCallsign.get(callsign)!.push(packet);
data.packets.forEach((packet) => {
const callsign = packet.callsign_group || packet.callsign || packet.id;
if (!packetsByCallsign.has(callsign)) {
packetsByCallsign.set(callsign, []);
}
packetsByCallsign.get(callsign)!.push(packet);
});
// Process each callsign group in chronological order (oldest first)
packetsByCallsign.forEach((packets, callsign) => {
// Sort by timestamp (oldest first) to ensure proper trail line drawing
const sortedPackets = packets.sort((a, b) => {
const timeA = a.timestamp
? typeof a.timestamp === "number"
? a.timestamp
: new Date(a.timestamp).getTime()
: 0;
const timeB = b.timestamp
? typeof b.timestamp === "number"
? b.timestamp
: new Date(b.timestamp).getTime()
: 0;
return timeA - timeB;
});
// Add markers in chronological order
sortedPackets.forEach((packet) => {
self.addMarker({
...packet,
historical: true,
popup: packet.popup || self.buildPopupContent(packet),
});
// Process each callsign group in chronological order (oldest first)
packetsByCallsign.forEach((packets, callsign) => {
// Sort by timestamp (oldest first) to ensure proper trail line drawing
const sortedPackets = packets.sort((a, b) => {
const timeA = a.timestamp
? typeof a.timestamp === "number"
? a.timestamp
: new Date(a.timestamp).getTime()
: 0;
const timeB = b.timestamp
? typeof b.timestamp === "number"
? b.timestamp
: new Date(b.timestamp).getTime()
: 0;
return timeA - timeB;
});
// Add markers in chronological order
sortedPackets.forEach((packet) => {
self.addMarker({
...packet,
historical: true,
popup: packet.popup || self.buildPopupContent(packet),
});
});
});
currentIndex += chunkSize;
// Continue processing if there are more packets
if (currentIndex < data.packets.length) {
// Use setTimeout to yield control and prevent blocking
setTimeout(processChunk, 0);
}
};
// Start processing
processChunk();
});
});
}
});

View file

@ -1321,52 +1321,44 @@ defmodule AprsmeWeb.MapLive.Index do
# Progressive loading functions using LiveView's efficient update mechanisms
@spec start_progressive_historical_loading(Socket.t()) :: Socket.t()
defp start_progressive_historical_loading(socket) do
# Calculate optimal batch count based on zoom level
# For high zoom levels, load everything in one batch for maximum speed
zoom = socket.assigns.map_zoom || 5
total_batches = calculate_batch_count_for_zoom(zoom)
# Start with a small batch for immediate visual feedback
socket =
if zoom >= 10 do
# High zoom - load everything at once for maximum speed
socket
|> assign(loading_batch: 0, total_batches: total_batches)
|> assign(loading_batch: 0, total_batches: 1)
|> load_historical_batch(0)
else
# Low zoom - use progressive loading to prevent overwhelming
total_batches = calculate_batch_count_for_zoom(zoom)
# Start with first batch
socket =
socket
|> assign(loading_batch: 0, total_batches: total_batches)
|> load_historical_batch(0)
# Schedule next batches using LiveView's async processing
# Use much shorter delays for higher zoom levels (fewer batches)
base_delay =
cond do
# Very zoomed in - almost instant
zoom >= 15 -> 10
# Moderately zoomed in
zoom >= 12 -> 20
# Medium zoom
zoom >= 8 -> 35
# Zoomed out
true -> 50
end
# Load all remaining batches immediately - no delays
Enum.each(1..(total_batches - 1), fn batch_index ->
send(self(), {:load_historical_batch, batch_index})
end)
Enum.each(1..(total_batches - 1), fn batch_index ->
# Linear delays instead of exponential
delay = base_delay * batch_index
Process.send_after(self(), {:load_historical_batch, batch_index}, delay)
end)
socket
socket
end
end
# Calculate optimal batch size based on zoom level
# Higher zoom = smaller viewport = fewer packets needed = smaller batches for faster response
# Higher zoom = smaller viewport = load everything at once for speed
@spec calculate_batch_size_for_zoom(integer()) :: integer()
# Very zoomed in - tiny batches for instant response
defp calculate_batch_size_for_zoom(zoom) when zoom >= 15, do: 10
# Moderately zoomed in - small batches
defp calculate_batch_size_for_zoom(zoom) when zoom >= 12, do: 20
# High zoom - load everything at once (up to 500 packets)
defp calculate_batch_size_for_zoom(zoom) when zoom >= 10, do: 500
# Medium zoom
defp calculate_batch_size_for_zoom(zoom) when zoom >= 8, do: 35
defp calculate_batch_size_for_zoom(zoom) when zoom >= 8, do: 100
# Zoomed out
defp calculate_batch_size_for_zoom(zoom) when zoom >= 5, do: 50
defp calculate_batch_size_for_zoom(zoom) when zoom >= 5, do: 75
# Very zoomed out
defp calculate_batch_size_for_zoom(_), do: 75
defp calculate_batch_size_for_zoom(_), do: 50
# Calculate optimal number of batches based on zoom level
# Higher zoom = fewer batches needed since viewport is smaller
@ -1397,10 +1389,7 @@ defmodule AprsmeWeb.MapLive.Index do
batch_size = calculate_batch_size_for_zoom(zoom)
offset = batch_offset * batch_size
# Debug logging to see what bounds we're using
Logger.debug(
"Loading historical batch #{batch_offset} with zoom #{zoom}, batch_size #{batch_size}, bounds: #{inspect(bounds)}"
)
# Debug logging removed for performance
packets_module = Application.get_env(:aprsme, :packets_module, Aprsme.Packets)