- Add extractCoordinate helper to recursively extract coordinates
- Handle coordinates that come as nested arrays like [[lat]]
- Log raw coordinate values when validation fails for debugging
- Prevents Invalid coordinates errors in console
This handles edge cases where coordinates are wrapped in arrays
before being passed to the marker creation code.
- Check if data object exists before accessing properties
- Validate lat/lng are numbers, not just truthy values
- Prevents TypeError when clustering tries to access undefined coordinates
- Fixes: Error adding historical packet: TypeError: can't access property x of undefined
- Remove duplicate time formatting function in components.ex
- Use existing time_ago_in_words from TimeHelpers instead of custom format_time_ago
- Remove unnecessary Float multiplication in format_coordinates
- Changed Float.round(lat * 1.0, 4) to Float.round(lat, 4)
- Fix TypeScript type safety issues
- Add pendingMarkers to LiveViewHookContext interface
- Add initializationTimeout property for proper cleanup
- Add cleanup for map initialization retry timeout
- Prevent memory leak by clearing timeout in destroyed() method
- Format code with mix format
All changes maintain backward compatibility while improving code quality.
- Check if markerClusterGroup is ready before removing markers
- Verify _map and _topClusterLevel exist in cluster group
- Add try-catch blocks to handle removal errors gracefully
- Clean up tracking maps even if layer removal fails
- Prevents 'can't access property "_childClusters"' errors
- Add marker queuing system for markers that arrive before map is ready
- Check map._container and getZoom to ensure internal structures exist
- Process pending markers after map.whenReady() callback
- Fix typo: bindTooltip -> bindTooltip
The errorTileUrl was set to a base64 data URL of a transparent 1x1 PNG,
which caused browsers to fail when trying to use it as a tile replacement.
Removing this option allows Leaflet to handle tile errors with its
default behavior, which is more robust and prevents console errors.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The function was being called before it was defined, causing a runtime error.
Moving the function definition before the whenReady callback ensures it's
available when the callback executes.
- Add clearRfPathLines() method for centralized cleanup logic
- Clear RF paths when clearing all markers
- Clear RF paths in destroyed() lifecycle hook
- Add error handling to prevent failures during cleanup
- Fix issue where path lines could persist after hover ends
- Added sendBoundsToServer() call after map_ready event
- Previously only saveMapState was called which doesn't send bounds
- This ensures historical packets are loaded on initial page load
- Also added to retry logic for reliability
The issue was that bounds_changed event was never triggered on initial load, preventing historical packets from being fetched.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Increased spiderfyDistanceMultiplier from 2 to 3.5
- Provides much better separation when overlapping markers are clicked
- Markers now spread out 3.5x the default distance for easier clicking
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Reduced nearbyDistance from 100 to 20 pixels to only spider truly overlapping markers
- Added spiderfyDistanceMultiplier: 2 to increase separation when markers do spider
- Added leg color configuration for better visibility
- Fixes issue where distant markers like K5FDT-R were incorrectly grouped with AE5PL stations
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Increased nearbyDistance from 60 to 100 pixels for maximum clickability
- Increased circleSpiralSwitchover from 12 to 15 markers
- Provides even better separation when clicking on densely packed APRS packets
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Increased nearbyDistance from 40 to 60 pixels for better clickability
- Increased circleSpiralSwitchover from 9 to 12 markers before switching to spiral layout
- Improves user experience when clicking on overlapping APRS packets
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Improves robustness by adding fallback logic when is_most_recent_for_callsign
is undefined or null. In edge cases where this server-side property might not
be reliably set, falls back to the previous behavior of excluding historical
markers using the _isHistorical flag.
Changes:
- Added explicit boolean checks for is_most_recent_for_callsign === true
- Added fallback logic: if property is null/undefined, use \!_isHistorical
- Applied to both addMarker() and zoom handler functions
- Ensures spidering works even if server-side property is inconsistent
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The OverlappingMarkerSpiderfier (OMS) was incorrectly configured to exclude
historical markers but wasn't properly filtering for only the most recent
packets with icons. This caused spidering functionality to break.
Changes:
- Updated addMarker() to check data.is_most_recent_for_callsign instead of \!_isHistorical
- Updated zoom handler to check markerState.is_most_recent_for_callsign when re-adding markers to OMS
- Ensures only current position markers (with APRS icons) participate in spidering
- Historical markers (red dots) are excluded from spidering as intended
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Only include actual current position icons in the OverlappingMarkerSpiderfier,
not historical trail points. This prevents historical positions from spidering
out when clicked.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed extra closing brace that was prematurely ending the try block
and causing build failure.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed VectorGrid from map.ts, now using only raster tiles
- Removed VectorGrid from vendor bundle build scripts
- Removed VectorGrid TypeScript definitions
- Removed VectorGrid JavaScript file
- Rebuilt all vendor bundles without VectorGrid
- Simplified tile layer creation to use only OpenStreetMap raster tiles
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix race condition in map bundle loading by waiting for script to load before initializing map
- Ensure Leaflet is properly exposed as window.L in map bundle
- Add Leaflet availability check in map initialization function
- Disable Exq background jobs in development environment to remove Redis dependency
- Remove invalid TelemetryMetricsPrometheus plug from endpoint
- Application now starts successfully without Redis in development mode
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed "Leaflet library failed to load" error by deferring window.L access
- Changed map.ts to access window.L dynamically instead of at module load time
- Added const L = window.L; inside functions that use Leaflet
- This allows the vendor bundle to load asynchronously before map initialization
The issue was that the TypeScript module was trying to access window.L
immediately when imported, before the vendor bundle had loaded Leaflet.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Disabled vector tiles by setting useVectorTiles to false.
The application will now use OpenStreetMap raster tiles instead.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add comprehensive mobile viewport meta tags for better mobile experience
- Implement touch gesture support with long-press to show station info
- Create mobile-specific CSS with touch target optimization (44px minimum)
- Add safe area insets support for notched devices
- Position zoom controls at bottom-right on mobile for thumb accessibility
- Optimize map performance on mobile with canvas renderer
- Fix desktop sidebar toggle button clipping when slideover is open
- Improve responsive design for slideover panels and popups
- Add landscape mode and high DPI screen optimizations
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add retry logic with exponential backoff for failed tiles (up to 3 attempts)
- Configure tile layer with optimized settings (keepBuffer, updateInterval)
- Add support for alternative tile providers (OSM DE, CartoDB)
- Update CSP to allow alternative tile providers
- Add error tile placeholder to prevent broken images
This should help with partial tile loading issues by retrying failed requests
and providing fallback options.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed the esbuild errors during Docker build where npm packages couldn't
be resolved. The issue was caused by node_modules being excluded from
the Docker build context in .dockerignore.
Implemented a proper vendor bundle strategy following Phoenix 1.7+ patterns:
- Created vendor.js that bundles all npm dependencies (Leaflet, Chart.js,
topbar) and their CSS files into a single pre-built bundle
- Added vendor esbuild profile in config.exs with proper CSS/image loaders
- Updated mix.exs to build vendor bundle before app bundle in assets.deploy
- Modified JavaScript imports to use globally loaded libraries from vendor
bundle instead of importing from node_modules
- Added vendor.js script tag to root.html.heex before app.js
This approach avoids Docker build failures by pre-bundling all vendor
dependencies, eliminating the need for node_modules during production builds.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Moved CSS imports from Tailwind config to JavaScript to let ESBuild handle them.
This fixes the Docker build error where Tailwind couldn't resolve node_modules paths.
- Removed CSS @import statements from app.css
- Added CSS imports to map.ts where Leaflet is used
- Configured ESBuild to handle CSS and image files
- Added missing topbar package to package.json
- Updated both dev and prod ESBuild configs
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
When changing trail duration and historical data settings, historical positions
would show up on the map but trail lines wouldn't connect them. This was caused
by a mismatch between trail ID generation and callsign extraction.
## Changes
- Fix getTrailId() to properly extract base callsigns from historical marker IDs
- Add setTrailDuration() method to TrailManager for dynamic duration updates
- Add LiveView event to synchronize trail duration changes with client
- Add comprehensive tests for historical ID handling
## Problem
Historical markers have IDs like "hist_CALLSIGN_123" but getTrailId() was
returning the full ID while TrailManager.extractBaseCallsign() extracted just
"CALLSIGN", creating separate trails instead of connected ones.
## Solution
Updated getTrailId() to extract base callsigns from historical IDs using the
same logic as TrailManager, ensuring all positions from the same station use
the same trail ID and connect properly.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed "can't access property 'invalidateSize', e.map is undefined" error
that occurred when navigating away from the map page while a setTimeout
was still trying to access the destroyed map.
Changes:
- Added check for self.map and self.isDestroyed before invalidating map size
- Stored timeout references in a cleanupTimeouts array
- Added cleanup code in destroyed() function to clear all pending timeouts
- Updated TypeScript type definition to include cleanupTimeouts property
This prevents attempting to access the map object after it has been
destroyed during page navigation.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed all console.log debugging statements from app.js (theme changes, chart rendering)
- Removed all console.log statements from map.ts (map initialization, data processing)
- Removed all console.debug statements from map_helpers.ts
- Removed all console.debug statements from map_fixes.ts
- Kept essential console.error and console.warn statements for error handling
- Reduced bundle size by ~1.4kb
This cleanup removes unnecessary debug output while maintaining error reporting
for production debugging via console.error and Sentry.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed console.log for "Adding hover handlers for RF packet"
- Removed console.log for "Marker hover start"
- Removed console.log for "Marker hover end"
These were debug statements that are no longer needed.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix "this.__view is undefined" error when calling pushEvent in event handlers
- Bind pushEvent context properly in all marker click and hover handlers
- Replace undefined sendBoundsToServer calls with saveMapState
- Ensure all event handlers check for pushEvent availability and type
- Use .bind(self) to preserve LiveView hook context in callbacks
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add comprehensive type definitions for Leaflet plugins (heatmap, marker clustering, overlapping marker spiderfier)
- Create event payload interfaces for all LiveView events
- Add marker extension types for APRS-specific properties
- Define Chart.js dataset and configuration types
- Replace 74 instances of 'any' type across all TypeScript files
- Improve type safety for event handlers and state management
- Add proper typing for external library integrations
This refactoring enhances type safety throughout the codebase, making it easier to catch errors at compile time and improving IDE support for autocompletion and refactoring.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>