These features match the DHTMLX Gantt PRO edition. They are all opt-in.
Working time
<.live_component
module={GanttEx.Live.Gantt}
id="gantt"
tasks={@tasks}
links={@links}
work_time
calendar={[work_days: 1..5, hours: ["09:00-13:00", "14:00-18:00"], holidays: [~D[2025-12-25]]]}
calendars={[[id: "weekend-crew", work_days: [6, 7]]]}
/>Durations then count working days (or working hours with
duration_unit={:hour}), starts snap to working time, and non-working days
and holidays are highlighted. Tasks use another calendar with
calendar_id: "weekend-crew". See GanttEx.Calendar.
Auto-scheduling and constraints
auto_scheduling moves tasks after every change so that dependencies and
constraints hold; auto_scheduling_strict also moves them earlier. Tasks
accept constraint_type (:asap, :alap, :snet, :snlt, :fnet,
:fnlt, :mso, :mfo) and constraint_date, editable in the lightbox.
Moves caused by scheduling are reported as :task_updated events within the
same undo step. See GanttEx.Scheduler.
Critical path and slack
critical_path highlights the critical tasks and links (the toolbar has a
toggle), show_slack draws the free slack after each bar, and the
:total_slack / :free_slack columns show the numbers. See
GanttEx.CriticalPath.
Baselines and deadlines
Tasks accept planned_start / planned_end (drawn below the bar with
baselines) and deadline (a flag; tasks ending after it are marked as
overdue). The lightbox sections are :baseline and :deadline, and the
grid columns :planned_start, :planned_end and :deadline.
Resources
<.live_component
module={GanttEx.Live.Gantt}
id="gantt"
tasks={@tasks}
links={@links}
resources={[%{id: "ana", text: "Ana", capacity: 8}, %{id: "luis", text: "Luis"}]}
resource_panel
lightbox_sections={[:text, :time, :resources]}
/>Tasks list their assignments in resources (["ana"] or
[%{resource_id: "ana", value: 4}], the value being units per working day).
The resource panel shows the load of each resource per column and highlights
overloads. See GanttEx.Resource and GanttEx.ResourceLoad.
Grouping
group_by regroups tasks under virtual rows: a task field (:type), a
:meta key (:owner), :resources (a task appears under each of its
resources) or a function. group_label customizes the labels.
Split tasks and rollups
A task with render: :split draws its children on its own row (they can be
dragged there, and links reach them while the branch is collapsed). Tasks
with rollup: true also appear on the rows of their ancestor projects.
Undo and redo
Enabled by default (undo={false} disables it): toolbar buttons,
Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z or Ctrl+Y. Undone changes are reported as
events, so they are persisted like any other change. Undoing a deletion
sends :task_created / :link_created events with the original ids: insert
them with those ids so that links stay valid. See GanttEx.History.
Multi-selection
Ctrl/Cmd+click toggles tasks and Shift+click selects ranges. Dragging a
selected bar moves the whole selection, and Delete removes all the selected
tasks after a single confirmation. :task_selected events carry the
selection.
Timeline markers
markers={[%{date: ~D[2025-03-01], text: "Release", color: "#e11d48"}]} and
today_marker draw vertical lines with labels. See GanttEx.Marker.
WBS codes
The :wbs column shows outline numbers (1.2.3), see
GanttEx.Store.wbs_codes/1.
Dynamic loading
Mark tasks whose children are not loaded with has_children: true.
Expanding one sends a :branch_requested event; load the children and render
the component with them:
def handle_info({GanttEx, %GanttEx.Event{type: :branch_requested, task: task}}, socket) do
{:noreply, update(socket, :tasks, &(&1 ++ Planning.children_of(task.id)))}
endAuto types
auto_types turns tasks with children into projects and projects without
children into tasks, on load and after every change.