cleanup
This commit is contained in:
parent
8d5bfe127e
commit
dadfef8a5b
2 changed files with 10 additions and 124 deletions
|
|
@ -1,114 +0,0 @@
|
||||||
# Virtual Marker Scrolling for Large Datasets
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
When dealing with thousands of APRS markers on the map, rendering all markers at once can cause performance issues. Virtual scrolling for map markers is a technique where only visible markers within the viewport (plus a buffer zone) are rendered.
|
|
||||||
|
|
||||||
## Current Implementation
|
|
||||||
|
|
||||||
The current implementation already has some optimizations:
|
|
||||||
1. Viewport-based filtering in `get_recent_packets_optimized/3`
|
|
||||||
2. Marker state tracking to prevent unnecessary updates
|
|
||||||
3. Batch processing of historical packets
|
|
||||||
|
|
||||||
## Proposed Virtual Scrolling Enhancement
|
|
||||||
|
|
||||||
### 1. Marker Clustering at Low Zoom Levels
|
|
||||||
```typescript
|
|
||||||
// Use Leaflet.markercluster for automatic clustering
|
|
||||||
// Already included in the project but not fully utilized
|
|
||||||
if (self.map.getZoom() < 10) {
|
|
||||||
// Use marker clustering
|
|
||||||
self.clusterLayer = L.markerClusterGroup({
|
|
||||||
maxClusterRadius: 80,
|
|
||||||
spiderfyOnMaxZoom: true,
|
|
||||||
showCoverageOnHover: false,
|
|
||||||
zoomToBoundsOnClick: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Quadtree-based Spatial Indexing
|
|
||||||
```elixir
|
|
||||||
defmodule AprsmeWeb.MapLive.QuadTree do
|
|
||||||
@moduledoc """
|
|
||||||
Quadtree implementation for efficient spatial queries
|
|
||||||
"""
|
|
||||||
|
|
||||||
defstruct [:bounds, :markers, :children, :max_markers]
|
|
||||||
|
|
||||||
def insert(tree, marker) do
|
|
||||||
# Insert marker into appropriate quadrant
|
|
||||||
end
|
|
||||||
|
|
||||||
def query(tree, bounds) do
|
|
||||||
# Return only markers within bounds
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Progressive Rendering with RequestIdleCallback
|
|
||||||
```typescript
|
|
||||||
function renderMarkersProgressively(markers: MarkerData[]) {
|
|
||||||
let index = 0;
|
|
||||||
const batchSize = 50;
|
|
||||||
|
|
||||||
function renderBatch() {
|
|
||||||
const batch = markers.slice(index, index + batchSize);
|
|
||||||
batch.forEach(marker => self.addMarker(marker));
|
|
||||||
index += batchSize;
|
|
||||||
|
|
||||||
if (index < markers.length) {
|
|
||||||
requestIdleCallback(renderBatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
requestIdleCallback(renderBatch);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Server-side Aggregation
|
|
||||||
```elixir
|
|
||||||
def aggregate_markers_for_zoom(zoom_level, bounds) do
|
|
||||||
case zoom_level do
|
|
||||||
z when z < 8 ->
|
|
||||||
# Return aggregated grid cells with counts
|
|
||||||
Packets.get_grid_aggregates(bounds, grid_size: 50)
|
|
||||||
|
|
||||||
z when z < 12 ->
|
|
||||||
# Return simplified markers (no popups)
|
|
||||||
Packets.get_simplified_markers(bounds)
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
# Return full markers
|
|
||||||
Packets.get_recent_packets_optimized(bounds)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Viewport Buffer Strategy
|
|
||||||
```typescript
|
|
||||||
// Render markers in expanded viewport to reduce re-renders during panning
|
|
||||||
const bounds = self.map.getBounds();
|
|
||||||
const bufferedBounds = bounds.pad(0.5); // 50% buffer
|
|
||||||
```
|
|
||||||
|
|
||||||
## Implementation Priority
|
|
||||||
|
|
||||||
1. **Phase 1**: Implement marker clustering (easiest, biggest impact)
|
|
||||||
2. **Phase 2**: Add server-side aggregation for low zoom levels
|
|
||||||
3. **Phase 3**: Implement progressive rendering
|
|
||||||
4. **Phase 4**: Add quadtree spatial indexing if still needed
|
|
||||||
|
|
||||||
## Performance Metrics to Track
|
|
||||||
|
|
||||||
- Time to first marker render
|
|
||||||
- Frame rate during pan/zoom
|
|
||||||
- Memory usage with 10k+ markers
|
|
||||||
- Server query time by zoom level
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- The current implementation already handles viewport filtering well
|
|
||||||
- Virtual scrolling is most beneficial when dealing with 5000+ markers
|
|
||||||
- Consider implementing only if performance issues are reported by users
|
|
||||||
|
|
@ -164,16 +164,16 @@ defmodule Aprsme.PacketConsumer do
|
||||||
%{}
|
%{}
|
||||||
)
|
)
|
||||||
|
|
||||||
Logger.info("Batch processing completed",
|
# Logger.info("Batch processing completed",
|
||||||
batch_result:
|
# batch_result:
|
||||||
LogSanitizer.log_data(
|
# LogSanitizer.log_data(
|
||||||
packet_count: length(packets),
|
# packet_count: length(packets),
|
||||||
duration_ms: duration,
|
# duration_ms: duration,
|
||||||
success_count: success_count,
|
# success_count: success_count,
|
||||||
error_count: error_count,
|
# error_count: error_count,
|
||||||
memory_diff_bytes: memory_diff
|
# memory_diff_bytes: memory_diff
|
||||||
)
|
# )
|
||||||
)
|
# )
|
||||||
end
|
end
|
||||||
|
|
||||||
defp process_chunk(packets) do
|
defp process_chunk(packets) do
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue