🐛 Fixed Issues:
- CTRL+Drag Required: Panels now require holding CTRL key to drag
* Cursor changes to 'grab' hand when CTRL is held
* Prevents accidental moves when using dropdowns/sliders
* Visual feedback with tooltip 'Hold CTRL and drag to reposition'
* Default cursor when CTRL not pressed
- Persistent Panel Positions: Positions correctly saved and restored
* Panel positions persist when toggling plugin off/on
* Each panel has independent localStorage key
* Positions restored from localStorage on plugin enable
* Positions saved on drag end
- Proper Cleanup on Disable: All controls removed when plugin disabled
* Fixed 'WSPR Activity' popup remaining after disable
* Fixed multiple popup spawning bug
* All controls properly cleaned up: filterControl, statsControl, legendControl, chartControl, heatmapLayer
* Added console logging for debugging cleanup process
* Controls only created when enabled=true
🔧 Technical Changes:
- Updated makeDraggable() function with CTRL key detection
- Added keydown/keyup listeners for CTRL key state
- Updated cursor dynamically based on CTRL key state
- Enhanced cleanup useEffect with individual control removal
- Added proper state reset for all controls
- Fixed control recreation logic to prevent duplicates
📝 Documentation:
- Updated README.md with v1.4.1 fixes
- Added CTRL+Drag usage instructions
- Documented persistent position behavior
- Added cleanup behavior notes
Version: 1.3.0 → 1.4.1
User-requested enhancements:
🖱️ Draggable Control Panels:
- ALL 4 control panels now draggable (Filter, Stats, Legend, Chart)
- Click and drag any panel to reposition
- Position saved to localStorage automatically
- Panels remember their position between sessions
- Smooth drag with opacity feedback
- Storage keys: wspr-filter-position, wspr-stats-position, etc.
- Prevents accidental dragging of inputs/selects
🗺️ Working Heatmap Implementation:
- Heatmap toggle now functional (was UI-only)
- Shows activity "hot spots" as gradient circles
- Color-coded by station count:
- Red: Very high activity (>7 stations)
- Orange: High activity (5-7 stations)
- Yellow: Moderate activity (3-5 stations)
- Blue: Low activity (<3 stations)
- Circle radius scales with activity level (20-50px base)
- Click hot spots for station count details
- Respects SNR threshold filter
- Smooth opacity transitions
- 0.1° grid aggregation for performance
🔧 Technical Implementation:
- makeDraggable() helper function
- Handles mousedown/mousemove/mouseup events
- Converts Leaflet control position to fixed positioning
- JSON storage for x/y coordinates
- Prevents dragging from interactive elements
- Heatmap algorithm:
- Aggregates TX/RX stations by location
- Counts activity per 0.1° grid cell
- Normalizes intensity (0-1 scale)
- Creates L.circle overlays with gradients
- Efficient rendering (only unique locations)
📊 Heatmap Features:
- Toggle on/off in filter panel
- Works with all other filters (band, time, SNR)
- Popup shows station count per hot spot
- Respects global opacity slider
- Automatic cleanup on disable
- Separate layer management (doesn't interfere with paths)
🎨 UX Improvements:
- Panels convert to fixed positioning when dragged
- Cursor changes to 'move' on hover
- Drag handle on entire panel (except inputs)
- Opacity feedback during drag (0.8)
- Smooth transitions back to opacity 1.0
- Console logging for debugging (heatmap toggle, render count)
🐛 Bug Fixes:
- Heatmap checkbox now actually works
- Added console.log for toggle debugging
- Proper layer cleanup on mode switch
- Fixed heatmap/path view switching
📝 Storage Format:
localStorage['wspr-filter-position'] = {"top":100,"left":200"}
localStorage['wspr-stats-position'] = {"top":50,"left":50"}
localStorage['wspr-legend-position'] = {"top":500,"left":900"}
localStorage['wspr-chart-position'] = {"top":450,"left":50"}
Version: 1.3.0 → 1.4.0
Files: useWSPR.js (+110 lines)
Features: +2 major (draggable, heatmap)
Resolves user issues:
✅ "clicking the heat map doesn't seem to do anything" - FIXED
✅ "popup windows be movable" - DONE
✅ "remember where on the screen they were moved to" - DONE
Fixed critical bug causing map to render as black screen:
🐛 Bug Fix:
- Added comprehensive coordinate validation before great circle calculation
- Prevents NaN (Not a Number) errors that caused Leaflet crashes
- Validates all coordinates are finite numbers before processing
🛡️ Safeguards Added:
- Input validation: Check coordinates exist and are valid numbers
- Distance check: Use simple line for points < 0.5 degrees apart
- Math clamping: Clamp cosine values to [-1, 1] to avoid Math.acos NaN
- Antipodal check: Handle opposite-side-of-Earth edge cases
- Output validation: Verify all generated points are finite
- Fallback: Return simple line if great circle calculation fails
🔍 Edge Cases Handled:
- Same location (distance = 0)
- Very close points (< 0.5 degrees)
- Antipodal points (opposite sides of Earth)
- Invalid/missing coordinates in API data
- NaN propagation from bad input
📝 Logging:
- Console warnings for invalid data (debugging)
- Skips bad spots gracefully without crashing
- Continues processing valid spots
Error message fixed:
"Error: Invalid LatLng object: (NaN, NaN)"
The map now renders correctly with curved propagation paths!
Major enhancements to WSPR Propagation Heatmap plugin:
🌍 Great Circle Paths:
- Replaced straight lines with curved great circle routes
- Follows Earth's curvature for realistic propagation visualization
- 30-point interpolation for smooth arcs
- Removes dashed line style for cleaner appearance
📊 Statistics Display:
- Real-time activity counter (top-left corner)
- Shows: Propagation paths, TX stations, RX stations, total stations
- Updates dynamically as data refreshes
- Dark themed for minimal distraction
📈 Signal Strength Legend:
- Color-coded SNR legend (bottom-right corner)
- 5 signal strength categories with dB ranges
- Helps users quickly interpret propagation quality
- Matches path colors exactly
🎨 UI Improvements:
- Removed dashed lines for smoother appearance
- Enhanced opacity handling for all elements
- Better contrast with white marker borders
- Professional dark theme for overlays
📚 Documentation:
- Created comprehensive README.md in wspr/ directory
- Documented all features, API, usage, troubleshooting
- Included roadmap for future enhancements
- Added developer guide and customization examples
🔧 Technical Improvements:
- Great circle path calculation algorithm
- Leaflet custom control integration
- Proper control cleanup on disable
- No memory leaks with control management
Version bumped: 1.0.0 → 1.1.0
All features fully self-contained in plugin layer
- Added /api/wspr/heatmap endpoint to server.js for fetching WSPR spots from PSK Reporter
- Created useWSPR.js plugin with real-time propagation path visualization
- Features:
- Path lines between TX and RX stations color-coded by SNR
- Signal strength visualization (red=weak, green=strong)
- Automatic refresh every 5 minutes
- Displays up to 500 most recent spots (last 30 minutes)
- Band filtering support (20m, 40m, etc.)
- Detailed popups showing TX/RX info, frequency, SNR, age
- Plugin fully self-contained in layers/ directory per project architecture
- Registered in layerRegistry.js for Settings panel integration
- Zero changes required to core WorldMap component
Data source: PSK Reporter API (WSPR mode)
Category: Propagation
Default: Disabled (user can enable in Settings → Map Layers)
- Added /api/wspr/heatmap endpoint to fetch global WSPR spots via PSK Reporter
- Created useWSPR.js plugin with real-time propagation visualization
- Displays color-coded propagation paths based on SNR (signal strength)
- Shows TX (orange) and RX (blue) station markers with tooltips
- Supports band filtering and 30-minute lookback window
- Auto-refreshes every 5 minutes with caching
- Registered plugin in layerRegistry for Settings panel access
Features:
- Path lines color-coded: red (weak) → yellow → green (strong)
- Line weight varies with signal strength
- Detailed popups showing TX/RX callsigns, frequency, SNR, and age
- Performance-optimized with 500-spot limit
- Compatible with existing plugin architecture (enable/disable, opacity control)
This plugin enables real-time visualization of global HF propagation conditions
by showing WSPR beacon paths and signal strengths across all bands.