New version with grafana

This commit is contained in:
erik 2025-05-23 08:11:11 +00:00
parent f86ad9a542
commit b2f649a489
6 changed files with 201 additions and 21 deletions

View file

@ -12,6 +12,8 @@ const tooltip = document.getElementById('tooltip');
let socket;
// Keep track of open chat windows: character_name -> DOM element
const chatWindows = {};
// Keep track of open stats windows: character_name -> DOM element
const statsWindows = {};
/* ---------- constants ------------------------------------------- */
const MAX_Z = 10;
@ -25,7 +27,8 @@ const MAP_BOUNDS = {
};
// Base path for tracker API endpoints; prefix API calls with '/api' when served behind a proxy
const API_BASE = '/api';
// If serving APIs at root, leave empty
const API_BASE = '';
// Maximum number of lines to retain in each chat window scrollback
const MAX_CHAT_LINES = 1000;
// Map numeric chat color codes to CSS hex colors
@ -134,6 +137,59 @@ function worldToPx(ew, ns) {
return { x, y };
}
// Show or create a stats window for a character
function showStatsWindow(name) {
if (statsWindows[name]) {
const existing = statsWindows[name];
existing.style.display = 'flex';
return;
}
const win = document.createElement('div');
win.className = 'stats-window';
win.dataset.character = name;
// Header (reuses chat-header styling)
const header = document.createElement('div');
header.className = 'chat-header';
const title = document.createElement('span');
title.textContent = `Stats: ${name}`;
const closeBtn = document.createElement('button');
closeBtn.className = 'chat-close-btn';
closeBtn.textContent = '×';
closeBtn.addEventListener('click', () => { win.style.display = 'none'; });
header.appendChild(title);
header.appendChild(closeBtn);
win.appendChild(header);
// Content container
const content = document.createElement('div');
content.className = 'chat-messages';
content.textContent = 'Loading stats...';
win.appendChild(content);
document.body.appendChild(win);
statsWindows[name] = win;
// Embed a 2×2 grid of Grafana solo-panel iframes for this character
content.innerHTML = '';
const panels = [
{ title: 'Kills per Hour', id: 1 },
{ title: 'Memory (MB)', id: 2 },
{ title: 'CPU (%)', id: 3 },
{ title: 'Mem Handles', id: 4 }
];
panels.forEach(p => {
const iframe = document.createElement('iframe');
iframe.src =
`/grafana/d-solo/dereth-tracker/dereth-tracker-dashboard` +
`?panelId=${p.id}` +
`&var-character=${encodeURIComponent(name)}` +
`&theme=light`;
iframe.setAttribute('title', p.title);
iframe.width = '350';
iframe.height = '200';
iframe.frameBorder = '0';
iframe.allowFullscreen = true;
content.appendChild(iframe);
});
}
const applyTransform = () =>
group.style.transform = `translate(${offX}px,${offY}px) scale(${scale})`;
@ -280,6 +336,15 @@ function render(players) {
showChatWindow(p.character_name);
});
li.appendChild(chatBtn);
// Stats button
const statsBtn = document.createElement('button');
statsBtn.className = 'stats-btn';
statsBtn.textContent = 'Stats';
statsBtn.addEventListener('click', e => {
e.stopPropagation();
showStatsWindow(p.character_name);
});
li.appendChild(statsBtn);
list.appendChild(li);
});
}

View file

@ -220,7 +220,7 @@ body {
}
/* ---------- chat window styling ------------------------------- */
.chat-btn {
.chat-btn, .stats-btn {
margin-top: 4px;
padding: 2px 6px;
background: var(--accent);
@ -231,7 +231,7 @@ body {
cursor: pointer;
}
.chat-window {
.chat-window, .stats-window {
position: absolute;
top: 10px;
/* position window to start just right of the sidebar */
@ -319,3 +319,24 @@ body.noselect, body.noselect * {
stroke-linecap: round;
stroke-linejoin: round;
}
/* -------------------------------------------------------- */
/* Stats window: 2×2 iframe grid and flexible height */
.stats-window {
/* allow height to expand to fit two rows of panels */
height: auto;
}
.stats-window .chat-messages {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: auto;
gap: 10px;
padding: 10px;
overflow: visible;
background: #f7f7f7;
color: #000;
}
.stats-window iframe {
width: 350px;
height: 200px;
border: none;
}