map tweaks
This commit is contained in:
parent
3b0c1213f4
commit
43d4792760
3 changed files with 139 additions and 33 deletions
|
|
@ -23,12 +23,22 @@ export class TrailManager {
|
|||
this.trails = new Map();
|
||||
this.showTrails = true;
|
||||
this.trailDuration = trailDuration;
|
||||
|
||||
// Ensure trail layer is added to the map and visible
|
||||
if (this.trailLayer && this.trailLayer.bringToFront) {
|
||||
setTimeout(() => this.trailLayer.bringToFront(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
setShowTrails(show: boolean) {
|
||||
this.showTrails = show;
|
||||
if (!show) {
|
||||
this.clearAllTrails();
|
||||
} else {
|
||||
// When re-enabling trails, recreate all trails immediately
|
||||
this.trails.forEach((trailState, baseCallsign) => {
|
||||
this.updateTrailVisualization(baseCallsign, trailState, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,8 +87,9 @@ export class TrailManager {
|
|||
});
|
||||
}
|
||||
|
||||
// Always update trail visualization
|
||||
this.updateTrailVisualization(baseCallsign, trailState);
|
||||
// Always update trail visualization, with immediate=true for historical dots
|
||||
// This ensures historical trails are immediately visible when loaded all at once
|
||||
this.updateTrailVisualization(baseCallsign, trailState, isHistoricalDot);
|
||||
}
|
||||
|
||||
private extractBaseCallsign(markerId: string | any): string {
|
||||
|
|
@ -97,7 +108,11 @@ export class TrailManager {
|
|||
return id;
|
||||
}
|
||||
|
||||
private updateTrailVisualization(baseCallsign: string, trailState: TrailState) {
|
||||
private updateTrailVisualization(
|
||||
baseCallsign: string,
|
||||
trailState: TrailState,
|
||||
immediate: boolean = false,
|
||||
) {
|
||||
// Remove old trail and dots
|
||||
if (trailState.trail) {
|
||||
this.trailLayer.removeLayer(trailState.trail);
|
||||
|
|
@ -113,14 +128,17 @@ export class TrailManager {
|
|||
const latLngs = trailState.positions.map((pos) => [pos.lat, pos.lng]);
|
||||
|
||||
// Create blue polyline connecting the historical position dots
|
||||
// For historical positions (immediate=true), use higher opacity for better visibility
|
||||
trailState.trail = L.polyline(latLngs, {
|
||||
color: "#1E90FF",
|
||||
weight: 3,
|
||||
opacity: 0.8,
|
||||
opacity: immediate ? 0.9 : 0.8,
|
||||
smoothFactor: 1,
|
||||
lineCap: "round",
|
||||
lineJoin: "round",
|
||||
className: "historical-trail-line",
|
||||
// Ensure the trail renders on top of other map elements
|
||||
zIndexOffset: immediate ? 1000 : 0,
|
||||
}).addTo(this.trailLayer);
|
||||
|
||||
// Don't create additional dots here since historical positions are now shown as markers
|
||||
|
|
|
|||
101
assets/js/map.ts
101
assets/js/map.ts
|
|
@ -305,9 +305,10 @@ let MapAPRSMap = {
|
|||
const currentZoom = self.map!.getZoom();
|
||||
const zoomDifference = self.lastZoom ? Math.abs(currentZoom - self.lastZoom) : 0;
|
||||
|
||||
// If zoom changed significantly (more than 2 levels), clear and reload
|
||||
// If zoom changed significantly (more than 2 levels), request reload of normal markers
|
||||
// but preserve historical ones and current position
|
||||
if (zoomDifference > 2) {
|
||||
self.pushEvent("clear_and_reload_markers", {});
|
||||
self.pushEvent("refresh_markers", {});
|
||||
}
|
||||
|
||||
self.sendBoundsToServer();
|
||||
|
|
@ -668,25 +669,15 @@ let MapAPRSMap = {
|
|||
self.markers!.delete(id);
|
||||
self.markerStates!.delete(id);
|
||||
|
||||
// Only remove trail if this was the only marker for this callsign
|
||||
if (self.trailManager && markerState) {
|
||||
const callsign = markerState.callsign_group || markerState.callsign || id;
|
||||
// Check if there are any live markers left for this callsign
|
||||
let hasLiveMarkers = false;
|
||||
self.markerStates!.forEach((state) => {
|
||||
const stateCallsign = state.callsign_group || state.callsign;
|
||||
if (stateCallsign === callsign && !state.historical) {
|
||||
hasLiveMarkers = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Only remove trail if no live markers remain
|
||||
if (!hasLiveMarkers) {
|
||||
self.trailManager.removeTrail(callsign);
|
||||
}
|
||||
}
|
||||
// We now NEVER remove trails when clearing historical packets
|
||||
// This preserves the historical trail visibility
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure trail layer is visible and on top
|
||||
if (self.trailLayer && self.trailLayer.bringToFront) {
|
||||
self.trailLayer.bringToFront();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle bounds-based marker filtering
|
||||
|
|
@ -708,7 +699,13 @@ let MapAPRSMap = {
|
|||
|
||||
// Handle clear_all_markers event
|
||||
self.handleEvent("clear_all_markers", () => {
|
||||
// Modified to preserve historical trails - only removes non-historical markers
|
||||
self.clearAllMarkers();
|
||||
|
||||
// Force trail layer to front to ensure visibility
|
||||
if (self.trailLayer && self.trailLayer.bringToFront) {
|
||||
self.trailLayer.bringToFront();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
@ -720,8 +717,9 @@ let MapAPRSMap = {
|
|||
const center = self.map!.getCenter();
|
||||
const zoom = self.map!.getZoom();
|
||||
|
||||
// Remove markers that are now outside the visible bounds
|
||||
self.removeMarkersOutsideBounds(bounds);
|
||||
// We're no longer removing markers outside bounds during normal panning/zooming
|
||||
// to preserve historical positions and the current marker
|
||||
// self.removeMarkersOutsideBounds(bounds);
|
||||
|
||||
self.pushEvent("bounds_changed", {
|
||||
bounds: {
|
||||
|
|
@ -825,6 +823,13 @@ let MapAPRSMap = {
|
|||
marker.addTo(self.markerLayer!);
|
||||
self.markers!.set(data.id, marker);
|
||||
|
||||
// Make sure historical markers and trails stay visible
|
||||
if (data.historical || data.is_most_recent_for_callsign) {
|
||||
if (self.trailLayer && self.trailLayer.bringToFront) {
|
||||
setTimeout(() => self.trailLayer.bringToFront(), 50);
|
||||
}
|
||||
}
|
||||
|
||||
// Store marker state for optimization
|
||||
self.markerStates!.set(data.id, {
|
||||
lat: lat,
|
||||
|
|
@ -923,13 +928,49 @@ let MapAPRSMap = {
|
|||
|
||||
clearAllMarkers() {
|
||||
const self = this as unknown as LiveViewHookContext;
|
||||
self.markerLayer!.clearLayers();
|
||||
|
||||
// Instead of clearing all markers, only remove non-historical and non-current markers
|
||||
const markersToPreserve = new Map();
|
||||
const statesToPreserve = new Map();
|
||||
|
||||
// Identify historical markers and most recent markers to preserve
|
||||
self.markers!.forEach((marker, id) => {
|
||||
const markerState = self.markerStates!.get(String(id));
|
||||
const isHistorical = (marker as any)._isHistorical || (markerState && markerState.historical);
|
||||
const isMostRecent = markerState && markerState.is_most_recent_for_callsign;
|
||||
|
||||
// Keep historical markers and current position markers
|
||||
if (isHistorical || isMostRecent) {
|
||||
markersToPreserve.set(String(id), marker);
|
||||
if (markerState) {
|
||||
statesToPreserve.set(String(id), markerState);
|
||||
}
|
||||
} else {
|
||||
// Remove only non-historical, non-current markers
|
||||
self.markerLayer!.removeLayer(marker);
|
||||
}
|
||||
});
|
||||
|
||||
// Replace the markers and states with just the preserved ones
|
||||
self.markers!.clear();
|
||||
self.markerStates!.clear();
|
||||
|
||||
// Clear all trails
|
||||
if (self.trailManager) {
|
||||
self.trailManager.clearAllTrails();
|
||||
markersToPreserve.forEach((marker, id) => {
|
||||
self.markers!.set(id, marker);
|
||||
});
|
||||
|
||||
statesToPreserve.forEach((state, id) => {
|
||||
self.markerStates!.set(id, state);
|
||||
});
|
||||
|
||||
// Don't clear trails - keep them visible
|
||||
// if (self.trailManager) {
|
||||
// self.trailManager.clearAllTrails();
|
||||
// }
|
||||
|
||||
// Make sure trail layer is on top
|
||||
if (self.trailLayer && self.trailLayer.bringToFront) {
|
||||
setTimeout(() => self.trailLayer.bringToFront(), 100);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -940,6 +981,16 @@ let MapAPRSMap = {
|
|||
const markersToRemove: string[] = [];
|
||||
|
||||
self.markers!.forEach((marker: L.Marker, id: string) => {
|
||||
// Check if this is a historical marker or the most recent marker for a callsign
|
||||
const markerState = self.markerStates!.get(String(id));
|
||||
const isHistorical = (marker as any)._isHistorical || (markerState && markerState.historical);
|
||||
const isMostRecent = markerState && markerState.is_most_recent_for_callsign;
|
||||
|
||||
// Always preserve historical markers and the most recent marker for a callsign
|
||||
if (isHistorical || isMostRecent) {
|
||||
return; // Skip this marker, don't remove it
|
||||
}
|
||||
|
||||
const position = marker.getLatLng();
|
||||
const lat = position.lat;
|
||||
const lng = position.lng;
|
||||
|
|
|
|||
|
|
@ -160,7 +160,26 @@ defmodule AprsWeb.MapLive.CallsignView do
|
|||
|> assign(packets_loaded: true)
|
||||
end
|
||||
|
||||
# Don't start historical replay yet - wait for bounds to be available
|
||||
# Immediately start historical replay without waiting for bounds
|
||||
# If bounds aren't available, use a default world bounds
|
||||
socket =
|
||||
if is_nil(socket.assigns.map_bounds) do
|
||||
# Use a default global bounds to ensure we get all historical points
|
||||
default_bounds = %{
|
||||
north: 90.0,
|
||||
south: -90.0,
|
||||
east: 180.0,
|
||||
west: -180.0
|
||||
}
|
||||
|
||||
socket = assign(socket, map_bounds: default_bounds)
|
||||
socket = start_historical_replay(socket)
|
||||
assign(socket, replay_started: true, replay_active: true)
|
||||
else
|
||||
# Bounds already available, use them
|
||||
socket = start_historical_replay(socket)
|
||||
assign(socket, replay_started: true, replay_active: true)
|
||||
end
|
||||
|
||||
# If we have a pending geolocation, zoom to it after a delay
|
||||
socket =
|
||||
|
|
@ -252,12 +271,30 @@ defmodule AprsWeb.MapLive.CallsignView do
|
|||
end
|
||||
|
||||
def handle_info(:auto_start_replay, socket) do
|
||||
if not socket.assigns.replay_started and socket.assigns.map_ready and
|
||||
not is_nil(socket.assigns.map_bounds) do
|
||||
# We now handle this in map_ready event, but keep this for backward compatibility
|
||||
# and in case auto_start_replay is triggered from elsewhere
|
||||
if socket.assigns.map_ready and not socket.assigns.replay_started do
|
||||
# Update socket with bounds if needed
|
||||
socket =
|
||||
if is_nil(socket.assigns.map_bounds) do
|
||||
# Use a default global bounds if needed
|
||||
default_bounds = %{
|
||||
north: 90.0,
|
||||
south: -90.0,
|
||||
east: 180.0,
|
||||
west: -180.0
|
||||
}
|
||||
|
||||
assign(socket, map_bounds: default_bounds)
|
||||
else
|
||||
socket
|
||||
end
|
||||
|
||||
socket = start_historical_replay(socket)
|
||||
{:noreply, assign(socket, replay_started: true, replay_active: true)}
|
||||
else
|
||||
if not socket.assigns.map_ready or is_nil(socket.assigns.map_bounds) do
|
||||
# Only retry if map isn't ready yet
|
||||
if not socket.assigns.map_ready do
|
||||
Process.send_after(self(), :auto_start_replay, 1000)
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue