demo D276
A project plan, balanced across people in Angular
Put people on tasks and see who is booked past what they can do: the clashing bars are outlined and the avatar ringed, then one press shifts the lower-priority work later until the plan is clear
gantt.overAllocations · gantt.level()
This puts people on tasks and shows who is booked past what they can do, outlining the clashing bars and ringing the avatar, then levels the plan in one press by shifting lower-priority work later. It turns overallocation from something you hunt for into something the plan shows and can resolve.
This is the Angular version. A standalone component takes the whole configuration through one config input, surfaces grid events as outputs, and exposes the live grid on a getter for anything the inputs do not cover.
The configuration
import { Component, ViewChild, ElementRef, AfterViewInit, OnDestroy } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { createGantt } from '@toclocoinc/lattice-grid/modules/gantt';
// mountSplit is a second render path the plain <lattice-gantt> component does
// not cover (see gantt-split-view), so this stays an imperative build against
// a ViewChild'd container.
@Component({
selector: 'app-root',
standalone: true,
template:
'<div style="margin-bottom:10px">' +
' <button (click)="levelPlan()">Level the plan</button> <span>{{ status }}</span>' +
'</div>' +
'<div #plan style="height:440px;overflow:auto"></div>',
})
export class AppComponent implements AfterViewInit, OnDestroy {
@ViewChild('plan') planRef!: ElementRef<HTMLElement>;
private gantt: any;
status = '';
ngAfterViewInit() {
// Each task carries an assignee; each resource a capacity. Two tasks fall
// to one person at the same time, so that resource is booked past
// capacity.
const tasks: any[] = [/* the task list, each with an assignee */];
const dependencies: any[] = [/* the dependency links */];
this.gantt = createGantt({
tasks, dependencies,
resources: [
{ id: 'Ana Ruiz', capacity: 1 },
{ id: 'Bo Ito', capacity: 1 },
{ id: 'Cy Okafor', capacity: 1 },
],
projectStart: '2027-01-04', calendar: 'weekends', autoSchedule: true,
});
this.render();
}
private render() {
this.gantt.mountSplit(this.planRef.nativeElement, {
gridWidth: 300, rowHeight: 34, height: 440, zoom: 'day',
nonWorking: 'weekends', showArrows: true, showProgress: true,
});
// overAllocations reports where a resource is booked beyond capacity
// across concurrent tasks; the split view rings the over-booked avatars.
const over = this.gantt.overAllocations;
this.status = over.length ? 'Over-booked: ' + [...new Set(over.map((o: any) => o.resource))].join(', ') : 'Everyone is within capacity.';
}
levelPlan() {
// level() shifts the lower-priority tasks later to clear the
// over-allocation, honouring the dependency order and the working-day
// calendar.
this.gantt.level();
this.render();
}
ngOnDestroy() { this.gantt?.destroy(); }
}
bootstrapApplication(AppComponent);