Project#level#

Resolves resource overallocation in a Project. It runs solve(null, …) with default options first, then writes persistent levelingDelay and pauses edits and accepts the leveled state as the baseline.

Signature#

public LevelingResult level(LevelingOptions options)

Synchronous and CPU-only. Changes the project's state. Not synchronized: serialize calls on one instance.

Parameters#

Name Type Description
options LevelingOptions Scope, order, basis and how leveling may move tasks. Must not be null

Behavior#

  • Forward scheduling only.
  • On a cyclic project, it returns the initial solve's result with rounds = 0.
  • The leveled dates replace the baseline. To see leveling without committing it, call level on a copy().
  • Known bug: the call doesn't return when an assignment asks for more units than its resource can ever supply, for example value 1.25 on capacity 1.

Returns#

A LevelingResult. The project keeps its schedule as the baseline and shares it with copies. Treat schedule as read-only, or call deepClone() before changing it.

Errors#

All exceptions are unchecked.

Error When
InputException An unknown id in options.scope.resources or options.scope.tasks (path is scope.resources / scope.tasks); the project has config.scheduleFromEnd = true (path is config.schedule_from_end)
ProjectException with code == ProjectError.NEEDS_RESYNC Thrown by the initial solve
NullPointerException options is null

Example#

Level two tasks that share one resource, first on a copy, then on the project itself.

import java.util.List;
import org.dhtmlx.plen.*;

public class LevelExample {
  public static void main(String[] args) throws Exception {
    Moment monday = Moment.fromYmdHm(2026, 8, 10, 8, 0);
    ProjectData data = new ProjectData()
        .withTasks(List.of(
            new TaskData(Id.str("a")).withStartDate(monday).withDuration(2.0),
            new TaskData(Id.str("b")).withStartDate(monday).withDuration(2.0)))
        .withResources(List.of(new ResourceData().withId(Id.str("dev"))))
        .withAssignments(List.of(
            new AssignmentData().withTask(Id.str("a")).withResource(Id.str("dev")).withValue(1.0),
            new AssignmentData().withTask(Id.str("b")).withResource(Id.str("dev")).withValue(1.0)));

    Project project = new Project();
    project.solve(data, new SolveOptions());

    // A proposal: level a cheap copy, the project keeps its dates.
    Project draft = project.copy();
    LevelingResult proposal = draft.level(new LevelingOptions());
    for (Mutation update : proposal.schedule.updates) {
      System.out.println("task " + update.id + " delay " + update.levelingDelay);
      // task b delay 2.0
    }

    // Commit: level the project itself.
    LevelingResult leveled = project.level(new LevelingOptions());
    System.out.println(leveled.rounds + " round(s)");
  }
}