Files
esp32-web/static/js/main.js
user dfbd2a2196 feat: v0.1.4 — device intelligence dashboard
Add tabbed dashboard at /dashboard/ with three D3.js visualizations:
- Vendor treemap (devices grouped by type and vendor)
- SSID social graph (force-directed, shared probed SSIDs as edges)
- Fingerprint clusters (packed circles by device behavior)

Intelligence API endpoints at /api/v1/intelligence/ with param
validation. Dashboard built on htmx + Pico CSS dark theme + D3 v7,
all vendored locally (make vendor). 13 new tests (59 total).
2026-02-06 18:59:53 +01:00

59 lines
1.5 KiB
JavaScript

/* ESP32-Web Dashboard — tab switching & shared utilities */
document.addEventListener('DOMContentLoaded', () => {
initTabs();
});
function initTabs() {
const tabs = document.querySelectorAll('.tab-nav a');
tabs.forEach(tab => {
tab.addEventListener('click', (e) => {
e.preventDefault();
if (tab.classList.contains('active')) return;
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
// htmx handles the AJAX load via hx-get on the element
});
});
// Load first tab on page load
const first = document.querySelector('.tab-nav a');
if (first) {
first.click();
}
}
/* Shared D3 tooltip */
function createTooltip() {
let tip = document.querySelector('.d3-tooltip');
if (!tip) {
tip = document.createElement('div');
tip.className = 'd3-tooltip';
tip.style.display = 'none';
document.body.appendChild(tip);
}
return {
show(html, event) {
tip.innerHTML = html;
tip.style.display = 'block';
tip.style.left = (event.pageX + 12) + 'px';
tip.style.top = (event.pageY - 12) + 'px';
},
move(event) {
tip.style.left = (event.pageX + 12) + 'px';
tip.style.top = (event.pageY - 12) + 'px';
},
hide() {
tip.style.display = 'none';
}
};
}
/* Responsive SVG dimensions from container */
function getVizSize(container) {
return {
width: Math.max(container.clientWidth || container.parentElement.clientWidth, 300),
height: Math.max(container.clientHeight, 400)
};
}