<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Project Happiness Index</title>
<style>
.chart-container {
max-width: 800px;
margin: 20px auto;
background: white;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 20px;
font-family: Arial, sans-serif;
}
.chart-header {
text-align: center;
margin-bottom: 20px;
}
.chart-title {
font-size: 24px;
font-weight: bold;
color: #333;
margin-bottom: 15px;
}
.download-btn {
background: #007cba;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.3s;
}
.download-btn:hover {
background: #005a87;
}
.chart-canvas {
display: block;
margin: 0 auto;
border: 1px solid #ddd;
border-radius: 8px;
}
.chart-description {
margin-top: 15px;
text-align: center;
color: #666;
font-style: italic;
}
@media (max-width: 768px) {
.chart-container {
padding: 15px;
margin: 10px;
}
.chart-title {
font-size: 20px;
}
.chart-canvas {
max-width: 100%;
height: auto;
}
}
</style>
</head>
<body>
<div class="chart-container">
<div class="chart-header">
<h2 class="chart-title">AI Project Happiness Index: The Emotional Rollercoaster</h2>
<button class="download-btn" onclick="downloadChart()">📥 Download PNG</button>
</div>
<canvas id="happinessChart" class="chart-canvas" width="800" height="600"></canvas>
<div class="chart-description">
The emotional journey of every AI project developer - from excitement to existential crisis! 😅
</div>
</div>
<script>
// Chart data
const data = [
{ stage: 'Start', happiness: 90, x: 0 },
{ stage: 'Early\nProgress', happiness: 70, x: 1 },
{ stage: 'Mid\nProgress', happiness: 50, x: 2 },
{ stage: 'Expected\nDeadline', happiness: 30, x: 3 },
{ stage: 'Post\nDeadline', happiness: 20, x: 4 },
{ stage: 'Extended\nDelay', happiness: 10, x: 5 }
];
function drawChart() {
const canvas = document.getElementById('happinessChart');
const ctx = canvas.getContext('2d');
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// White background
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Chart dimensions
const padding = 80;
const chartWidth = canvas.width - 2 * padding;
const chartHeight = canvas.height - 2 * padding - 60;
const chartX = padding;
const chartY = padding;
// Draw grid
ctx.strokeStyle = '#e0e0e0';
ctx.lineWidth = 1;
// Horizontal grid lines
for (let i = 0; i <= 10; i++) {
const y = chartY + (chartHeight * i / 10);
ctx.beginPath();
ctx.moveTo(chartX, y);
ctx.lineTo(chartX + chartWidth, y);
ctx.stroke();
// Y-axis labels
ctx.fillStyle = '#666666';
ctx.font = '12px Arial';
ctx.textAlign = 'right';
ctx.fillText((100 - i * 10).toString(), chartX - 10, y + 4);
}
// Vertical grid lines
for (let i = 0; i < data.length; i++) {
const x = chartX + (chartWidth * i / (data.length - 1));
ctx.beginPath();
ctx.moveTo(x, chartY);
ctx.lineTo(x, chartY + chartHeight);
ctx.stroke();
}
// Chart border
ctx.strokeStyle = '#cccccc';
ctx.lineWidth = 2;
ctx.strokeRect(chartX, chartY, chartWidth, chartHeight);
// Calculate points
const points = data.map((d, i) => ({
x: chartX + (chartWidth * i / (data.length - 1)),
y: chartY + chartHeight - (chartHeight * d.happiness / 100),
happiness: d.happiness,
stage: d.stage
}));
// Fill area under the line
ctx.fillStyle = 'rgba(255, 0, 0, 0.1)';
ctx.beginPath();
ctx.moveTo(points[0].x, chartY + chartHeight);
points.forEach(point => ctx.lineTo(point.x, point.y));
ctx.lineTo(points[points.length - 1].x, chartY + chartHeight);
ctx.closePath();
ctx.fill();
// Draw line
ctx.strokeStyle = '#ff0000';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
points.forEach(point => ctx.lineTo(point.x, point.y));
ctx.stroke();
// Draw points
ctx.fillStyle = '#ff0000';
points.forEach(point => {
ctx.beginPath();
ctx.arc(point.x, point.y, 6, 0, 2 * Math.PI);
ctx.fill();
// White border for points
ctx.strokeStyle = '#ffffff';
ctx.lineWidth = 2;
ctx.stroke();
});
// X-axis labels
ctx.fillStyle = '#666666';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
data.forEach((d, i) => {
const x = chartX + (chartWidth * i / (data.length - 1));
const lines = d.stage.split('\n');
lines.forEach((line, lineIndex) => {
ctx.fillText(line, x, chartY + chartHeight + 25 + (lineIndex * 15));
});
});
// Y-axis title
ctx.save();
ctx.translate(25, chartY + chartHeight / 2);
ctx.rotate(-Math.PI / 2);
ctx.fillStyle = '#333333';
ctx.font = '14px Arial';
ctx.textAlign = 'center';
ctx.fillText('Happiness Index', 0, 0);
ctx.restore();
// X-axis title
ctx.fillStyle = '#333333';
ctx.font = '14px Arial';
ctx.textAlign = 'center';
ctx.fillText('Project Stages', chartX + chartWidth / 2, canvas.height - 20);
// Annotations
ctx.font = 'bold 14px Arial';
// "So Excited!" - Start point
ctx.fillStyle = '#008000';
ctx.textAlign = 'left';
ctx.fillText('So Excited! 🚀', points[0].x + 15, points[0].y - 15);
// "Why Isn't It Done?" - Expected Deadline point
ctx.fillStyle = '#ff8c00';
ctx.textAlign = 'center';
ctx.fillText("Why Isn't It Done? 🤔", points[3].x, points[3].y - 20);
// "I'm Done With This!" - Extended Delay point
ctx.fillStyle = '#8b0000';
ctx.textAlign = 'right';
ctx.fillText("I'm Done With This! 😤", points[5].x - 15, points[5].y - 15);
}
function downloadChart() {
const canvas = document.getElementById('happinessChart');
const link = document.createElement('a');
link.download = 'ai-project-happiness-index.png';
link.href = canvas.toDataURL('image/png');
link.click();
}
// Initialize chart when page loads
window.addEventListener('load', function() {
drawChart();
});
// Redraw on window resize for responsiveness
window.addEventListener('resize', function() {
setTimeout(drawChart, 100);
});
</script>
</body>
</html>