<div class="container">
<div class="header">
<h1>Project Gantt Chart</h1>
<p class="subtitle">Interactive timeline visualization</p>
</div>
<div class="legend">
<div class="legend-item">
<div class="legend-color" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);"></div>
<span>Completed</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);"></div>
<span>In Progress</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);"></div>
<span>Pending</span>
</div>
</div>
<div class="gantt-wrapper">
<div class="gantt-container" id="ganttChart"></div>
</div>
</div>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
padding: 20px;
min-height: 100vh;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: white;
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
padding: 30px;
text-align: center;
}
h1 {
font-size: 28px;
margin-bottom: 8px;
}
.subtitle {
font-size: 14px;
opacity: 0.9;
}
.gantt-wrapper {
padding: 30px;
overflow-x: auto;
}
.gantt-container {
min-width: 1000px;
}
.timeline-header {
display: grid;
grid-template-columns: 200px 1fr;
margin-bottom: 2px;
background: #f8f9fa;
border-radius: 8px;
}
.task-header {
padding: 15px;
font-weight: 600;
color: #333;
border-right: 2px solid #e0e0e0;
}
.dates-header {
display: flex;
padding: 15px 0;
}
.date-column {
flex: 1;
text-align: center;
font-size: 12px;
color: #666;
font-weight: 500;
}
.gantt-row {
display: grid;
grid-template-columns: 200px 1fr;
margin-bottom: 10px;
background: white;
border: 1px solid #e0e0e0;
border-radius: 8px;
overflow: hidden;
transition: transform 0.2s;
}
.gantt-row:hover {
transform: translateX(4px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.task-name {
padding: 20px 15px;
font-weight: 500;
color: #333;
border-right: 2px solid #e0e0e0;
display: flex;
flex-direction: column;
justify-content: center;
}
.task-person {
font-size: 12px;
color: #888;
margin-top: 4px;
}
.timeline {
display: flex;
position: relative;
padding: 10px 0;
}
.timeline-cell {
flex: 1;
border-right: 1px solid #f0f0f0;
position: relative;
}
.bar {
position: absolute;
height: 32px;
top: 50%;
transform: translateY(-50%);
border-radius: 6px;
display: flex;
align-items: center;
padding: 0 12px;
color: white;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.bar:hover {
transform: translateY(-50%) scale(1.05);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}
.bar.status-completed {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
.bar.status-in-progress {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.bar.status-pending {
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
}
.legend {
display: flex;
justify-content: center;
gap: 30px;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
margin: 20px 30px;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
}
.legend-color {
width: 24px;
height: 24px;
border-radius: 4px;
}
.today-line {
position: absolute;
width: 2px;
background: #ff4757;
height: 100%;
top: 0;
z-index: 10;
}
.today-label {
position: absolute;
top: -25px;
left: 50%;
transform: translateX(-50%);
background: #ff4757;
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 11px;
font-weight: 600;
white-space: nowrap;
}
const tasks = [
{ name: 'Project Planning', person: 'John Doe', start: 1, duration: 3, status: 'completed' },
{ name: 'Design Phase', person: 'Jane Smith', start: 3, duration: 4, status: 'completed' },
{ name: 'Frontend Development', person: 'Mike Johnson', start: 5, duration: 6, status: 'in-progress' },
{ name: 'Backend Development', person: 'Sarah Williams', start: 6, duration: 5, status: 'in-progress' },
{ name: 'Database Setup', person: 'Tom Brown', start: 7, duration: 3, status: 'in-progress' },
{ name: 'API Integration', person: 'Emily Davis', start: 10, duration: 4, status: 'pending' },
{ name: 'Testing & QA', person: 'Chris Wilson', start: 12, duration: 3, status: 'pending' },
{ name: 'Deployment', person: 'Alex Martinez', start: 14, duration: 2, status: 'pending' }
];
const totalDays = 16;
const dates = [];
const startDate = new Date('2025-01-01');
for (let i = 0; i < totalDays; i++) {
const date = new Date(startDate);
date.setDate(date.getDate() + i);
dates.push(date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }));
}
function renderGanttChart() {
const container = document.getElementById('ganttChart');
// Header
let html = '<div class="timeline-header">';
html += '<div class="task-header">Task / Assignee</div>';
html += '<div class="dates-header">';
dates.forEach(date => {
html += `<div class="date-column">${date}</div>`;
});
html += '</div></div>';
// Rows
tasks.forEach(task => {
const startPercent = (task.start / totalDays) * 100;
const widthPercent = (task.duration / totalDays) * 100;
html += '<div class="gantt-row">';
html += `<div class="task-name">
<div>${task.name}</div>
<div class="task-person">${task.person}</div>
</div>`;
html += '<div class="timeline">';
for (let i = 0; i < totalDays; i++) {
html += '<div class="timeline-cell"></div>';
}
html += `<div class="bar status-${task.status}"
style="left: ${startPercent}%; width: ${widthPercent}%;"
title="${task.name}: ${task.duration} days">
${task.duration}d
</div>`;
html += '</div></div>';
});
container.innerHTML = html;
}
renderGanttChart();
No comments yet. Be the first!