Files
radiacode/web/static/js/cps.js
Jacquin Antoine c764a5c264 Dash web: crosshair, zoom/pan X, scale log/lin, continuum extraction, background resume
- Tooltip entier (intersect:false) + ligne verticale crosshair sur tous les graphes
- Zoom molette/pinch sur l'axe X, pan souris, limites clamped 30-3000 keV
- Toggle échelle log/linéaire onglet Background
- Extraction continuum détecteur (isotope peaks subtracted + Gaussian smoothing)
- Reprise snapshot précédent au démarrage capture_background.py
- Suppression refs "Théorique" et "Bruit capteur" de l'interface
- Plugin chartjs-plugin-zoom + hammerjs via CDN
- Fix Chart constructor spread operator

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 23:26:28 +02:00

119 lines
4.0 KiB
JavaScript

let cpsChart = null;
async function loadCps(hours = 24) {
// Highlight active button
document.querySelectorAll('.controls button').forEach(b => b.style.opacity = '0.6');
const activeBtn = [...document.querySelectorAll('.controls button')].find(
b => b.textContent.includes(hours <= 24 ? `${hours}h` : `${hours/24}j`) || (hours === 168 && b.textContent === '7j')
);
if (activeBtn) activeBtn.style.opacity = '1';
try {
const resp = await fetch(`${API_BASE}/api/cps/timeline?hours=${hours}`);
if (!resp.ok) return;
const data = await resp.json();
if (!data.data_points || data.data_points.length === 0) {
return;
}
const labels = data.data_points.map(d => d.ts);
const cpsValues = data.data_points.map(d => d.cps);
updateCpsChart(labels, cpsValues);
} catch {}
}
function updateCpsChart(labels, values) {
const ctx = document.getElementById('cps-chart').getContext('2d');
const chartData = {
labels: labels,
datasets: [{
label: 'CPS',
data: values,
borderColor: '#4caf50',
backgroundColor: 'rgba(76, 175, 80, 0.1)',
borderWidth: 1.5,
pointRadius: 0,
fill: true,
tension: 0.3,
}]
};
const options = {
responsive: true,
maintainAspectRatio: false,
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { labels: { color: '#e0e0e0' } },
tooltip: {
enabled: true,
mode: 'index',
intersect: false,
filter: (item) => item.raw != null,
callbacks: {
title: (items) => {
const d = new Date(items[0].parsed.x / 1000);
return d.toLocaleString('fr-FR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
},
label: (item) => `${item.dataset.label}: ${item.raw.toFixed(2)}`
}
},
zoom: {
pan: {
enabled: true,
mode: 'x',
modifierKey: null,
},
zoom: {
wheel: { enabled: true },
pinch: { enabled: true },
drag: { enabled: false },
mode: 'x',
onZoom: () => { document.getElementById('reset-zoom-cps').style.display = 'inline-block'; }
}
}
},
scales: {
x: {
type: 'time',
time: {
tooltipFormat: 'dd/MM HH:mm',
displayFormats: { minute: 'HH:mm', hour: 'HH:mm', day: 'dd/MM' }
},
title: { display: true, text: 'Temps', color: '#888' },
ticks: { color: '#888', maxTicksLimit: 12 },
grid: { color: '#333' },
},
y: {
title: { display: true, text: 'CPS', color: '#888' },
ticks: { color: '#888' },
grid: { color: '#333' },
beginAtZero: true,
}
}
};
if (cpsChart) {
cpsChart.data = chartData;
cpsChart.options = options;
cpsChart.update();
} else {
// Chart.js needs the date adapter for time axis
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js';
script.onload = () => {
cpsChart = new Chart(ctx, { type: 'line', data: chartData, ...options });
};
document.head.appendChild(script);
}
}
// Reset zoom
document.getElementById('reset-zoom-cps')?.addEventListener('click', () => {
if (cpsChart) {
cpsChart.resetZoom();
document.getElementById('reset-zoom-cps').style.display = 'none';
}
});