Critical Path Method Calculator

Critical Path Method (CPM) Calculator & Guide :root { –primary-color: #004a99; –success-color: #28a745; –background-color: #f8f9fa; –text-color: #333; –border-color: #ddd; –card-background: #fff; –shadow: 0 2px 5px rgba(0,0,0,0.1); } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; color: var(–text-color); background-color: var(–background-color); margin: 0; padding: 0; } .container { max-width: 1000px; margin: 20px auto; padding: 20px; background-color: var(–card-background); border-radius: 8px; box-shadow: var(–shadow); } h1, h2, h3 { color: var(–primary-color); text-align: center; margin-bottom: 20px; } h1 { font-size: 2.5em; } h2 { font-size: 1.8em; margin-top: 30px; border-bottom: 2px solid var(–primary-color); padding-bottom: 10px; } h3 { font-size: 1.4em; margin-top: 25px; } .calculator-wrapper { background-color: var(–card-background); padding: 30px; border-radius: 8px; box-shadow: var(–shadow); margin-bottom: 40px; } .input-group { margin-bottom: 20px; text-align: left; } .input-group label { display: block; margin-bottom: 8px; font-weight: bold; color: var(–primary-color); } .input-group input[type="text"], .input-group input[type="number"], .input-group select { width: calc(100% – 22px); padding: 10px; border: 1px solid var(–border-color); border-radius: 4px; font-size: 1em; box-sizing: border-box; } .input-group input[type="text"]:focus, .input-group input[type="number"]:focus, .input-group select:focus { border-color: var(–primary-color); outline: none; box-shadow: 0 0 0 2px rgba(0, 74, 153, 0.2); } .input-group .helper-text { font-size: 0.85em; color: #666; margin-top: 5px; display: block; } .error-message { color: red; font-size: 0.8em; margin-top: 5px; display: none; /* Hidden by default */ } .button-group { display: flex; justify-content: space-between; margin-top: 30px; gap: 10px; } button { padding: 12px 25px; border: none; border-radius: 5px; cursor: pointer; font-size: 1em; font-weight: bold; transition: background-color 0.3s ease; } button.primary { background-color: var(–primary-color); color: white; } button.primary:hover { background-color: #003366; } button.secondary { background-color: #6c757d; color: white; } button.secondary:hover { background-color: #5a6268; } button.reset { background-color: #ffc107; color: #212529; } button.reset:hover { background-color: #e0a800; } #results { margin-top: 30px; padding: 25px; background-color: var(–primary-color); color: white; border-radius: 8px; box-shadow: var(–shadow); text-align: center; } #results h3 { color: white; margin-bottom: 15px; } .result-item { margin-bottom: 10px; font-size: 1.1em; } .result-item strong { font-size: 1.3em; display: block; margin-top: 5px; } .result-item .label { font-size: 0.9em; opacity: 0.8; } .intermediate-results { margin-top: 25px; padding: 20px; background-color: #e9ecef; border-radius: 6px; text-align: left; } .intermediate-results h4 { margin-top: 0; color: var(–primary-color); font-size: 1.2em; margin-bottom: 15px; } .intermediate-results div { margin-bottom: 10px; font-size: 0.95em; } .intermediate-results span { font-weight: bold; margin-left: 5px; } .formula-explanation { margin-top: 20px; font-size: 0.9em; color: #555; text-align: center; padding: 15px; background-color: #f1f1f1; border-left: 4px solid var(–primary-color); border-radius: 4px; } table { width: 100%; border-collapse: collapse; margin-top: 30px; box-shadow: var(–shadow); } th, td { padding: 12px 15px; text-align: left; border: 1px solid var(–border-color); } thead { background-color: var(–primary-color); color: white; } tbody tr:nth-child(even) { background-color: #f2f2f2; } caption { font-size: 1.1em; font-weight: bold; color: var(–primary-color); margin-bottom: 15px; caption-side: top; text-align: left; } #chartContainer { margin-top: 30px; padding: 20px; background-color: var(–card-background); border-radius: 8px; box-shadow: var(–shadow); text-align: center; } #chartContainer canvas { max-width: 100%; height: auto; } .chart-caption { font-size: 0.9em; color: #666; margin-top: 10px; } .article-section { margin-top: 40px; padding: 30px; background-color: var(–card-background); border-radius: 8px; box-shadow: var(–shadow); } .article-section h2 { text-align: left; margin-bottom: 20px; border-bottom: none; } .article-section h3 { text-align: left; margin-top: 25px; margin-bottom: 15px; color: var(–primary-color); } .article-section p, .article-section ul, .article-section ol { margin-bottom: 15px; font-size: 1.05em; } .article-section ul, .article-section ol { padding-left: 25px; } .article-section li { margin-bottom: 8px; } .article-section strong { color: var(–primary-color); } .faq-item { margin-bottom: 15px; padding: 15px; background-color: #f8f9fa; border-left: 3px solid var(–primary-color); border-radius: 4px; } .faq-item strong { display: block; margin-bottom: 5px; color: var(–primary-color); } .internal-links { margin-top: 30px; padding: 25px; background-color: #e9ecef; border-radius: 8px; } .internal-links h3 { text-align: left; margin-top: 0; margin-bottom: 15px; color: var(–primary-color); } .internal-links ul { list-style: none; padding: 0; } .internal-links li { margin-bottom: 10px; } .internal-links a { color: var(–primary-color); text-decoration: none; font-weight: bold; } .internal-links a:hover { text-decoration: underline; } .internal-links p { font-size: 0.9em; color: #555; margin-top: 5px; } .highlighted-result { font-size: 1.8em !important; font-weight: bold; color: var(–success-color); } .copy-button { background-color: #6c757d; color: white; margin-left: 10px; } .copy-button:hover { background-color: #5a6268; } .tooltip { position: relative; display: inline-block; border-bottom: 1px dotted black; cursor: help; } .tooltip .tooltiptext { visibility: hidden; width: 220px; background-color: #555; color: #fff; text-align: center; border-radius: 6px; padding: 5px 10px; position: absolute; z-index: 1; bottom: 125%; left: 50%; margin-left: -110px; opacity: 0; transition: opacity 0.3s; font-size: 0.8em; line-height: 1.4; } .tooltip .tooltiptext::after { content: ""; position: absolute; top: 100%; left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: #555 transparent transparent transparent; } .tooltip:hover .tooltiptext { visibility: visible; opacity: 1; }

Critical Path Method (CPM) Calculator

Determine your project's critical path and minimum duration with our easy-to-use CPM calculator.

CPM Calculator Inputs

Enter the total number of distinct tasks in your project.

Project Critical Path Analysis

Project Duration (Days):
Critical Path Tasks:
Total Tasks:

Intermediate Calculations

Earliest Start (ES):
Earliest Finish (EF):
Latest Start (LS):
Latest Finish (LF):
Total Float (TF):
CPM Calculation Logic: The Critical Path Method (CPM) identifies the longest sequence of dependent tasks and determines the minimum project completion time. It involves calculating Earliest Start (ES), Earliest Finish (EF), Latest Start (LS), and Latest Finish (LF) times for each task. Tasks with zero total float (TF = LF – EF or LS – ES) form the critical path.
Gantt-like representation of task durations and critical path.
Task Details and Float Analysis
Task ID Duration (Days) Predecessors ES EF LS LF TF Critical

What is the Critical Path Method (CPM)?

The Critical Path Method (CPM) is a project management technique used to identify the longest sequence of tasks that must be completed on time for a project to finish by its earliest possible date. It's a powerful tool for project planning, scheduling, and control, helping managers understand task dependencies, estimate project duration, and allocate resources effectively. By pinpointing the critical path, project managers can focus their attention on the tasks that have no room for delay, as any slippage in these activities will directly impact the overall project completion date. Understanding the critical path is fundamental to successful project delivery, especially in complex projects with numerous interdependencies.

Who Should Use CPM? CPM is invaluable for project managers, program managers, construction supervisors, software development leads, event planners, and anyone responsible for overseeing projects with defined start and end dates and sequential tasks. It's particularly useful for projects involving multiple teams, complex workflows, or tight deadlines. If your project involves tasks that depend on the completion of other tasks, CPM can provide clarity and control.

Common Misconceptions about CPM:

  • CPM is only about the longest task: This is incorrect. CPM focuses on the longest *sequence* of dependent tasks, not just the single longest task.
  • CPM eliminates all project delays: CPM identifies tasks with zero float, highlighting where delays are critical. It doesn't eliminate delays but helps manage them proactively.
  • CPM is overly complex for small projects: While powerful for large projects, even small projects can benefit from basic CPM analysis to ensure timely completion and identify potential bottlenecks.
  • CPM assumes fixed task durations: Traditional CPM uses deterministic durations. More advanced techniques like PERT (Program Evaluation and Review Technique) incorporate probabilistic durations.

Critical Path Method (CPM) Formula and Mathematical Explanation

The core of the Critical Path Method (CPM) lies in calculating four key time estimates for each activity (task) within a project network:

  1. Earliest Start (ES): The earliest possible time an activity can begin, assuming all its predecessors are completed.
  2. Earliest Finish (EF): The earliest possible time an activity can be completed (ES + Duration).
  3. Latest Finish (LF): The latest possible time an activity can be completed without delaying the project's overall completion date.
  4. Latest Start (LS): The latest possible time an activity can begin without delaying the project's overall completion date (LF – Duration).

These calculations are performed in two passes:

Forward Pass (Calculating ES and EF)

The forward pass starts from the beginning of the project. For the first task(s) with no predecessors, ES = 0. The EF for any task is calculated as: EF = ES + Duration.

For subsequent tasks, the ES is determined by the maximum EF of all its immediate predecessors. If a task has multiple predecessors, it cannot start until the latest of their earliest finish times has passed. Mathematically:

ES(Task J) = max(EF(Task I)) for all tasks I that are immediate predecessors of task J.

The project's total duration is the maximum EF of all tasks that have no successors (i.e., the final tasks in the project network).

Backward Pass (Calculating LF and LS)

The backward pass starts from the end of the project. The LF for the final task(s) is set equal to their EF (which is also the project's total duration). The LS for any task is calculated as: LS = LF – Duration.

For preceding tasks, the LF is determined by the minimum LS of all its immediate successors. If a task has multiple successors, its latest finish time is constrained by the earliest of their latest start times. Mathematically:

LF(Task I) = min(LS(Task J)) for all tasks J that are immediate successors of task I.

Calculating Total Float (TF)

Total Float (or Slack) is the amount of time an activity can be delayed without delaying the project completion date. It is calculated using either:

TF = LF – EF

or

TF = LS – ES

Tasks with a Total Float of zero (TF = 0) are considered part of the critical path. Any delay in these tasks directly impacts the project's overall duration.

Variables Table

CPM Variables Explained
Variable Meaning Unit Typical Range
Task ID Unique identifier for each project activity. Alphanumeric A1, B2, Task_001
Duration Estimated time required to complete a task. Days (or other time units) 1 to 100+
Predecessors Tasks that must be completed before this task can start. Task IDs Comma-separated list (e.g., A1, B2)
ES (Earliest Start) The earliest time a task can begin. Days 0 to Project Duration
EF (Earliest Finish) The earliest time a task can be completed. Days Duration to Project Duration
LS (Latest Start) The latest time a task can begin without delaying the project. Days 0 to Project Duration
LF (Latest Finish) The latest time a task can be completed without delaying the project. Days Duration to Project Duration
TF (Total Float) The amount of time a task can be delayed without affecting the project end date. Days 0 to Positive Integer

Practical Examples of Critical Path Method (CPM)

Let's illustrate CPM with two practical examples:

Example 1: Simple Software Feature Development

Consider a small software team developing a new feature. The tasks, durations, and dependencies are:

  • Task A (Design): Duration 5 days, Predecessors: None
  • Task B (Backend Dev): Duration 10 days, Predecessors: A
  • Task C (Frontend Dev): Duration 8 days, Predecessors: A
  • Task D (Integration): Duration 4 days, Predecessors: B, C
  • Task E (Testing): Duration 6 days, Predecessors: D

CPM Calculation:

  • Forward Pass:
    • A: ES=0, EF=0+5=5
    • B: ES=max(EF_A)=5, EF=5+10=15
    • C: ES=max(EF_A)=5, EF=5+8=13
    • D: ES=max(EF_B, EF_C)=max(15, 13)=15, EF=15+4=19
    • E: ES=max(EF_D)=19, EF=19+6=25
    Project Duration = 25 days.
  • Backward Pass:
    • E: LF=25, LS=25-6=19
    • D: LF=min(LS_E)=19, LS=19-4=15
    • B: LF=min(LS_D)=15, LS=15-10=5
    • C: LF=min(LS_D)=15, LS=15-8=7
    • A: LF=min(LS_B, LS_C)=min(5, 7)=5, LS=5-5=0
  • Total Float:
    • A: TF = 5-5 = 0
    • B: TF = 15-15 = 0
    • C: TF = 15-13 = 2
    • D: TF = 19-19 = 0
    • E: TF = 25-25 = 0

Result Interpretation: The project duration is 25 days. The critical path is A -> B -> D -> E. Task C has 2 days of float, meaning it can be delayed by up to 2 days without affecting the project end date.

Example 2: Construction Project Phase

Consider a phase of a construction project:

  • Task 1 (Foundation): Duration 15 days, Predecessors: None
  • Task 2 (Framing): Duration 20 days, Predecessors: 1
  • Task 3 (Roofing): Duration 10 days, Predecessors: 2
  • Task 4 (Electrical): Duration 12 days, Predecessors: 2
  • Task 5 (Plumbing): Duration 14 days, Predecessors: 2
  • Task 6 (Finishing): Duration 18 days, Predecessors: 3, 4, 5

CPM Calculation:

  • Forward Pass:
    • 1: ES=0, EF=15
    • 2: ES=15, EF=15+20=35
    • 3: ES=35, EF=35+10=45
    • 4: ES=35, EF=35+12=47
    • 5: ES=35, EF=35+14=49
    • 6: ES=max(45, 47, 49)=49, EF=49+18=67
    Project Duration = 67 days.
  • Backward Pass:
    • 6: LF=67, LS=67-18=49
    • 3: LF=min(LS_6)=49, LS=49-10=39
    • 4: LF=min(LS_6)=49, LS=49-12=37
    • 5: LF=min(LS_6)=49, LS=49-14=35
    • 2: LF=min(LS_3, LS_4, LS_5)=min(39, 37, 35)=35, LS=35-20=15
    • 1: LF=min(LS_2)=15, LS=15-15=0
  • Total Float:
    • 1: TF = 15-15 = 0
    • 2: TF = 35-35 = 0
    • 3: TF = 49-45 = 4
    • 4: TF = 49-47 = 2
    • 5: TF = 49-49 = 0
    • 6: TF = 67-67 = 0

Result Interpretation: The project phase duration is 67 days. The critical path is 1 -> 2 -> 5 -> 6. Tasks 3 and 4 have float (4 and 2 days respectively), offering some flexibility.

How to Use This Critical Path Method (CPM) Calculator

Our Critical Path Method (CPM) calculator simplifies the process of identifying your project's critical path and duration. Follow these steps:

  1. Enter Number of Tasks: Start by inputting the total number of distinct tasks involved in your project into the "Number of Tasks" field.
  2. Input Task Details: The calculator will dynamically generate input fields for each task. For every task, you need to provide:
    • Task ID: A unique name or number for the task (e.g., "Design", "Build", "Test").
    • Duration (Days): The estimated number of working days required to complete the task.
    • Predecessors: A comma-separated list of the Task IDs of all tasks that must be completed *before* this task can begin. If a task has no predecessors, leave this field blank.
  3. Calculate CPM: Once all task details are entered, click the "Calculate CPM" button.
  4. Review Results: The calculator will display:
    • Project Duration: The minimum time required to complete the project.
    • Critical Path Tasks: A list of tasks that lie on the critical path (those with zero float).
    • Intermediate Calculations: Earliest Start (ES), Earliest Finish (EF), Latest Start (LS), Latest Finish (LF), and Total Float (TF) for each task.
  5. Analyze the Table and Chart:
    • The Task Details Table provides a comprehensive breakdown of calculations for each task, including its float and whether it's critical.
    • The Gantt-like Chart visually represents task durations and highlights the critical path sequence.
  6. Decision Making: Use the results to:
    • Focus management attention on critical path tasks.
    • Identify tasks with float that might be rescheduled or have resources shifted.
    • Optimize the project schedule for faster completion.
    • Manage risks associated with potential delays on critical tasks.
  7. Reset: Click the "Reset" button to clear all inputs and return to default settings.
  8. Copy Results: Use the "Copy Results" button to copy the main findings and key assumptions for documentation or sharing.

By leveraging this critical path method calculator, you gain crucial insights into your project's timeline and potential risks, enabling more effective project management and delivery.

Key Factors Affecting Critical Path Method (CPM) Results

Several factors can significantly influence the outcome of a CPM analysis and the resulting critical path. Understanding these is key to accurate project planning:

  1. Task Duration Estimates: The accuracy of your duration estimates is paramount. Overly optimistic or pessimistic estimates will skew the calculated project duration and potentially misidentify the critical path. Use historical data, expert judgment, and techniques like PERT for more robust estimates.
  2. Dependency Accuracy: Incorrectly defined task dependencies (predecessors/successors) are a common source of flawed CPM analysis. Ensure that the logical sequence of tasks accurately reflects the project workflow. Missing dependencies or incorrectly assumed ones can lead to unrealistic schedules.
  3. Resource Availability: While basic CPM doesn't explicitly model resource constraints, resource limitations can indirectly affect task durations and dependencies. If a critical resource is shared across multiple tasks, it can create bottlenecks not captured by simple CPM, potentially extending the actual project timeline beyond the calculated critical path duration. Resource leveling techniques are often used in conjunction with CPM.
  4. Scope Changes: Any changes to the project scope (adding or removing tasks, altering requirements) necessitate a recalculation of the CPM. Unmanaged scope creep can invalidate the original critical path analysis and lead to schedule overruns.
  5. Unforeseen Events & Risks: CPM typically uses deterministic durations. However, real-world projects face risks like weather delays, equipment failures, or unexpected technical challenges. Incorporating contingency time (buffers) or using probabilistic methods like PERT can help account for these uncertainties and provide a more realistic project duration estimate.
  6. Management Decisions & Prioritization: Project managers constantly make decisions that affect the schedule. Prioritizing certain tasks, reallocating resources, or approving overtime can alter the critical path. Effective CPM usage involves using the analysis to inform these decisions, not just as a static report.
  7. Communication Breakdown: Poor communication among team members or stakeholders can lead to misunderstandings about task status, dependencies, or priorities. This can result in delays that impact the critical path, even if the initial CPM analysis was sound.
  8. External Factors: Market conditions, regulatory changes, supplier delays, or client feedback loops can all impact project timelines. These external influences need to be considered when interpreting CPM results and setting realistic deadlines.

Accurate critical path method analysis requires diligent input, continuous monitoring, and an awareness of these influencing factors.

Frequently Asked Questions (FAQ) about CPM

Q1: What is the difference between CPM and Gantt charts?

A1: A Gantt chart is a visual bar chart representing a project schedule, showing task durations and timelines. CPM is a network analysis technique used to determine the critical path and project duration. They are often used together; CPM identifies the critical tasks, and a Gantt chart visually displays the entire schedule, including the critical path.

Q2: Can the critical path change during a project?

A2: Yes, the critical path can change if task durations change significantly, dependencies are altered, or new tasks are added. This is why regular updates and recalculations of the CPM are essential throughout the project lifecycle.

Q3: What does it mean if a task has negative float?

A3: Negative float typically indicates a scheduling conflict or an unrealistic deadline. It means that even if all preceding tasks finish as late as possible, this task still cannot start and finish within its required timeframe, suggesting the project is already behind schedule.

Q4: How do I handle tasks with multiple predecessors?

A4: When calculating the Earliest Start (ES) for a task with multiple predecessors, you must use the *latest* Earliest Finish (EF) among all its predecessors. The task cannot begin until all preceding tasks are completed. For the Latest Finish (LF), you use the *earliest* Latest Start (LS) among its successors.

Q5: Is CPM only useful for large, complex projects?

A5: While CPM is incredibly powerful for large projects, its principles can be applied to smaller projects as well. Even for simpler projects, identifying the critical sequence of tasks helps ensure focus and timely completion.

Q6: What is the difference between Total Float and Free Float?

A6: Total Float (TF) is the total amount of time a task can be delayed without delaying the project end date. Free Float (FF) is the amount of time a task can be delayed without delaying the Earliest Start (ES) of any successor task. TF is generally more critical for identifying the overall project path.

Q7: How does CPM relate to resource management?

A7: Basic CPM doesn't directly manage resources, but it highlights tasks that require close monitoring. Resource constraints can impact task durations and dependencies, potentially altering the critical path. Advanced techniques often integrate resource allocation with CPM (e.g., resource leveling).

Q8: Can I use different time units (e.g., hours, weeks) with CPM?

A8: Yes, CPM is flexible with time units. As long as you are consistent throughout your project (e.g., all durations in hours, or all in weeks), the calculations and logic remain the same. Our calculator uses 'Days' as the standard unit.

Related Tools and Internal Resources

© 2023 Your Project Management Suite. All rights reserved.

var taskCount = 0; var tasksData = []; function updateTaskInputs() { var numTasks = parseInt(document.getElementById("tasks").value); var taskDetailsDiv = document.getElementById("taskDetails"); taskDetailsDiv.innerHTML = "; // Clear previous inputs tasksData = []; // Reset task data if (isNaN(numTasks) || numTasks < 1) { document.getElementById("tasksError").textContent = "Please enter a valid number of tasks (1 or more)."; document.getElementById("tasksError").style.display = "block"; return; } else { document.getElementById("tasksError").textContent = ""; document.getElementById("tasksError").style.display = "none"; } taskCount = numTasks; for (var i = 0; i < taskCount; i++) { var taskDiv = document.createElement("div"); taskDiv.className = "input-group"; taskDiv.innerHTML = `

Task ${i + 1}

`; taskDetailsDiv.appendChild(taskDiv); } } function validateInputs() { var isValid = true; tasksData = []; // Clear previous data for (var i = 0; i task.id === taskId)) { document.getElementById(`taskIdError_${i}`).textContent = "Duplicate Task ID found."; document.getElementById(`taskIdError_${i}`).style.display = "block"; isValid = false; } // Validate Duration if (isNaN(duration) || duration <= 0) { document.getElementById(`durationError_${i}`).textContent = "Duration must be a positive number."; document.getElementById(`durationError_${i}`).style.display = "block"; isValid = false; } // Validate Predecessors if (predecessorsStr !== "") { predecessors = predecessorsStr.split(',').map(function(p) { return p.trim(); }); for (var j = 0; j task.id); for (var i = 0; i < tasksData.length; i++) { for (var j = 0; j < tasksData[i].predecessors.length; j++) { var predId = tasksData[i].predecessors[j]; if (!allTaskIds.includes(predId)) { document.getElementById(`predecessorsError_${i}`).textContent = `Predecessor task ID "${predId}" not found.`; document.getElementById(`predecessorsError_${i}`).style.display = "block"; isValid = false; } } // Check for self-dependency if (tasksData[i].predecessors.includes(tasksData[i].id)) { document.getElementById(`predecessorsError_${i}`).textContent = "Task cannot be its own predecessor."; document.getElementById(`predecessorsError_${i}`).style.display = "block"; isValid = false; } } } return isValid; } function calculateCPM() { if (!validateInputs()) { alert("Please correct the errors in the input fields before calculating."); return; } // — Forward Pass — var maxEF = 0; var projectDuration = 0; var tasksWithNoSuccessors = []; // Initialize ES for tasks with no predecessors for (var i = 0; i < tasksData.length; i++) { if (tasksData[i].predecessors.length === 0) { tasksData[i].es = 0; tasksData[i].ef = tasksData[i].duration; } } // Iteratively calculate ES and EF until stable var changed = true; while(changed) { changed = false; for (var i = 0; i 0) { var maxPredEF = 0; for (var j = 0; j < currentTask.predecessors.length; j++) { var predId = currentTask.predecessors[j]; var predecessor = tasksData.find(function(task) { return task.id === predId; }); if (predecessor) { maxPredEF = Math.max(maxPredEF, predecessor.ef); } } var newES = maxPredEF; var newEF = newES + currentTask.duration; if (newES !== currentTask.es || newEF !== currentTask.ef) { currentTask.es = newES; currentTask.ef = newEF; changed = true; } } else { // Tasks with no predecessors var newEF = currentTask.es + currentTask.duration; if (newEF !== currentTask.ef) { currentTask.ef = newEF; changed = true; } } } } // Determine project duration and identify final tasks for (var i = 0; i < tasksData.length; i++) { var isSuccessor = false; for (var j = 0; j < tasksData.length; j++) { if (i !== j && tasksData[j].predecessors.includes(tasksData[i].id)) { isSuccessor = true; break; } } if (!isSuccessor) { tasksWithNoSuccessors.push(tasksData[i]); } maxEF = Math.max(maxEF, tasksData[i].ef); } projectDuration = maxEF; // — Backward Pass — // Initialize LF for tasks with no successors for (var i = 0; i < tasksData.length; i++) { var isSuccessor = false; for (var j = 0; j = 0; i–) { // Iterate backwards var currentTask = tasksData[i]; var successors = tasksData.filter(function(task) { return task.predecessors.includes(currentTask.id); }); if (successors.length > 0) { var minSuccLS = Infinity; for (var j = 0; j < successors.length; j++) { minSuccLS = Math.min(minSuccLS, successors[j].ls); } var newLF = minSuccLS; var newLS = newLF – currentTask.duration; if (newLF !== currentTask.lf || newLS !== currentTask.ls) { currentTask.lf = newLF; currentTask.ls = newLS; changed = true; } } else { // Tasks with no successors (already initialized) var newLS = currentTask.lf – currentTask.duration; if (newLS !== currentTask.ls) { currentTask.ls = newLS; changed = true; } } } } // — Calculate Total Float and Identify Critical Path — var criticalPathTasks = []; for (var i = 0; i "); document.getElementById("totalTasksResult").textContent = taskCount; document.getElementById("earliestStart").innerHTML = `Earliest Start (ES): ${tasksData.find(t => t.id === "Task 1") ? tasksData.find(t => t.id === "Task 1").es : '–'}`; document.getElementById("earliestFinish").innerHTML = `Earliest Finish (EF): ${tasksData.find(t => t.id === "Task 1") ? tasksData.find(t => t.id === "Task 1").ef : '–'}`; document.getElementById("latestStart").innerHTML = `Latest Start (LS): ${tasksData.find(t => t.id === "Task 1") ? tasksData.find(t => t.id === "Task 1").ls : '–'}`; document.getElementById("latestFinish").innerHTML = `Latest Finish (LF): ${tasksData.find(t => t.id === "Task 1") ? tasksData.find(t => t.id === "Task 1").lf : '–'}`; document.getElementById("totalFloat").innerHTML = `Total Float (TF): ${tasksData.find(t => t.id === "Task 1") ? tasksData.find(t => t.id === "Task 1").tf : '–'}`; // Update Table updateTaskTable(); // Update Chart updateChart(); } function updateTaskTable() { var tableBody = document.querySelector("#taskTable tbody"); tableBody.innerHTML = "; // Clear existing rows tasksData.sort(function(a, b) { return a.es – b.es || a.id.localeCompare(b.id); }); // Sort by ES, then ID for (var i = 0; i < tasksData.length; i++) { var task = tasksData[i]; var row = tableBody.insertRow(); row.innerHTML = ` ${task.id} ${task.duration} ${task.predecessors.join(', ')} ${task.es} ${task.ef} ${task.ls} ${task.lf} ${task.tf} ${task.isCritical ? 'Yes' : 'No'} `; if (task.isCritical) { row.style.fontWeight = "bold"; row.style.backgroundColor = "#fff3cd"; // Light yellow for critical tasks } } } function updateChart() { var ctx = document.getElementById('cpmChart').getContext('2d'); var chartData = { labels: tasksData.map(function(task) { return task.id; }), datasets: [ { label: 'Task Duration (Days)', data: tasksData.map(function(task) { return task.duration; }), backgroundColor: tasksData.map(function(task) { return task.isCritical ? 'rgba(255, 99, 132, 0.6)' : 'rgba(54, 162, 235, 0.6)'; }), // Red for critical, Blue for non-critical borderColor: tasksData.map(function(task) { return task.isCritical ? 'rgba(255, 99, 132, 1)' : 'rgba(54, 162, 235, 1)'; }), borderWidth: 1 }, { label: 'Earliest Start (ES)', data: tasksData.map(function(task) { return task.es; }), type: 'line', // Use line for ES/LS to show progression fill: false, borderColor: 'rgba(75, 192, 192, 0.8)', tension: 0.1, pointRadius: 0, // Hide points for line series borderDash: [5, 5] // Dashed line for ES }, { label: 'Latest Start (LS)', data: tasksData.map(function(task) { return task.ls; }), type: 'line', fill: false, borderColor: 'rgba(255, 159, 64, 0.8)', tension: 0.1, pointRadius: 0, // Hide points for line series borderDash: [5, 5] // Dashed line for LS } ] }; // Destroy previous chart instance if it exists if (window.cpmChartInstance) { window.cpmChartInstance.destroy(); } // Create new chart window.cpmChartInstance = new Chart(ctx, { type: 'bar', // Base type is bar for durations data: chartData, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, title: { display: true, text: 'Time (Days)' } }, x: { title: { display: true, text: 'Tasks' } } }, plugins: { title: { display: true, text: 'Task Durations and Critical Path Visualization' }, legend: { position: 'top', } } } }); } function resetCalculator() { document.getElementById("tasks").value = 5; updateTaskInputs(); // Regenerate inputs based on default 5 tasks // Set default values for the first 5 tasks var defaultDurations = [10, 15, 8, 4, 6]; var defaultPredecessors = ["", "Task 1", "Task 1", "Task 2, Task 3", "Task 4"]; for (var i = 0; i < Math.min(taskCount, 5); i++) { document.getElementById(`duration_${i}`).value = defaultDurations[i]; document.getElementById(`predecessors_${i}`).value = defaultPredecessors[i]; document.getElementById(`taskId_${i}`).value = `Task ${i + 1}`; } // Clear any remaining inputs if taskCount < 5 for (var i = taskCount; i < 5; i++) { document.getElementById(`duration_${i}`).value = 10; document.getElementById(`predecessors_${i}`).value = ""; document.getElementById(`taskId_${i}`).value = `Task ${i + 1}`; } // Clear results document.getElementById("projectDuration").textContent = "–"; document.getElementById("criticalPathTasks").textContent = "–"; document.getElementById("totalTasksResult").textContent = "–"; document.getElementById("earliestStart").innerHTML = `Earliest Start (ES): `; document.getElementById("earliestFinish").innerHTML = `Earliest Finish (EF): `; document.getElementById("latestStart").innerHTML = `Latest Start (LS): `; document.getElementById("latestFinish").innerHTML = `Latest Finish (LF): `; document.getElementById("totalFloat").innerHTML = `Total Float (TF): `; document.querySelector("#taskTable tbody").innerHTML = "; if (window.cpmChartInstance) { window.cpmChartInstance.destroy(); document.getElementById('cpmChart').getContext('2d').clearRect(0,0,100,100); // Clear canvas } } function copyResults() { var resultsText = "Critical Path Method (CPM) Analysis:\n\n"; resultsText += `Project Duration: ${document.getElementById("projectDuration").textContent}\n`; resultsText += `Critical Path Tasks: ${document.getElementById("criticalPathTasks").textContent}\n`; resultsText += `Total Tasks Analyzed: ${document.getElementById("totalTasksResult").textContent}\n\n`; resultsText += "Key Time Estimates:\n"; resultsText += `Earliest Start (ES): ${document.getElementById("earliestStart").querySelector('span').textContent}\n`; resultsText += `Earliest Finish (EF): ${document.getElementById("earliestFinish").querySelector('span').textContent}\n`; resultsText += `Latest Start (LS): ${document.getElementById("latestStart").querySelector('span').textContent}\n`; resultsText += `Latest Finish (LF): ${document.getElementById("latestFinish").querySelector('span').textContent}\n`; resultsText += `Total Float (TF): ${document.getElementById("totalFloat").querySelector('span').textContent}\n\n`; resultsText += "Task Details Table:\n"; var table = document.getElementById("taskTable"); var rows = table.querySelectorAll("tr"); for (var i = 0; i < rows.length; i++) { var cells = rows[i].querySelectorAll("th, td"); var rowText = []; for (var j = 0; j < cells.length; j++) { rowText.push(cells[j].textContent.trim()); } resultsText += rowText.join("\t") + "\n"; // Use tab for column separation } // Use a temporary textarea to copy to clipboard var textArea = document.createElement("textarea"); textArea.value = resultsText; textArea.style.position = "fixed"; // Avoid scrolling to bottom textArea.style.opacity = "0"; document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { var successful = document.execCommand('copy'); var msg = successful ? 'Results copied successfully!' : 'Failed to copy results.'; alert(msg); } catch (err) { alert('Oops, unable to copy. Please copy manually.'); } document.body.removeChild(textArea); } // Initial setup on page load document.addEventListener('DOMContentLoaded', function() { updateTaskInputs(); // Generate initial task input fields resetCalculator(); // Load default values // Load Chart.js library dynamically if not already present if (typeof Chart === 'undefined') { var script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.js'; script.onload = function() { console.log('Chart.js loaded.'); // Ensure chart is updated after JS library loads if results are already displayed if (document.getElementById("projectDuration").textContent !== "–") { updateChart(); } }; document.head.appendChild(script); } else { // If Chart.js is already loaded, update chart immediately if needed if (document.getElementById("projectDuration").textContent !== "–") { updateChart(); } } });

Leave a Comment