Files
stupidsimcpp/web/script.js
2025-11-07 13:03:36 -05:00

218 lines
7.0 KiB
JavaScript

let autoRefreshInterval = null;
let currentMode = 'gradient';
function refreshImage() {
const img = document.getElementById('displayImage');
// Check if server has finished encoding
fetch('/api/image-ready')
.then(response => response.json())
.then(data => {
if (data.ready) {
performSmoothImageSwap();
} else {
// Try again in 1 second
setTimeout(refreshImage, 1000);
}
})
.catch(error => {
console.error('Error checking image status:', error);
updateStatus('Error checking image status', 'error');
});
}
function performSmoothImageSwap() {
const img = document.getElementById('displayImage');
const newImage = new Image();
newImage.onload = function() {
// Crossfade transition
img.style.opacity = '0';
setTimeout(() => {
img.src = './output/display.jxl';
img.style.opacity = '1';
updateStatus('Image refreshed at ' + new Date().toLocaleTimeString());
}, 300);
};
newImage.onerror = function() {
updateStatus('Error loading image', 'error');
};
// Load with cache busting only when we know it's ready
newImage.src = './output/display.jxl?' + new Date().getTime();
}
function refreshTerrain() {
fetch('/api/refresh-terrain', { method: 'POST' })
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
refreshImage();
} else {
updateStatus('Error refreshing terrain', 'error');
}
})
.catch(error => {
console.error('Error refreshing terrain:', error);
updateStatus('Error refreshing terrain', 'error');
});
}
function toggleAutoRefresh() {
const button = document.getElementById('autoRefreshBtn');
if (autoRefreshInterval) {
clearInterval(autoRefreshInterval);
autoRefreshInterval = null;
button.textContent = 'Start Auto-Refresh';
button.classList.remove('danger');
updateStatus('Auto-refresh stopped');
} else {
// Faster refresh for terrain (5 seconds)
autoRefreshInterval = setInterval(currentMode === 'terrain' ? refreshTerrain : refreshImage, 100);
button.textContent = 'Stop Auto-Refresh';
button.classList.add('danger');
updateStatus('Auto-refresh started');
}
}
function switchMode() {
fetch('/api/switch-mode', { method: 'POST' })
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
currentMode = data.mode;
updateModeDisplay();
refreshImage();
updateStatus('Switched to ' + data.mode + ' mode');
// Restart auto-refresh if active
if (autoRefreshInterval) {
clearInterval(autoRefreshInterval);
autoRefreshInterval = setInterval(currentMode === 'terrain' ? refreshTerrain : refreshImage, 5000);
}
} else {
updateStatus('Error switching mode', 'error');
}
})
.catch(error => {
console.error('Error switching mode:', error);
updateStatus('Error switching mode', 'error');
});
}
function updateModeDisplay() {
const modeDisplay = document.getElementById('modeDisplay');
const switchBtn = document.getElementById('switchModeBtn');
const refreshBtn = document.getElementById('refreshBtn');
if (modeDisplay) {
modeDisplay.textContent = 'Current Mode: ' + currentMode;
}
if (switchBtn) {
switchBtn.textContent = 'Switch to ' + (currentMode === 'gradient' ? 'Terrain' : 'Gradient');
}
if (refreshBtn) {
if (currentMode === 'terrain') {
refreshBtn.textContent = 'Refresh Terrain';
refreshBtn.onclick = refreshTerrain;
} else {
refreshBtn.textContent = 'Refresh Image';
refreshBtn.onclick = refreshImage;
}
}
}
function showStats() {
fetch('/api/timing-stats')
.then(response => response.json())
.then(data => {
displayStats(data);
document.getElementById('statsPanel').style.display = 'block';
})
.catch(error => {
console.error('Error fetching stats:', error);
updateStatus('Error loading stats', 'error');
});
}
function hideStats() {
document.getElementById('statsPanel').style.display = 'none';
}
function clearStats() {
fetch('/api/clear-stats', { method: 'POST' })
.then(response => response.json())
.then(data => {
updateStatus('Statistics cleared');
hideStats();
})
.catch(error => {
console.error('Error clearing stats:', error);
updateStatus('Error clearing stats', 'error');
});
}
function displayStats(stats) {
const statsContent = document.getElementById('statsContent');
if (stats.length === 0) {
statsContent.innerHTML = '<p>No timing data available.</p>';
return;
}
let html = '<table class="stats-table">';
html += '<tr><th>Function</th><th>Calls</th><th>Total (s)</th><th>Avg (s)</th><th>Min (s)</th><th>Max (s)</th><th>Median (s)</th><th>P90 (s)</th><th>P95 (s)</th><th>P99 (s)</th></tr>';
stats.forEach(stat => {
html += `<tr>
<td>${stat.function}</td>
<td>${stat.call_count}</td>
<td>${parseFloat(stat.total_time).toFixed(6)}</td>
<td>${parseFloat(stat.avg_time).toFixed(6)}</td>
<td>${parseFloat(stat.min_time).toFixed(6)}</td>
<td>${parseFloat(stat.max_time).toFixed(6)}</td>
<td>${parseFloat(stat.median_time).toFixed(6)}</td>
<td>${parseFloat(stat.p90_time).toFixed(6)}</td>
<td>${parseFloat(stat.p95_time).toFixed(6)}</td>
<td>${parseFloat(stat.p99_time).toFixed(6)}</td>
</tr>`;
});
html += '</table>';
statsContent.innerHTML = html;
}
function updateStatus(message, type = 'info') {
const statusEl = document.getElementById('status');
statusEl.textContent = message;
statusEl.className = `status ${type}`;
// Auto-hide after 5 seconds
setTimeout(() => {
statusEl.textContent = '';
statusEl.className = 'status';
}, 5000);
}
// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
// Check if we're in all mode and get current mode
fetch('/api/current-mode')
.then(response => response.json())
.then(data => {
if (data.mode) {
currentMode = data.mode;
updateModeDisplay();
}
refreshImage();
})
.catch(error => {
// If endpoint doesn't exist, we're not in all mode
console.log('Not in all mode, using default');
refreshImage();
});
});