Availability
${line.availability.toFixed(1)}%
Performance
${line.performance.toFixed(1)}%
Quality
${line.quality.toFixed(1)}%
`;
container.innerHTML += card;
});
};
// --- CHARTING LOGIC ---
const createOrUpdateChart = (ctx, type, data, options) => {
if (!ctx) return;
const chartId = ctx.id;
if (chartInstances[chartId]) chartInstances[chartId].destroy();
chartInstances[chartId] = new Chart(ctx, { type, data, options });
};
const renderCharts = () => {
// OEE Components by Line
createOrUpdateChart(document.getElementById('oeeComponentsChart'), 'bar', {
labels: productionLines.map(p => p.name),
datasets: [
{ label: 'Availability', data: productionLines.map(p => p.availability), backgroundColor: '#3b82f6' },
{ label: 'Performance', data: productionLines.map(p => p.performance), backgroundColor: '#16a34a' },
{ label: 'Quality', data: productionLines.map(p => p.quality), backgroundColor: '#f59e0b' },
]
}, { responsive: true, maintainAspectRatio: false, scales: { y: { max: 100, min: 0 } } });
// Downtime Reasons Chart
const sortedDowntime = Object.entries(downtimeReasons).sort(([,a],[,b]) => b-a).slice(0, 5);
createOrUpdateChart(document.getElementById('downtimeReasonsChart'), 'bar', {
labels: sortedDowntime.map(d => d[0]),
datasets: [{ label: 'Minutes', data: sortedDowntime.map(d => d[1]), backgroundColor: '#ef4444' }]
}, { responsive: true, maintainAspectRatio: false, indexAxis: 'y', plugins: { legend: { display: false } } });
// OEE Trend Chart
const today = new Date();
const labels = Array.from({length: 7}, (_, i) => {
const d = new Date();
d.setDate(today.getDate() - (6 - i));
return d;
});
const datasets = [{
label: 'Average OEE',
data: Array.from({length: 7}, (_, i) => {
let totalOEE = 0;
productionLines.forEach(line => {
totalOEE += line.oeeHistory[i];
});
return totalOEE / productionLines.length;
}),
borderColor: '#1d4ed8',
tension: 0.3,
fill: true,
backgroundColor: 'rgba(29, 78, 216, 0.1)'
}];
createOrUpdateChart(document.getElementById('oeeTrendChart'), 'line', {
labels: labels,
datasets: datasets
}, { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'day' } }, y: { min: 50, max: 100 } } });
};
// --- FORM HANDLING ---
const populateLineSelect = () => {
if (!lineSelect) return;
lineSelect.innerHTML = productionLines.map(p => `
`).join('');
updateFormForSelectedLine();
};
const updateFormForSelectedLine = () => {
const selectedId = lineSelect.value;
const line = productionLines.find(p => p.id === selectedId);
if (line) {
document.getElementById('line-id-input').value = line.id;
document.getElementById('line-status').value = line.status;
document.getElementById('line-availability').value = line.availability;
document.getElementById('line-performance').value = line.performance;
document.getElementById('line-quality').value = line.quality;
}
};
lineSelect.addEventListener('change', updateFormForSelectedLine);
productionForm.addEventListener('submit', (e) => {
e.preventDefault();
const id = document.getElementById('line-id-input').value;
const index = productionLines.findIndex(p => p.id === id);
if (index !== -1) {
const line = productionLines[index];
line.status = document.getElementById('line-status').value;
line.availability = parseFloat(document.getElementById('line-availability').value);
line.performance = parseFloat(document.getElementById('line-performance').value);
line.quality = parseFloat(document.getElementById('line-quality').value);
// Recalculate OEE
line.oee = (line.availability / 100) * (line.performance / 100) * (line.quality / 100) * 100;
// Update last point in history
line.oeeHistory[line.oeeHistory.length - 1] = line.oee;
}
renderAll();
alert('Production line data updated successfully.');
});
resetDataBtn.addEventListener('click', () => { if (confirm('Reset all data to sample data?')) init(); });
// --- PDF DOWNLOAD ---
downloadPdfBtn.addEventListener('click', () => {
const { jsPDF } = window.jspdf;
const content = document.getElementById('dashboard-content-to-print');
html2canvas(content, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
const imgProps = pdf.getImageProperties(imgData);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
pdf.save('Manufacturing_OEE_Dashboard.pdf');
});
});
// --- INITIALIZATION ---
const init = () => {
generateSampleData();
renderAll();
updateNavButtons();
};
init();
});