fix: globe rendering, CPU sizing, manual location support

- Fix globe destroyed on re-render by preserving canvas DOM node across
  renderLocationCard() calls instead of recreating from scratch
- Reduce globe.gl camera minDistance (180->120) so globe is visible in
  200px container
- Clear stale globeInstance ref when canvas is gone
- Enlarge CPU gauge (90->110px), percentage label (18->22px), core bars
  (24->48px height), and detail text (11->12px)
- JS fetchLocation() now supplements server response with client-side
  ObserverLocation.getShared() from localStorage when server returns
  'default' or 'none', picking up manual coordinates from settings modal
- Location priority: GPS > config env vars > manual (localStorage) > default

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-02-27 00:00:51 +00:00
parent 4b31474080
commit f679433ac0
2 changed files with 50 additions and 18 deletions

View File

@@ -134,8 +134,8 @@
.sys-gauge-arc {
position: relative;
width: 90px;
height: 90px;
width: 110px;
height: 110px;
flex-shrink: 0;
}
@@ -168,7 +168,7 @@
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 18px;
font-size: 22px;
font-weight: 700;
font-family: var(--font-mono, 'JetBrains Mono', monospace);
color: var(--text-primary, #e0e0ff);
@@ -176,25 +176,25 @@
.sys-gauge-details {
flex: 1;
font-size: 11px;
font-size: 12px;
}
/* Per-core bars */
.sys-core-bars {
display: flex;
gap: 3px;
gap: 4px;
align-items: flex-end;
height: 24px;
margin-top: 8px;
height: 48px;
margin-top: 12px;
}
.sys-core-bar {
flex: 1;
background: var(--bg-primary, #0d0d1a);
border-radius: 2px;
border-radius: 3px;
position: relative;
min-width: 4px;
max-width: 16px;
min-width: 6px;
max-width: 32px;
height: 100%;
}

View File

@@ -153,7 +153,7 @@ const SystemHealth = (function () {
coreHtml = '<div class="sys-core-bars">';
cpu.per_core.forEach(function (c) {
var cls = barClass(c);
var h = Math.max(2, Math.round(c / 100 * 24));
var h = Math.max(3, Math.round(c / 100 * 48));
coreHtml += '<div class="sys-core-bar"><div class="sys-core-bar-fill ' + cls +
'" style="height:' + h + 'px;background:var(--accent-' +
(cls === 'ok' ? 'green' : cls === 'warn' ? 'yellow' : 'red') +
@@ -384,11 +384,23 @@ const SystemHealth = (function () {
var el = document.getElementById('sysCardLocation');
if (!el) return;
// Preserve the globe DOM node if it already has a canvas
var existingGlobe = document.getElementById('sysGlobeContainer');
var savedGlobe = null;
if (existingGlobe && existingGlobe.querySelector('canvas')) {
savedGlobe = existingGlobe;
existingGlobe.parentNode.removeChild(existingGlobe);
}
var html = '<div class="sys-card-header">Location &amp; Weather</div><div class="sys-card-body">';
html += '<div class="sys-location-inner">';
// Globe container
html += '<div class="sys-globe-wrap" id="sysGlobeContainer"></div>';
// Globe placeholder (will be replaced with saved node or initialized fresh)
if (!savedGlobe) {
html += '<div class="sys-globe-wrap" id="sysGlobeContainer"></div>';
} else {
html += '<div id="sysGlobePlaceholder"></div>';
}
// Details below globe
html += '<div class="sys-location-details">';
@@ -437,8 +449,13 @@ const SystemHealth = (function () {
html += '</div>';
el.innerHTML = html;
// Initialize globe after DOM is ready
setTimeout(function () { initGlobe(); }, 50);
// Re-insert saved globe or initialize fresh
if (savedGlobe) {
var placeholder = document.getElementById('sysGlobePlaceholder');
if (placeholder) placeholder.parentNode.replaceChild(savedGlobe, placeholder);
} else {
setTimeout(function () { initGlobe(); }, 100);
}
}
// -----------------------------------------------------------------------
@@ -477,9 +494,14 @@ const SystemHealth = (function () {
var container = document.getElementById('sysGlobeContainer');
if (!container || globeDestroyed) return;
// Don't reinitialize if globe is already in this container
// Don't reinitialize if globe canvas is still alive in this container
if (globeInstance && container.querySelector('canvas')) return;
// Clear stale reference if canvas was destroyed by innerHTML replacement
if (globeInstance && !container.querySelector('canvas')) {
globeInstance = null;
}
ensureGlobeLibrary().then(function (ready) {
if (!ready || typeof window.Globe !== 'function' || globeDestroyed) return;
@@ -505,8 +527,8 @@ const SystemHealth = (function () {
controls.autoRotate = true;
controls.autoRotateSpeed = 0.5;
controls.enablePan = false;
controls.minDistance = 180;
controls.maxDistance = 400;
controls.minDistance = 120;
controls.maxDistance = 300;
}
// Size the globe
@@ -732,6 +754,16 @@ const SystemHealth = (function () {
fetch('/system/location')
.then(function (r) { return r.json(); })
.then(function (data) {
// If server only has default/none, check client-side saved location
if ((data.source === 'default' || data.source === 'none') &&
window.ObserverLocation && ObserverLocation.getShared) {
var shared = ObserverLocation.getShared();
if (shared && shared.lat && shared.lon) {
data.lat = shared.lat;
data.lon = shared.lon;
data.source = 'manual';
}
}
locationData = data;
updateSidebarLocation();
renderLocationCard();