push
This commit is contained in:
76
static/css/style.css
Normal file
76
static/css/style.css
Normal file
@@ -0,0 +1,76 @@
|
||||
:root {
|
||||
--bg-dark: #0d1117;
|
||||
--card-bg: #161b22;
|
||||
--border-color: #30363d;
|
||||
--text-main: #c9d1d9;
|
||||
--blue-accent: #58a6ff;
|
||||
}
|
||||
body {
|
||||
background-color: var(--bg-dark);
|
||||
color: var(--text-main);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.gauge-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.gauge-card {
|
||||
background-color: var(--card-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 12px;
|
||||
padding: 10px 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.gauge-canvas-container {
|
||||
max-width: 80px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.gauge-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--blue-accent);
|
||||
margin-top: 2px;
|
||||
}
|
||||
.voltage-value {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 800;
|
||||
color: #ffffff;
|
||||
}
|
||||
.time-btn-container {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
gap: 6px;
|
||||
padding-bottom: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
.time-btn {
|
||||
font-size: 0.75rem !important;
|
||||
padding: 5px 12px !important;
|
||||
white-space: nowrap;
|
||||
border-color: var(--border-color) !important;
|
||||
color: var(--blue-accent) !important;
|
||||
}
|
||||
.time-btn.active {
|
||||
background-color: #1f6feb !important;
|
||||
color: white !important;
|
||||
border-color: #1f6feb !important;
|
||||
}
|
||||
.main-chart-card {
|
||||
background-color: var(--card-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 12px;
|
||||
padding: 15px;
|
||||
height: 55vh;
|
||||
min-height: 350px;
|
||||
}
|
||||
footer { padding: 20px 0; opacity: 0.7; }
|
||||
@media (max-width: 576px) {
|
||||
.voltage-value { font-size: 0.95rem; }
|
||||
.main-chart-card { height: 50vh; padding: 10px; }
|
||||
}
|
||||
117
static/js/monitor.js
Normal file
117
static/js/monitor.js
Normal file
@@ -0,0 +1,117 @@
|
||||
const socket = io();
|
||||
let currentTimeRange = '6h';
|
||||
let phasesConfig = {};
|
||||
const gauges = {};
|
||||
let voltageChart = null;
|
||||
|
||||
const THRESHOLDS = { min: 207, max: 253 };
|
||||
|
||||
function initMonitor(phases, defaultRange) {
|
||||
phasesConfig = phases;
|
||||
currentTimeRange = defaultRange;
|
||||
|
||||
const gaugeConfig = {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [0, 100],
|
||||
backgroundColor: ['#198754', '#1a1d20'],
|
||||
borderWidth: 0,
|
||||
circumference: 180,
|
||||
rotation: 270
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
cutout: '75%',
|
||||
plugins: { legend: { display: false }, tooltip: { enabled: false } }
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys(phasesConfig).forEach(id => {
|
||||
const canvas = document.getElementById('gauge' + id);
|
||||
if (canvas) {
|
||||
gauges[id] = new Chart(canvas, JSON.parse(JSON.stringify(gaugeConfig)));
|
||||
updateGaugeUI(id, 230);
|
||||
}
|
||||
});
|
||||
|
||||
const ctxChart = document.getElementById('voltageChart');
|
||||
if (ctxChart) {
|
||||
voltageChart = new Chart(ctxChart, {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: Object.keys(phasesConfig).map(id => ({
|
||||
label: phasesConfig[id].label,
|
||||
data: [],
|
||||
borderColor: phasesConfig[id].color,
|
||||
backgroundColor: phasesConfig[id].color + '20',
|
||||
tension: 0.3,
|
||||
pointRadius: 0,
|
||||
borderWidth: 2
|
||||
}))
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
displayFormats: { hour: 'HH:mm', minute: 'HH:mm' },
|
||||
tooltipFormat: 'HH:mm'
|
||||
},
|
||||
grid: { color: '#2d3139' }
|
||||
},
|
||||
y: { min: 190, max: 270, grid: { color: '#2d3139' }, ticks: { stepSize: 10 } }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
socket.on('voltage_update', function(data) {
|
||||
Object.keys(phasesConfig).forEach(id => {
|
||||
const val = data['phase' + id];
|
||||
const textElement = document.getElementById('value' + id);
|
||||
if (val !== undefined && val !== null && val !== 0) {
|
||||
const numVal = parseFloat(val);
|
||||
if (textElement) textElement.textContent = numVal.toFixed(1) + 'V';
|
||||
updateGaugeUI(id, numVal);
|
||||
}
|
||||
});
|
||||
if (data.timestamp) {
|
||||
const date = new Date(data.timestamp);
|
||||
document.getElementById('lastUpdate').textContent = 'Odczyt: ' + date.toLocaleTimeString('pl-PL', {hour: '2-digit', minute:'2-digit', second:'2-digit', hour12: false});
|
||||
}
|
||||
});
|
||||
|
||||
window.changeTimeRange(currentTimeRange);
|
||||
}
|
||||
|
||||
function updateGaugeUI(id, val) {
|
||||
if (!gauges[id]) return;
|
||||
const percentage = Math.max(0, Math.min(100, ((val - 190) / 80) * 100));
|
||||
let color = '#198754';
|
||||
if (val < THRESHOLDS.min || val > THRESHOLDS.max) color = '#dc3545';
|
||||
else if (val < 212 || val > 248) color = '#ffc107';
|
||||
gauges[id].data.datasets[0].data = [percentage, 100 - percentage];
|
||||
gauges[id].data.datasets[0].backgroundColor = [color, '#1a1d20'];
|
||||
gauges[id].update('none');
|
||||
}
|
||||
|
||||
window.changeTimeRange = async function(range) {
|
||||
currentTimeRange = range;
|
||||
document.querySelectorAll('.time-btn').forEach(btn => btn.classList.remove('active'));
|
||||
const activeBtn = document.querySelector(`[data-range="${range}"]`);
|
||||
if (activeBtn) activeBtn.classList.add('active');
|
||||
if (!voltageChart) return;
|
||||
for (let i = 1; i <= Object.keys(phasesConfig).length; i++) {
|
||||
try {
|
||||
const response = await fetch(`/api/timeseries/${i}?range=${range}`);
|
||||
const data = await response.json();
|
||||
voltageChart.data.datasets[i-1].data = data.map(d => ({ x: new Date(d.time), y: d.voltage }));
|
||||
} catch (e) { console.error(e); }
|
||||
}
|
||||
voltageChart.update();
|
||||
};
|
||||
Reference in New Issue
Block a user