diff --git a/public/css/style.css b/public/css/style.css index 3b5b103..15511a0 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -586,7 +586,7 @@ input:checked+.slider:before { /* ---- Charts Section ---- */ .charts-section { display: grid; - grid-template-columns: 3fr 2fr; + grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 24px; } @@ -761,8 +761,8 @@ input:checked+.slider:before { } .globe-body { - flex: 1; - min-height: 280px; + height: 280px; /* Match chart-body height exactly */ + padding: 12px 22px; position: relative; overflow: hidden; cursor: grab; diff --git a/public/index.html b/public/index.html index ee9f3fb..69e1641 100644 --- a/public/index.html +++ b/public/index.html @@ -248,6 +248,20 @@
+ diff --git a/public/js/app.js b/public/js/app.js index 8e9c457..4e2c0f1 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -78,7 +78,9 @@ confirmNewPasswordInput: document.getElementById('confirmNewPassword'), btnChangePassword: document.getElementById('btnChangePassword'), changePasswordMessage: document.getElementById('changePasswordMessage'), - globeContainer: document.getElementById('globeContainer') + globeContainer: document.getElementById('globeContainer'), + globeTotalNodes: document.getElementById('globeTotalNodes'), + globeTotalRegions: document.getElementById('globeTotalRegions') }; // ---- State ---- @@ -373,9 +375,14 @@ } try { + const width = dom.globeContainer.clientWidth || 400; + const height = dom.globeContainer.clientHeight || 280; + myGlobe = Globe() (dom.globeContainer) - .globeImageUrl('//unpkg.com/three-globe/example/img/earth-dark.jpg') + .width(width) + .height(height) + .globeImageUrl('//unpkg.com/three-globe/example/img/earth-blue-marble.jpg') .bumpImageUrl('//unpkg.com/three-globe/example/img/earth-topology.png') .backgroundColor('rgba(0,0,0,0)') .showAtmosphere(true) @@ -396,20 +403,25 @@ `); - // Resizing + // Resizing with initial dimensions + myGlobe.width(dom.globeContainer.clientWidth).height(dom.globeContainer.clientHeight); + const resizeObserver = new ResizeObserver(() => { - if (myGlobe) { - const width = dom.globeContainer.clientWidth; - const height = dom.globeContainer.clientHeight; - myGlobe.width(width).height(height); + if (myGlobe && dom.globeContainer.clientWidth > 0) { + myGlobe.width(dom.globeContainer.clientWidth).height(dom.globeContainer.clientHeight); } }); resizeObserver.observe(dom.globeContainer); // Initial view myGlobe.controls().autoRotate = true; - myGlobe.controls().autoRotateSpeed = 0.5; - myGlobe.controls().enableZoom = false; // Disable zoom to maintain dashboard feel + myGlobe.controls().autoRotateSpeed = 1.2; // Slightly faster for visual appeal + myGlobe.controls().enableZoom = false; + + // Initial data sync if available + if (allServersData.length > 0) { + updateGlobe(allServersData); + } } catch (err) { console.error('[Globe] Initialization failed:', err); } @@ -435,6 +447,13 @@ myGlobe.pointsData(geoData); + // Update footer stats + if (dom.globeTotalNodes) dom.globeTotalNodes.textContent = geoData.length; + if (dom.globeTotalRegions) { + const regions = new Set(geoData.map(d => d.country)).size; + dom.globeTotalRegions.textContent = regions; + } + // Also add arcs for "traffic flow" if we have multiple servers // For now, let's just show rings or pulses for active traffic myGlobe.ringsData(geoData.filter(d => (d.netRx + d.netTx) > 1024 * 1024)); // Pulse for servers > 1MB/s