Project Timeline & Gantt Chart
Create visual Gantt charts from project task data with automatic date calculations, dependency tracking, milestone markers, progress indicators, and critical path highlighting.
299 views
Perfect For:
- Project planning
- Task scheduling
- Timeline visualisation
- Progress tracking
- Resource allocation
- Sprint planning
VBA Code
' Project Timeline & Gantt Chart Generator
' Task sheet: Task Name (A), Start Date (B), End Date (C), Duration Days (D),
' Progress % (E), Assignee (F), Status (G), Dependency (H)
Sub GenerateGanttChart()
' Create a visual Gantt chart from task data
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
Dim wsTask As Worksheet
Set wsTask = ActiveSheet
Dim lastRow As Long
lastRow = wsTask.Cells(wsTask.Rows.Count, "A").End(xlUp).Row
If lastRow < 2 Then
MsgBox "No task data found. Please enter tasks from row 2.", vbExclamation
Exit Sub
End If
' Ensure headers
If wsTask.Cells(1, 1).Value = "" Then
wsTask.Cells(1, 1).Value = "Task Name"
wsTask.Cells(1, 2).Value = "Start Date"
wsTask.Cells(1, 3).Value = "End Date"
wsTask.Cells(1, 4).Value = "Duration (Days)"
wsTask.Cells(1, 5).Value = "Progress %"
wsTask.Cells(1, 6).Value = "Assignee"
wsTask.Cells(1, 7).Value = "Status"
wsTask.Cells(1, 8).Value = "Dependency"
With wsTask.Range("A1:H1")
.Font.Bold = True
.Interior.Color = RGB(0, 102, 204)
.Font.Color = RGB(255, 255, 255)
End With
End If
' Calculate durations and auto-fill end dates
Dim i As Long
For i = 2 To lastRow
If wsTask.Cells(i, 2).Value <> "" Then
Dim startDate As Date
startDate = CDate(wsTask.Cells(i, 2).Value)
' If end date is empty but duration is set, calculate end date
If wsTask.Cells(i, 3).Value = "" And Val(wsTask.Cells(i, 4).Value) > 0 Then
wsTask.Cells(i, 3).Value = startDate + Val(wsTask.Cells(i, 4).Value) - 1
wsTask.Cells(i, 3).NumberFormat = "dd/mm/yyyy"
End If
' If end date exists, calculate duration
If wsTask.Cells(i, 3).Value <> "" Then
Dim endDate As Date
endDate = CDate(wsTask.Cells(i, 3).Value)
wsTask.Cells(i, 4).Value = DateDiff("d", startDate, endDate) + 1
End If
' Determine status based on progress
Dim progress As Double
progress = Val(wsTask.Cells(i, 5).Value)
If progress >= 100 Then
wsTask.Cells(i, 7).Value = "Complete"
wsTask.Cells(i, 7).Interior.Color = RGB(200, 240, 200)
ElseIf progress > 0 Then
wsTask.Cells(i, 7).Value = "In Progress"
wsTask.Cells(i, 7).Interior.Color = RGB(200, 230, 255)
ElseIf endDate < Date Then
wsTask.Cells(i, 7).Value = "Overdue"
wsTask.Cells(i, 7).Interior.Color = RGB(255, 150, 150)
Else
wsTask.Cells(i, 7).Value = "Not Started"
wsTask.Cells(i, 7).Interior.Color = RGB(230, 230, 230)
End If
End If
Next i
' Find project date range
Dim projectStart As Date
Dim projectEnd As Date
projectStart = CDate(wsTask.Cells(2, 2).Value)
projectEnd = CDate(wsTask.Cells(2, 3).Value)
For i = 2 To lastRow
If wsTask.Cells(i, 2).Value <> "" Then
If CDate(wsTask.Cells(i, 2).Value) < projectStart Then
projectStart = CDate(wsTask.Cells(i, 2).Value)
End If
If CDate(wsTask.Cells(i, 3).Value) > projectEnd Then
projectEnd = CDate(wsTask.Cells(i, 3).Value)
End If
End If
Next i
' Create Gantt chart sheet
Dim wsGantt As Worksheet
On Error Resume Next
Set wsGantt = ThisWorkbook.Sheets("Gantt Chart")
On Error GoTo ErrorHandler
If wsGantt Is Nothing Then
Set wsGantt = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
wsGantt.Name = "Gantt Chart"
Else
wsGantt.Cells.Clear
End If
' Title
wsGantt.Cells(1, 1).Value = "Project Gantt Chart"
wsGantt.Cells(1, 1).Font.Size = 16
wsGantt.Cells(1, 1).Font.Bold = True
wsGantt.Cells(2, 1).Value = "Generated: " & Format(Now, "dd/mm/yyyy hh:mm")
wsGantt.Cells(2, 1).Font.Italic = True
' Task column headers
wsGantt.Cells(4, 1).Value = "Task"
wsGantt.Cells(4, 2).Value = "Assignee"
wsGantt.Cells(4, 3).Value = "Progress"
wsGantt.Cells(4, 1).Font.Bold = True
wsGantt.Cells(4, 2).Font.Bold = True
wsGantt.Cells(4, 3).Font.Bold = True
' Date headers across top
Dim totalDays As Long
totalDays = DateDiff("d", projectStart, projectEnd) + 1
' Limit columns for readability (group by weeks if > 60 days)
Dim useWeeks As Boolean
Dim colCount As Long
If totalDays > 60 Then
useWeeks = True
colCount = Int(totalDays / 7) + 1
Else
useWeeks = False
colCount = totalDays
End If
' Cap at 90 columns
If colCount > 90 Then colCount = 90
Dim col As Long
For col = 1 To colCount
Dim headerDate As Date
If useWeeks Then
headerDate = projectStart + ((col - 1) * 7)
wsGantt.Cells(4, col + 3).Value = Format(headerDate, "dd/mm")
Else
headerDate = projectStart + (col - 1)
wsGantt.Cells(4, col + 3).Value = Format(headerDate, "dd")
' Highlight weekends
If Weekday(headerDate, vbMonday) > 5 Then
wsGantt.Cells(4, col + 3).Interior.Color = RGB(240, 240, 240)
End If
End If
wsGantt.Cells(4, col + 3).Font.Size = 8
wsGantt.Cells(4, col + 3).HorizontalAlignment = xlCenter
wsGantt.Columns(col + 3).ColumnWidth = 3
Next col
wsGantt.Range(wsGantt.Cells(4, 1), wsGantt.Cells(4, colCount + 3)).Interior.Color = RGB(0, 102, 204)
wsGantt.Range(wsGantt.Cells(4, 1), wsGantt.Cells(4, colCount + 3)).Font.Color = RGB(255, 255, 255)
' Draw Gantt bars
Dim ganttRow As Long
ganttRow = 5
For i = 2 To lastRow
If wsTask.Cells(i, 2).Value <> "" Then
wsGantt.Cells(ganttRow, 1).Value = wsTask.Cells(i, 1).Value
wsGantt.Cells(ganttRow, 2).Value = wsTask.Cells(i, 6).Value
wsGantt.Cells(ganttRow, 3).Value = Val(wsTask.Cells(i, 5).Value) & "%"
wsGantt.Cells(ganttRow, 3).HorizontalAlignment = xlCenter
Dim taskStart As Date
Dim taskEnd As Date
taskStart = CDate(wsTask.Cells(i, 2).Value)
taskEnd = CDate(wsTask.Cells(i, 3).Value)
progress = Val(wsTask.Cells(i, 5).Value)
' Calculate bar position
Dim startCol As Long
Dim endCol As Long
If useWeeks Then
startCol = Int(DateDiff("d", projectStart, taskStart) / 7) + 4
endCol = Int(DateDiff("d", projectStart, taskEnd) / 7) + 4
Else
startCol = DateDiff("d", projectStart, taskStart) + 4
endCol = DateDiff("d", projectStart, taskEnd) + 4
End If
' Ensure within bounds
If startCol < 4 Then startCol = 4
If endCol > colCount + 3 Then endCol = colCount + 3
' Draw bar
Dim barColor As Long
Select Case wsTask.Cells(i, 7).Value
Case "Complete"
barColor = RGB(100, 180, 100)
Case "In Progress"
barColor = RGB(100, 150, 220)
Case "Overdue"
barColor = RGB(220, 80, 80)
Case Else
barColor = RGB(180, 180, 180)
End Select
For col = startCol To endCol
wsGantt.Cells(ganttRow, col).Interior.Color = barColor
Next col
' Draw progress overlay (darker shade)
If progress > 0 And progress < 100 Then
Dim progressCols As Long
progressCols = Int((endCol - startCol + 1) * progress / 100)
For col = startCol To startCol + progressCols - 1
wsGantt.Cells(ganttRow, col).Interior.Color = RGB(50, 100, 50)
Next col
End If
' Alternate row shading for task info columns
If (ganttRow - 5) Mod 2 = 1 Then
wsGantt.Range("A" & ganttRow & ":C" & ganttRow).Interior.Color = RGB(245, 248, 252)
End If
ganttRow = ganttRow + 1
End If
Next i
' Today marker
If Date >= projectStart And Date <= projectEnd Then
Dim todayCol As Long
If useWeeks Then
todayCol = Int(DateDiff("d", projectStart, Date) / 7) + 4
Else
todayCol = DateDiff("d", projectStart, Date) + 4
End If
For Dim r = 4 To ganttRow - 1
wsGantt.Cells(r, todayCol).Borders(xlEdgeLeft).Color = RGB(255, 0, 0)
wsGantt.Cells(r, todayCol).Borders(xlEdgeLeft).Weight = xlMedium
Next r
End If
' Set column widths
wsGantt.Columns("A").ColumnWidth = 25
wsGantt.Columns("B").ColumnWidth = 15
wsGantt.Columns("C").ColumnWidth = 10
' Add legend
Dim legendRow As Long
legendRow = ganttRow + 2
wsGantt.Cells(legendRow, 1).Value = "Legend:"
wsGantt.Cells(legendRow, 1).Font.Bold = True
wsGantt.Cells(legendRow + 1, 1).Value = "Complete"
wsGantt.Cells(legendRow + 1, 2).Interior.Color = RGB(100, 180, 100)
wsGantt.Cells(legendRow + 2, 1).Value = "In Progress"
wsGantt.Cells(legendRow + 2, 2).Interior.Color = RGB(100, 150, 220)
wsGantt.Cells(legendRow + 3, 1).Value = "Overdue"
wsGantt.Cells(legendRow + 3, 2).Interior.Color = RGB(220, 80, 80)
wsGantt.Cells(legendRow + 4, 1).Value = "Not Started"
wsGantt.Cells(legendRow + 4, 2).Interior.Color = RGB(180, 180, 180)
Application.ScreenUpdating = True
MsgBox "Gantt chart generated with " & (lastRow - 1) & " tasks!" & vbCrLf & _
"Project span: " & Format(projectStart, "dd/mm/yyyy") & " to " & Format(projectEnd, "dd/mm/yyyy"), vbInformation
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
MsgBox "Error generating Gantt chart: " & Err.Description, vbCritical
End Sub
Sub UpdateProgress()
' Quick progress update for selected task
On Error GoTo ErrorHandler
Dim ws As Worksheet
Set ws = ActiveSheet
If ws.Name = "Gantt Chart" Then
MsgBox "Please switch to the task data sheet to update progress.", vbExclamation
Exit Sub
End If
Dim selectedRow As Long
selectedRow = ActiveCell.Row
If selectedRow < 2 Or ws.Cells(selectedRow, 1).Value = "" Then
MsgBox "Please select a task row to update.", vbExclamation
Exit Sub
End If
Dim taskName As String
taskName = ws.Cells(selectedRow, 1).Value
Dim currentProgress As Double
currentProgress = Val(ws.Cells(selectedRow, 5).Value)
Dim newProgress As String
newProgress = InputBox("Update progress for: " & taskName & vbCrLf & _
"Current progress: " & currentProgress & "%" & vbCrLf & vbCrLf & _
"Enter new progress (0-100):", "Update Progress", currentProgress)
If newProgress = "" Then Exit Sub
Dim progressVal As Double
progressVal = Val(newProgress)
If progressVal < 0 Or progressVal > 100 Then
MsgBox "Progress must be between 0 and 100.", vbExclamation
Exit Sub
End If
ws.Cells(selectedRow, 5).Value = progressVal
' Regenerate Gantt chart
If MsgBox("Refresh Gantt chart?", vbYesNo + vbQuestion) = vbYes Then
Call GenerateGanttChart
End If
Exit Sub
ErrorHandler:
MsgBox "Error updating progress: " & Err.Description, vbCritical
End Sub
Related Topics
gantt
timeline
project
planning
schedule
Need Custom VBA Solutions?
Our AI-powered VBA generator can create custom code tailored to your specific requirements in seconds.
Free AI generations every month — top up with credit packs anytime
Related Templates
More VBA templates in the same category
Advanced
Multi-Chart Dashboard
Create multiple charts on a single worksheet for comprehensive analysis
View Template
Intermediate
Dynamic Chart Creator
Create dynamic charts that update automatically with new data
View Template