<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>페라스타 제품 중간조건 안정성시험 결과</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', sans-serif;
margin: 0;
padding: 20px;
background-color: #f9fafb;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
width: 100%;
max-width: 1000px;
background: white;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 30px;
}
h2 {
text-align: center;
color: #1f2937;
margin-bottom: 30px;
font-size: 24px;
position: relative;
}
.pdf-btn {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
padding: 8px 16px;
background-color: #dc2626;
color: white;
text-decoration: none;
border-radius: 6px;
font-weight: 600;
cursor: pointer;
border: none;
font-size: 14px;
transition: background-color 0.2s;
}
.pdf-btn:hover {
background-color: #b91c1c;
}
.chart-container {
position: relative;
height: 500px;
margin-bottom: 40px;
}
.info {
text-align: center;
margin-top: 20px;
margin-bottom: 30px;
color: #6b7280;
font-size: 14px;
}
.download-btn {
display: inline-block;
padding: 12px 24px;
background-color: #2563eb;
color: white;
text-decoration: none;
border-radius: 6px;
font-weight: 600;
cursor: pointer;
border: none;
font-size: 14px;
transition: background-color 0.2s;
margin: 20px 0;
}
.download-btn:hover {
background-color: #1d4ed8;
}
.download-container {
text-align: center;
margin: 30px 0;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
font-size: 14px;
}
th, td {
border: 1px solid #d1d5db;
padding: 12px;
text-align: center;
}
th {
background-color: #f3f4f6;
font-weight: 600;
color: #374151;
}
tr:hover {
background-color: #f9fafb;
}
.check-mark {
color: #22c55e;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<h2>
페라스타 제품 중간조건 안정성시험 결과
<button class="pdf-btn" onclick="downloadPDF()">📄 PDF 다운로드</button>
</h2>
<div class="chart-container">
<canvas id="contentChart"></canvas>
</div>
<div class="info">
<p>허용범위: 90~110% (5.04% ~ 6.16%)</p>
</div>
<div class="download-container">
<button class="download-btn" onclick="downloadChart()">📊 그래프 PNG로 다운로드</button>
</div>
<table>
<thead>
<tr>
<th>시점</th>
<th>평균 함량 (%)</th>
<th>함량 범위 (%)</th>
<th>기준 대비 (%)</th>
<th>허용범위 적합성</th>
<th>초기 대비 감소율</th>
</tr>
</thead>
<tbody>
<tr>
<td>0개월</td>
<td>5.95</td>
<td>5.92-5.97</td>
<td>106.3%</td>
<td><span class="check-mark">✓</span> 적합</td>
<td>-</td>
</tr>
<tr>
<td>1개월</td>
<td>5.88</td>
<td>5.84-5.91</td>
<td>105.0%</td>
<td><span class="check-mark">✓</span> 적합</td>
<td>1.2%</td>
</tr>
<tr>
<td>2개월</td>
<td>5.32</td>
<td>5.32</td>
<td>95.0%</td>
<td><span class="check-mark">✓</span> 적합</td>
<td>10.6%</td>
</tr>
<tr>
<td>3개월</td>
<td>5.25</td>
<td>5.25</td>
<td>93.8%</td>
<td><span class="check-mark">✓</span> 적합</td>
<td>11.8%</td>
</tr>
<tr>
<td>4개월</td>
<td>5.16</td>
<td>5.16</td>
<td>92.1%</td>
<td><span class="check-mark">✓</span> 적합</td>
<td>13.3%</td>
</tr>
<tr>
<td>5개월</td>
<td>5.11</td>
<td>5.10-5.11</td>
<td>91.3%</td>
<td><span class="check-mark">✓</span> 적합</td>
<td>14.1%</td>
</tr>
<tr>
<td>6개월</td>
<td>5.08</td>
<td>5.07-5.08</td>
<td>90.7%</td>
<td><span class="check-mark">✓</span> 적합 (하한 근접)</td>
<td>14.6%</td>
</tr>
</tbody>
</table>
</div>
<script>
const ctx = document.getElementById('contentChart').getContext('2d');
const data = {
labels: ['0개월', '1개월', '2개월', '3개월', '4개월', '5개월', '6개월'],
datasets: [
{
label: '평균 함량',
data: [5.95, 5.88, 5.32, 5.25, 5.16, 5.11, 5.08],
borderColor: '#2563eb',
backgroundColor: '#2563eb',
borderWidth: 3,
pointRadius: 4,
pointHoverRadius: 6,
tension: 0
},
{
label: '함량 범위 상한',
data: [5.97, 5.91, 5.32, 5.25, 5.16, 5.11, 5.08],
borderColor: '#94a3b8',
backgroundColor: '#94a3b8',
borderWidth: 1.5,
pointRadius: 2,
borderDash: [3, 3],
tension: 0
},
{
label: '함량 범위 하한',
data: [5.92, 5.84, 5.32, 5.25, 5.16, 5.10, 5.07],
borderColor: '#94a3b8',
backgroundColor: '#94a3b8',
borderWidth: 1.5,
pointRadius: 2,
borderDash: [3, 3],
tension: 0
}
]
};
const config = {
type: 'line',
data: data,
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'bottom',
labels: {
usePointStyle: true,
pointStyle: 'circle',
padding: 20
}
},
tooltip: {
callbacks: {
label: function(context) {
return context.dataset.label + ': ' + context.parsed.y + '%';
}
}
},
annotation: {
annotations: {
upperLimit: {
type: 'line',
yMin: 6.16,
yMax: 6.16,
borderColor: '#ef4444',
borderWidth: 2,
borderDash: [5, 5]
},
lowerLimit: {
type: 'line',
yMin: 5.04,
yMax: 5.04,
borderColor: '#ef4444',
borderWidth: 2,
borderDash: [5, 5]
},
baseline: {
type: 'line',
yMin: 5.6,
yMax: 5.6,
borderColor: '#22c55e',
borderWidth: 2
}
}
}
},
scales: {
y: {
min: 2,
max: 8,
title: {
display: true,
text: '평균 함량 (%)',
font: {
size: 14
}
},
grid: {
color: '#e5e7eb'
}
},
x: {
title: {
display: true,
text: '시간 (개월)',
font: {
size: 14
}
},
grid: {
color: '#e5e7eb'
}
}
}
}
};
// Chart.js의 annotation 플러그인을 사용하지 않고 직접 선 그리기
const chart = new Chart(ctx, config);
// 수동으로 참조선 그리기
const originalDraw = chart.draw;
chart.draw = function() {
originalDraw.apply(this, arguments);
const ctx = this.ctx;
const yAxis = this.scales.y;
const xAxis = this.scales.x;
// 상한선 (6.16%)
ctx.save();
ctx.strokeStyle = '#ef4444';
ctx.lineWidth = 2;
ctx.setLineDash([5, 5]);
ctx.beginPath();
const upperY = yAxis.getPixelForValue(6.16);
ctx.moveTo(xAxis.left, upperY);
ctx.lineTo(xAxis.right, upperY);
ctx.stroke();
// 하한선 (5.04%)
ctx.beginPath();
const lowerY = yAxis.getPixelForValue(5.04);
ctx.moveTo(xAxis.left, lowerY);
ctx.lineTo(xAxis.right, lowerY);
ctx.stroke();
// 기준선 (5.6%)
ctx.setLineDash([]);
ctx.strokeStyle = '#22c55e';
ctx.beginPath();
const baseY = yAxis.getPixelForValue(5.6);
ctx.moveTo(xAxis.left, baseY);
ctx.lineTo(xAxis.right, baseY);
ctx.stroke();
ctx.restore();
};
chart.update();
// PNG 다운로드 함수
function downloadChart() {
const canvas = document.getElementById('contentChart');
const url = canvas.toDataURL('image/png');
const link = document.createElement('a');
link.download = '페라스타_안정성시험_결과.png';
link.href = url;
link.click();
}
// PDF 다운로드 함수
async function downloadPDF() {
const { jsPDF } = window.jspdf;
const container = document.querySelector('.container');
// html2canvas로 컨테이너를 이미지로 변환
const canvas = await html2canvas(container, {
scale: 2,
useCORS: true,
logging: false
});
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: 'a4'
});
const imgWidth = 210; // A4 width in mm
const imgHeight = (canvas.height * imgWidth) / canvas.width;
pdf.addImage(imgData, 'PNG', 0, 0, imgWidth, imgHeight);
pdf.save('페라스타_안정성시험_결과.pdf');
}
</script>
</body>
</html>
업무일지; 완료프로젝트 참조.