@gerald-neumann/gn-vgantt
Complete Gantt product for Angular. A host ships a GnVGanttDataProvider and one (commit) callback. The host does not implement D3, split panes, virtualization, schedule-conflict math, propose-to-fix, row-reorder chrome, or a second schedule table.
Peer dependencies: Angular 21 or 22, RxJS 7, d3 7, @gerald-neumann/gn-vtable ^1.4.0. Optional host chip search: @gerald-neumann/gn-vquery ^1.3.0.
Quick start (hardcoded)
Absolute minimum — in-memory rows, no REST, no kind catalog:
import { Component } from '@angular/core';
import {
GnVGanttComponent,
MemoryVGanttProvider,
type GnVGanttRow,
} from '@gerald-neumann/gn-vgantt';
const rows: GnVGanttRow[] = [
{
id: '1',
name: 'Design',
parentId: null,
startDate: new Date('2026-01-06'),
endDate: new Date('2026-01-17'),
},
{
id: '2',
name: 'Build',
parentId: null,
startDate: new Date('2026-01-13'),
endDate: new Date('2026-01-31'),
dependency: { predecessorId: '1', type: 'FS' },
},
];
@Component({
imports: [GnVGanttComponent],
template: `<gn-vgantt [dataProvider]="provider" />`,
})
export class MinimalGanttPage {
readonly provider = new MemoryVGanttProvider({ rows });
}
MemoryVGanttProvider implements commit, so bar/link edits stay in memory under default persistMode: 'auto'. Add [kindCatalog] when you need type badges, pin rules, or create menus. Production hosts usually switch to HttpVGanttProvider (below).
Runnable copy in this repo: projects/minimum-sample — .\start-minimum-sample.ps1 (or npm run start:minimum) → http://localhost:4201. Use Show code in the sample chrome to view this snippet beside the chart.
Host surface
<gn-vgantt
[dataProvider]="provider"
[kindCatalog]="catalog"
[assigneeOptions]="users()"
[highlightedRowIds]="highlightIds()"
[pinnedId]="focusReleaseId()"
(commit)="onCommit($event)"
/>
this.provider = new HttpVGanttProvider({
baseUrl: apiUrl('planning/gantt'),
http: this.http,
});
onCommit(event: GnVGanttCommitOutput): void {
if (event.persistHandledBy === 'provider') {
return; // library already POSTs via provider.commit — do not double-save
}
// persistMode output / auto without provider.commit:
this.gantt()?.setPersistStatus('saving');
this.save(event).subscribe({
next: () => this.gantt()?.setPersistStatus('idle'),
error: () => this.gantt()?.setPersistStatus('error'),
});
}
GnVGanttCommit is one payload for bar drag, link draw/remove, inline edit, reorder, reparent, and propose-to-fix. (commit) emits GnVGanttCommitOutput (= commit fields + persistHandledBy: 'provider' | 'host').
Persist (persistMode)
| Mode | Behavior |
|---|---|
auto (default) |
Call provider.commit when present (Saving… chrome); otherwise host handles (commit) |
provider |
Only provider.commit |
output |
Only (commit) — never call provider.commit |
Always check event.persistHandledBy before POSTing. For host-only persist, call setPersistStatus('saving' | 'idle' | 'error').
Deprecated: (barChange) / (linkChange) — analytics only; do not persist from them.
Schedule snapshot
There is no host [(schedule)] binding. Use scheduleRows() for a readonly viewport/scoped snapshot. Do not treat it as the full dataset in HTTP mode.
Holidays
Built-in tables are AT/DE only. For other regions pass [holidayResolver]="(date) => …" (return { name } or undefined to fall through). Unknown [holidayRegions] codes without a resolver warn in dev mode.
Supported host API (@public)
Full consumer contract: docs/SUPPORTED-HOST-API.md.
Exported from @gerald-neumann/gn-vgantt: GnVGanttComponent, provider types, HttpVGanttProvider / MemoryVGanttProvider, commit/row/kind/issue models, display helpers, i18n, holiday types + holidayResolver.
Supported component methods: reloadTable(), scrollToId(), flashRow(), scheduleRows(), setPersistStatus().
Expert helpers (detectIssues / proposeFix, schedule geometry, drop planners, calendar math, planning) live on @gerald-neumann/gn-vgantt/advanced — not semver-stable for hosts. Timeline stays package-private. Import outline helpers from @gerald-neumann/gn-vtable when needed.
import { applyCommit, detectIssues, proposeFix } from '@gerald-neumann/gn-vgantt/advanced';
Published REST (normative)
| Method | Path | Role |
|---|---|---|
POST |
{base}/rows |
VTableDataParams → VTableResponse<GnVGanttRow> (ISO dates) |
POST |
{base}/count |
VTableCountParams → number |
GET or POST |
{base}/domain |
GnVGanttTimeDomain for the current filter/pin |
POST |
{base}/links |
{ ids: string[] } → GnVGanttLink[] (visible ids + overscan) |
POST |
{base}/commit |
GnVGanttCommit → { ok, rows? } (optional) |
Optional chip filters (host @gerald-neumann/gn-vquery ^1.3.0): HttpVGanttProvider.setChipFilterQuery adds chipFilterQuery / chipFilterDialect to /rows /count /domain. Use applyCompiledQueryToVGantt then reloadTable({ countFirst: true }).
demo-api + demo-api/openapi.yaml are the reference implementation. HTTP mode stays O(viewport): fetchTimeDomain and fetchLinks are required; the component does not accumulate every loaded chunk.
Kind catalog (prefer) / kind graph (advanced)
Pass [kindCatalog] with sameKindChildren / childGroups / pinnable — the library derives the creatable-child graph. Optional [kindGraph] is an advanced override when catalog metadata is not enough. The library has no Magna or ReSpecT kind defaults — the demo app supplies those catalogs.
WBS parentId and visual scheduleOrder are independent. Table DnD uses gn-vtable drop zones: middle of the row nests onto a valid parent kind (commit.parents); top/bottom edge reorders as a sibling (commit.ranks, 10, 20, …). Illegal drops are rejected. [allowReparent]="false" keeps sibling reorder only; dropping into another row of the same kind then offers Set as predecessor / Set as successor (commit.links). Draw a connector from the end of a bar to the start of another same-kind bar (or Shift+drag). The preview is always that orthogonal end→start path (or start←end from the start handle), not a free diagonal. Double-click an arrow to remove it. Cross-type links are rejected.
Navigate / highlight / pin (precedence)
Clicking a row or bar highlights the critical path through that item (CPM, zero total float). Path bars and arrows use --gantt-critical. Click again to clear.
Use one concern per API — do not wire all four for the same jump:
| API | Role | Side effects |
|---|---|---|
[highlightedRowIds] |
Heatmap ?highlight= — timed flash of first id |
Also scrolls to that id |
[focusId] |
One-shot scroll + select when the id changes | Sets selectedId, then scrollToId |
[(pinnedId)] |
Persist pin scope (subtree filter via provider) | Synced to provider.setPinnedId |
[(selectedId)] |
Current selection / critical-path root | Cleared when user toggles the same bar |
scrollToId(id) / flashRow(id) |
Imperative after first chunk | Hosts must not query [data-task-id] |
Recipe: heatmap deep-link → [highlightedRowIds]; ALM “open this item” → [focusId]; “work under this release” → [(pinnedId)]; toolbar selection chrome → [(selectedId)].
[maxDepth] drills the pinned/scoped tree independently of navigation.
Font Awesome license
gn-vgantt does not ship Font Awesome files. Icons use gn-vtable’s iconLibrary / iconLibraries contract (sanitizeFaGlyphName: bare glyph names such as chart-gantt).
If you use font-awesome-solid, font-awesome-duotone, or a custom Sharp Duotone library, you must have your own Font Awesome license and load the CSS in the host app. The demo app uses Font Awesome Pro via FONTAWESOME_PRO_TOKEN (same pattern as MyERP / ReSpecT).
Theming (tokens only)
@use '@gerald-neumann/gn-vgantt/themes/bootstrap';
// or material, or tailwind
No host D3 CSS is required. All colors — including SVG chrome (buffer hatch, milestone knobs, resize/link handles, rails, header bands) — read --gantt-* tokens with light fallbacks; the component never assigns tokens on :host, so a plain host element selector (gn-vgantt { --gantt-bg: …; }) is enough for dark skins. The full token contract is documented in change-reqests/CR-2026-08-24-prototype-visual-parity.md and mirrored by the three theme files.
Outline / L-rails
Name-column L-rails come from gn-vtable (vtable-outline-prefix). Timeline date rails stay in this library. Providers must supply __outline (memory provider and demo-api do).
outlineMode |
Meaning |
|---|---|
l-rails (default) |
Colored through/join stems + chevron |
tree |
Indent + chevron only |
none |
Flat name column |
Chevron collapse: gn-vgantt handles (outlineToggle) and calls provider.toggleOutlineExpanded?.(id) when present. MemoryVGanttProvider implements it (hides descendants). HTTP providers typically stamp __expanded from the server instead.