diff --git a/assets/js/map.ts b/assets/js/map.ts index c7fc2df..774c8da 100644 --- a/assets/js/map.ts +++ b/assets/js/map.ts @@ -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(); + // Process all packets immediately for maximum speed + const packetsByCallsign = new Map(); - 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(); + }); }); } }); diff --git a/lib/aprsme_web/live/map_live/index.ex b/lib/aprsme_web/live/map_live/index.ex index 1733fd2..148dd0f 100644 --- a/lib/aprsme_web/live/map_live/index.ex +++ b/lib/aprsme_web/live/map_live/index.ex @@ -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)