diff --git a/static/css/modes/gps.css b/static/css/modes/gps.css index 92bf2fc..cd7449f 100644 --- a/static/css/modes/gps.css +++ b/static/css/modes/gps.css @@ -189,6 +189,36 @@ display: block; } +.gps-globe-sat-icon { + --sat-size: 18px; + --sat-color: #8ea6bd; + width: var(--sat-size); + height: var(--sat-size); + transform: translate(-50%, -50%); + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 50%; + border: 1px solid var(--sat-color); + background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, 0.22), rgba(7, 14, 23, 0.82) 72%); + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35), 0 0 12px var(--sat-color); +} + +.gps-globe-sat-icon img { + width: 76%; + height: 76%; + object-fit: contain; +} + +.gps-globe-sat-icon.used { + opacity: 0.98; +} + +.gps-globe-sat-icon.unused { + opacity: 0.72; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35), 0 0 6px var(--sat-color); +} + .gps-sky-label { position: absolute; transform: translate(-50%, -50%); diff --git a/static/images/globe/satellite-icon.svg b/static/images/globe/satellite-icon.svg new file mode 100644 index 0000000..3245e9b --- /dev/null +++ b/static/images/globe/satellite-icon.svg @@ -0,0 +1,50 @@ + diff --git a/static/js/modes/gps.js b/static/js/modes/gps.js index 6ea23fa..b066440 100644 --- a/static/js/modes/gps.js +++ b/static/js/modes/gps.js @@ -38,6 +38,7 @@ const GPS = (function() { 'https://cdn.jsdelivr.net/npm/globe.gl@2.33.1/dist/globe.gl.min.js', ]; const GPS_GLOBE_TEXTURE_URL = '/static/images/globe/earth-dark.jpg'; + const GPS_SATELLITE_ICON_URL = '/static/images/globe/satellite-icon.svg'; function init() { const initPromise = initSkyRenderer(); @@ -227,19 +228,14 @@ const GPS = (function() { .pointAltitude('altitude') .pointColor('color') .pointLabel(point => point.label || '') - .pointsTransitionDuration(260) - .arcColor('color') - .arcAltitude('altitude') - .arcStroke('stroke') - .arcDashLength('dashLength') - .arcDashGap('dashGap') - .arcDashInitialGap('dashInitialGap') - .arcDashAnimateTime('dashAnimateTime'); + .pointsTransitionDuration(0) + .htmlAltitude('altitude') + .htmlElementsData([]) + .htmlElement((sat) => createSatelliteIconElement(sat)); const controls = globe.controls(); if (controls) { - controls.autoRotate = true; - controls.autoRotateSpeed = 0.22; + controls.autoRotate = false; controls.enablePan = false; controls.minDistance = 130; controls.maxDistance = 420; @@ -271,7 +267,7 @@ const GPS = (function() { const observer = getObserverCoords(); const points = []; - const arcs = []; + const satelliteIcons = []; if (observer) { points.push({ @@ -284,7 +280,7 @@ const GPS = (function() { }); } - lastSatellites.forEach((sat, index) => { + lastSatellites.forEach((sat) => { const azimuth = Number(sat.azimuth); const elevation = Number(sat.elevation); if (!observer || !Number.isFinite(azimuth) || !Number.isFinite(elevation)) return; @@ -292,34 +288,20 @@ const GPS = (function() { const color = CONST_COLORS[sat.constellation] || CONST_COLORS.GPS; const shellAltitude = getSatelliteShellAltitude(sat.constellation, elevation); const footprint = projectSkyTrackToEarth(observer.lat, observer.lon, azimuth, elevation); - const label = buildSatelliteLabel(sat); - - points.push({ + satelliteIcons.push({ lat: footprint.lat, lng: footprint.lon, altitude: shellAltitude, - radius: sat.used ? 0.34 : 0.26, - color: sat.used ? color : hexToRgba(color, 0.66), - label: label, - }); - - arcs.push({ - startLat: observer.lat, - startLng: observer.lon, - endLat: footprint.lat, - endLng: footprint.lon, - color: [hexToRgba(color, 0.55), hexToRgba(color, 0.08)], - altitude: Math.max(0.12, shellAltitude * 0.55), - stroke: sat.used ? 0.62 : 0.36, - dashLength: sat.used ? 0.82 : 0.56, - dashGap: sat.used ? 0.58 : 1.1, - dashInitialGap: (index % 12) / 12, - dashAnimateTime: sat.used ? 2200 : 3400, + color: color, + used: !!sat.used, + sizePx: sat.used ? 20 : 17, + title: buildSatelliteTitle(sat), + iconUrl: GPS_SATELLITE_ICON_URL, }); }); globe.pointsData(points); - globe.arcsData(arcs); + globe.htmlElementsData(satelliteIcons); if (observer && !hasInitialView) { globe.pointOfView({ lat: observer.lat, lng: observer.lon, altitude: 1.6 }, 950); @@ -327,6 +309,23 @@ const GPS = (function() { } } + function createSatelliteIconElement(sat) { + const marker = document.createElement('div'); + marker.className = `gps-globe-sat-icon ${sat.used ? 'used' : 'unused'}`; + marker.style.setProperty('--sat-color', sat.color || '#9fb2c5'); + marker.style.setProperty('--sat-size', `${Math.max(12, Number(sat.sizePx) || 18)}px`); + marker.title = sat.title || 'Satellite'; + + const img = document.createElement('img'); + img.src = sat.iconUrl || GPS_SATELLITE_ICON_URL; + img.alt = 'Satellite'; + img.decoding = 'async'; + img.draggable = false; + + marker.appendChild(img); + return marker; + } + function setSatellites(satellites) { lastSatellites = Array.isArray(satellites) ? satellites : []; renderGlobe(); @@ -355,22 +354,15 @@ const GPS = (function() { }; } - function buildSatelliteLabel(sat) { - const constellation = escapeHtml(sat.constellation || 'GPS'); - const prn = escapeHtml(String(sat.prn || '--')); + function buildSatelliteTitle(sat) { + const constellation = String(sat.constellation || 'GPS'); + const prn = String(sat.prn || '--'); const elevation = Number.isFinite(Number(sat.elevation)) ? `${Number(sat.elevation).toFixed(1)}\u00b0` : '--'; const azimuth = Number.isFinite(Number(sat.azimuth)) ? `${Number(sat.azimuth).toFixed(1)}\u00b0` : '--'; const snr = Number.isFinite(Number(sat.snr)) ? `${Math.round(Number(sat.snr))} dB-Hz` : 'n/a'; const used = sat.used ? 'USED IN FIX' : 'TRACKED'; - return ` -