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:
parent
a9414823f1
commit
57fe2b0182
2 changed files with 61 additions and 94 deletions
|
|
@ -685,64 +685,42 @@ let MapAPRSMap = {
|
||||||
// Handle progressive loading of historical packets (batch processing)
|
// Handle progressive loading of historical packets (batch processing)
|
||||||
self.handleEvent("add_historical_packets_batch", (data: { packets: MarkerData[], batch: number, is_final: boolean }) => {
|
self.handleEvent("add_historical_packets_batch", (data: { packets: MarkerData[], batch: number, is_final: boolean }) => {
|
||||||
if (data.packets && Array.isArray(data.packets)) {
|
if (data.packets && Array.isArray(data.packets)) {
|
||||||
// Use requestAnimationFrame to ensure smooth rendering
|
// Process all packets immediately for maximum speed
|
||||||
requestAnimationFrame(() => {
|
const packetsByCallsign = new Map<string, MarkerData[]>();
|
||||||
// Process packets in smaller chunks to prevent UI blocking
|
|
||||||
const chunkSize = 10;
|
|
||||||
let currentIndex = 0;
|
|
||||||
|
|
||||||
const processChunk = () => {
|
data.packets.forEach((packet) => {
|
||||||
const chunk = data.packets.slice(currentIndex, currentIndex + chunkSize);
|
const callsign = packet.callsign_group || packet.callsign || packet.id;
|
||||||
|
if (!packetsByCallsign.has(callsign)) {
|
||||||
|
packetsByCallsign.set(callsign, []);
|
||||||
|
}
|
||||||
|
packetsByCallsign.get(callsign)!.push(packet);
|
||||||
|
});
|
||||||
|
|
||||||
// Group packets by callsign to process them in chronological order for proper trail drawing
|
// Process each callsign group in chronological order (oldest first)
|
||||||
const packetsByCallsign = new Map<string, MarkerData[]>();
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
chunk.forEach((packet) => {
|
// Add markers in chronological order
|
||||||
const callsign = packet.callsign_group || packet.callsign || packet.id;
|
sortedPackets.forEach((packet) => {
|
||||||
if (!packetsByCallsign.has(callsign)) {
|
self.addMarker({
|
||||||
packetsByCallsign.set(callsign, []);
|
...packet,
|
||||||
}
|
historical: true,
|
||||||
packetsByCallsign.get(callsign)!.push(packet);
|
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();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1321,52 +1321,44 @@ defmodule AprsmeWeb.MapLive.Index do
|
||||||
# Progressive loading functions using LiveView's efficient update mechanisms
|
# Progressive loading functions using LiveView's efficient update mechanisms
|
||||||
@spec start_progressive_historical_loading(Socket.t()) :: Socket.t()
|
@spec start_progressive_historical_loading(Socket.t()) :: Socket.t()
|
||||||
defp start_progressive_historical_loading(socket) do
|
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
|
zoom = socket.assigns.map_zoom || 5
|
||||||
total_batches = calculate_batch_count_for_zoom(zoom)
|
|
||||||
|
|
||||||
# Start with a small batch for immediate visual feedback
|
if zoom >= 10 do
|
||||||
socket =
|
# High zoom - load everything at once for maximum speed
|
||||||
socket
|
socket
|
||||||
|> assign(loading_batch: 0, total_batches: total_batches)
|
|> assign(loading_batch: 0, total_batches: 1)
|
||||||
|> load_historical_batch(0)
|
|> load_historical_batch(0)
|
||||||
|
else
|
||||||
|
# Low zoom - use progressive loading to prevent overwhelming
|
||||||
|
total_batches = calculate_batch_count_for_zoom(zoom)
|
||||||
|
|
||||||
# Schedule next batches using LiveView's async processing
|
# Start with first batch
|
||||||
# Use much shorter delays for higher zoom levels (fewer batches)
|
socket =
|
||||||
base_delay =
|
socket
|
||||||
cond do
|
|> assign(loading_batch: 0, total_batches: total_batches)
|
||||||
# Very zoomed in - almost instant
|
|> load_historical_batch(0)
|
||||||
zoom >= 15 -> 10
|
|
||||||
# Moderately zoomed in
|
|
||||||
zoom >= 12 -> 20
|
|
||||||
# Medium zoom
|
|
||||||
zoom >= 8 -> 35
|
|
||||||
# Zoomed out
|
|
||||||
true -> 50
|
|
||||||
end
|
|
||||||
|
|
||||||
Enum.each(1..(total_batches - 1), fn batch_index ->
|
# Load all remaining batches immediately - no delays
|
||||||
# Linear delays instead of exponential
|
Enum.each(1..(total_batches - 1), fn batch_index ->
|
||||||
delay = base_delay * batch_index
|
send(self(), {:load_historical_batch, batch_index})
|
||||||
Process.send_after(self(), {:load_historical_batch, batch_index}, delay)
|
end)
|
||||||
end)
|
|
||||||
|
|
||||||
socket
|
socket
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Calculate optimal batch size based on zoom level
|
# 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()
|
@spec calculate_batch_size_for_zoom(integer()) :: integer()
|
||||||
# Very zoomed in - tiny batches for instant response
|
# High zoom - load everything at once (up to 500 packets)
|
||||||
defp calculate_batch_size_for_zoom(zoom) when zoom >= 15, do: 10
|
defp calculate_batch_size_for_zoom(zoom) when zoom >= 10, do: 500
|
||||||
# Moderately zoomed in - small batches
|
|
||||||
defp calculate_batch_size_for_zoom(zoom) when zoom >= 12, do: 20
|
|
||||||
# Medium zoom
|
# 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
|
# 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
|
# 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
|
# Calculate optimal number of batches based on zoom level
|
||||||
# Higher zoom = fewer batches needed since viewport is smaller
|
# 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)
|
batch_size = calculate_batch_size_for_zoom(zoom)
|
||||||
offset = batch_offset * batch_size
|
offset = batch_offset * batch_size
|
||||||
|
|
||||||
# Debug logging to see what bounds we're using
|
# Debug logging removed for performance
|
||||||
Logger.debug(
|
|
||||||
"Loading historical batch #{batch_offset} with zoom #{zoom}, batch_size #{batch_size}, bounds: #{inspect(bounds)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
packets_module = Application.get_env(:aprsme, :packets_module, Aprsme.Packets)
|
packets_module = Application.get_env(:aprsme, :packets_module, Aprsme.Packets)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue