Complete Beast format implementation with enhanced features and fixes #19
3 changed files with 68 additions and 9 deletions
Fix map centering to use calculated origin
Backend Changes: - Added OriginConfig struct to server package - Modified NewServer to accept origin configuration - Added /api/origin endpoint to serve origin data to frontend - Updated main.go to pass origin configuration to server Frontend Changes: - Modified initializeMap() to fetch origin from API before map creation - Updated initializeCoverageMap() to also use origin data - Added fallback coordinates in case API request fails - Maps now center on the calculated origin position instead of hardcoded coordinates The map now properly centers on the calculated average position of enabled sources (or manually configured origin), providing a much better user experience with appropriate regional view. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
commit
af9bf8ecac
|
|
@ -100,8 +100,19 @@ class SkyView {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map Initialization
|
// Map Initialization
|
||||||
initializeMap() {
|
async initializeMap() {
|
||||||
this.map = L.map('map').setView([51.4700, -0.4600], 10);
|
// Get origin from server
|
||||||
|
let origin = { latitude: 51.4700, longitude: -0.4600 }; // fallback
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/origin');
|
||||||
|
if (response.ok) {
|
||||||
|
origin = await response.json();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Could not fetch origin, using default:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.map = L.map('map').setView([origin.latitude, origin.longitude], 10);
|
||||||
|
|
||||||
// Dark tile layer
|
// Dark tile layer
|
||||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
||||||
|
|
@ -117,9 +128,20 @@ class SkyView {
|
||||||
document.getElementById('toggle-sources').addEventListener('click', () => this.toggleSources());
|
document.getElementById('toggle-sources').addEventListener('click', () => this.toggleSources());
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeCoverageMap() {
|
async initializeCoverageMap() {
|
||||||
if (!this.coverageMap) {
|
if (!this.coverageMap) {
|
||||||
this.coverageMap = L.map('coverage-map').setView([51.4700, -0.4600], 10);
|
// Get origin from server
|
||||||
|
let origin = { latitude: 51.4700, longitude: -0.4600 }; // fallback
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/origin');
|
||||||
|
if (response.ok) {
|
||||||
|
origin = await response.json();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Could not fetch origin for coverage map, using default:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.coverageMap = L.map('coverage-map').setView([origin.latitude, origin.longitude], 10);
|
||||||
|
|
||||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
||||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,20 @@ import (
|
||||||
"skyview/internal/merger"
|
"skyview/internal/merger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// OriginConfig represents the reference point configuration
|
||||||
|
type OriginConfig struct {
|
||||||
|
Latitude float64 `json:"latitude"`
|
||||||
|
Longitude float64 `json:"longitude"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Server handles HTTP requests and WebSocket connections
|
// Server handles HTTP requests and WebSocket connections
|
||||||
type Server struct {
|
type Server struct {
|
||||||
port int
|
port int
|
||||||
merger *merger.Merger
|
merger *merger.Merger
|
||||||
staticFiles embed.FS
|
staticFiles embed.FS
|
||||||
server *http.Server
|
server *http.Server
|
||||||
|
origin OriginConfig
|
||||||
|
|
||||||
// WebSocket management
|
// WebSocket management
|
||||||
wsClients map[*websocket.Conn]bool
|
wsClients map[*websocket.Conn]bool
|
||||||
|
|
@ -50,11 +58,12 @@ type AircraftUpdate struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer creates a new HTTP server
|
// NewServer creates a new HTTP server
|
||||||
func NewServer(port int, merger *merger.Merger, staticFiles embed.FS) *Server {
|
func NewServer(port int, merger *merger.Merger, staticFiles embed.FS, origin OriginConfig) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
port: port,
|
port: port,
|
||||||
merger: merger,
|
merger: merger,
|
||||||
staticFiles: staticFiles,
|
staticFiles: staticFiles,
|
||||||
|
origin: origin,
|
||||||
wsClients: make(map[*websocket.Conn]bool),
|
wsClients: make(map[*websocket.Conn]bool),
|
||||||
upgrader: websocket.Upgrader{
|
upgrader: websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
|
@ -107,6 +116,7 @@ func (s *Server) setupRoutes() http.Handler {
|
||||||
api.HandleFunc("/aircraft/{icao}", s.handleGetAircraftDetails).Methods("GET")
|
api.HandleFunc("/aircraft/{icao}", s.handleGetAircraftDetails).Methods("GET")
|
||||||
api.HandleFunc("/sources", s.handleGetSources).Methods("GET")
|
api.HandleFunc("/sources", s.handleGetSources).Methods("GET")
|
||||||
api.HandleFunc("/stats", s.handleGetStats).Methods("GET")
|
api.HandleFunc("/stats", s.handleGetStats).Methods("GET")
|
||||||
|
api.HandleFunc("/origin", s.handleGetOrigin).Methods("GET")
|
||||||
api.HandleFunc("/coverage/{sourceId}", s.handleGetCoverage).Methods("GET")
|
api.HandleFunc("/coverage/{sourceId}", s.handleGetCoverage).Methods("GET")
|
||||||
api.HandleFunc("/heatmap/{sourceId}", s.handleGetHeatmap).Methods("GET")
|
api.HandleFunc("/heatmap/{sourceId}", s.handleGetHeatmap).Methods("GET")
|
||||||
|
|
||||||
|
|
@ -180,6 +190,11 @@ func (s *Server) handleGetStats(w http.ResponseWriter, r *http.Request) {
|
||||||
json.NewEncoder(w).Encode(stats)
|
json.NewEncoder(w).Encode(stats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleGetOrigin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(s.origin)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) handleGetCoverage(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleGetCoverage(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
sourceID := vars["sourceId"]
|
sourceID := vars["sourceId"]
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,19 @@ class SkyView {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map Initialization
|
// Map Initialization
|
||||||
initializeMap() {
|
async initializeMap() {
|
||||||
this.map = L.map('map').setView([51.4700, -0.4600], 10);
|
// Get origin from server
|
||||||
|
let origin = { latitude: 51.4700, longitude: -0.4600 }; // fallback
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/origin');
|
||||||
|
if (response.ok) {
|
||||||
|
origin = await response.json();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Could not fetch origin, using default:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.map = L.map('map').setView([origin.latitude, origin.longitude], 10);
|
||||||
|
|
||||||
// Dark tile layer
|
// Dark tile layer
|
||||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
||||||
|
|
@ -117,9 +128,20 @@ class SkyView {
|
||||||
document.getElementById('toggle-sources').addEventListener('click', () => this.toggleSources());
|
document.getElementById('toggle-sources').addEventListener('click', () => this.toggleSources());
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeCoverageMap() {
|
async initializeCoverageMap() {
|
||||||
if (!this.coverageMap) {
|
if (!this.coverageMap) {
|
||||||
this.coverageMap = L.map('coverage-map').setView([51.4700, -0.4600], 10);
|
// Get origin from server
|
||||||
|
let origin = { latitude: 51.4700, longitude: -0.4600 }; // fallback
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/origin');
|
||||||
|
if (response.ok) {
|
||||||
|
origin = await response.json();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Could not fetch origin for coverage map, using default:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.coverageMap = L.map('coverage-map').setView([origin.latitude, origin.longitude], 10);
|
||||||
|
|
||||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
||||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue